Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d11 / Image11.cpp
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7
8 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
9 // the actual underlying resources of a Texture
10
11 #include "libGLESv2/renderer/d3d11/Renderer11.h"
12 #include "libGLESv2/renderer/d3d11/Image11.h"
13 #include "libGLESv2/renderer/d3d11/TextureStorage11.h"
14 #include "libGLESv2/Framebuffer.h"
15 #include "libGLESv2/Renderbuffer.h"
16
17 #include "libGLESv2/main.h"
18 #include "libGLESv2/utilities.h"
19 #include "libGLESv2/renderer/d3d11/renderer11_utils.h"
20 #include "libGLESv2/renderer/generatemip.h"
21
22 namespace rx
23 {
24
25 Image11::Image11()
26 {
27     mStagingTexture = NULL;
28     mRenderer = NULL;
29     mDXGIFormat = DXGI_FORMAT_UNKNOWN;
30 }
31
32 Image11::~Image11()
33 {
34     if (mStagingTexture)
35     {
36         mStagingTexture->Release();
37     }
38 }
39
40 Image11 *Image11::makeImage11(Image *img)
41 {
42     ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
43     return static_cast<rx::Image11*>(img);
44 }
45
46 void Image11::generateMipmap(Image11 *dest, Image11 *src)
47 {
48     ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
49     ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
50     ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
51
52     D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped;
53     dest->map(D3D11_MAP_WRITE, &destMapped);
54     src->map(D3D11_MAP_READ, &srcMapped);
55
56     const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
57     unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
58
59     if (sourceData && destData)
60     {
61         switch (src->getDXGIFormat())
62         {
63           case DXGI_FORMAT_R8G8B8A8_UNORM:
64           case DXGI_FORMAT_B8G8R8A8_UNORM:
65             GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
66             break;
67           case DXGI_FORMAT_A8_UNORM:
68             GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
69             break;
70           case DXGI_FORMAT_R8_UNORM:
71             GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
72             break;
73           case DXGI_FORMAT_R32G32B32A32_FLOAT:
74             GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
75             break;
76           case DXGI_FORMAT_R32G32B32_FLOAT:
77             GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
78             break;
79           case DXGI_FORMAT_R16G16B16A16_FLOAT:
80             GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
81             break;
82           case DXGI_FORMAT_R8G8_UNORM:
83             GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
84             break;
85           case DXGI_FORMAT_R16_FLOAT:
86             GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
87             break;
88           case DXGI_FORMAT_R16G16_FLOAT:
89             GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
90             break;
91           case DXGI_FORMAT_R32_FLOAT:
92             GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
93             break;
94           case DXGI_FORMAT_R32G32_FLOAT:
95             GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
96             break;
97           default:
98             UNREACHABLE();
99             break;
100         }
101
102         dest->unmap();
103         src->unmap();
104     }
105
106     dest->markDirty();
107 }
108
109 static bool FormatRequiresInitialization(DXGI_FORMAT dxgiFormat, GLenum internalFormat)
110 {
111     return (dxgiFormat == DXGI_FORMAT_R8G8B8A8_UNORM && gl::GetAlphaSize(internalFormat) == 0) ||
112            (dxgiFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && gl::GetAlphaSize(internalFormat) == 0);
113 }
114
115 bool Image11::isDirty() const
116 {
117     return ((mStagingTexture || FormatRequiresInitialization(mDXGIFormat, mInternalFormat)) && mDirty);
118 }
119
120 bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
121 {
122     TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
123     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height);
124 }
125
126 bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
127 {
128     TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
129     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height);
130 }
131
132 bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
133 {
134     if (mWidth != width ||
135         mHeight != height ||
136         mInternalFormat != internalformat ||
137         forceRelease)
138     {
139         mRenderer = Renderer11::makeRenderer11(renderer);
140
141         mWidth = width;
142         mHeight = height;
143         mInternalFormat = internalformat;
144         // compute the d3d format that will be used
145         mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
146         mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
147
148         if (mStagingTexture)
149         {
150             mStagingTexture->Release();
151             mStagingTexture = NULL;
152         }
153         
154         return true;
155     }
156
157     return false;
158 }
159
160 bool Image11::isRenderableFormat() const
161 {
162     return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
163 }
164
165 DXGI_FORMAT Image11::getDXGIFormat() const
166 {
167     // this should only happen if the image hasn't been redefined first
168     // which would be a bug by the caller
169     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
170
171     return mDXGIFormat;
172 }
173
174 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
175 // into the target pixel rectangle.
176 void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
177                        GLint unpackAlignment, const void *input)
178 {
179     D3D11_MAPPED_SUBRESOURCE mappedImage;
180     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
181     if (FAILED(result))
182     {
183         ERR("Could not map image for loading.");
184         return;
185     }
186     
187     GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
188     size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
189     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
190
191     switch (mInternalFormat)
192     {
193       case GL_ALPHA8_EXT:
194         loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
195         break;
196       case GL_LUMINANCE8_EXT:
197         loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
198         break;
199       case GL_ALPHA32F_EXT:
200         loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
201         break;
202       case GL_LUMINANCE32F_EXT:
203         loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
204         break;
205       case GL_ALPHA16F_EXT:
206         loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
207         break;
208       case GL_LUMINANCE16F_EXT:
209         loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
210         break;
211       case GL_LUMINANCE8_ALPHA8_EXT:
212         loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
213         break;
214       case GL_LUMINANCE_ALPHA32F_EXT:
215         loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
216         break;
217       case GL_LUMINANCE_ALPHA16F_EXT:
218         loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
219         break;
220       case GL_RGB8_OES:
221         loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
222         break;
223       case GL_RGB565:
224         loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
225         break;
226       case GL_RGBA8_OES:
227         loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
228         break;
229       case GL_RGBA4:
230         loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
231         break;
232       case GL_RGB5_A1:
233         loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
234         break;
235       case GL_BGRA8_EXT:
236         loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
237         break;
238       case GL_RGB32F_EXT:
239         loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
240         break;
241       case GL_RGB16F_EXT:
242         loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
243         break;
244       case GL_RGBA32F_EXT:
245         loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
246         break;
247       case GL_RGBA16F_EXT:
248         loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
249         break;
250       default: UNREACHABLE(); 
251     }
252
253     unmap();
254 }
255
256 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
257                                 const void *input)
258 {
259     ASSERT(xoffset % 4 == 0);
260     ASSERT(yoffset % 4 == 0);
261
262     D3D11_MAPPED_SUBRESOURCE mappedImage;
263     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
264     if (FAILED(result))
265     {
266         ERR("Could not map image for loading.");
267         return;
268     }
269
270     // Size computation assumes a 4x4 block compressed texture format
271     size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
272     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
273
274     GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
275     GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
276     int rows = inputSize / inputPitch;
277     for (int i = 0; i < rows; ++i)
278     {
279         memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
280     }
281
282     unmap();
283 }
284
285 void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
286 {
287     gl::Renderbuffer *colorbuffer = source->getReadColorbuffer();
288
289     if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat)
290     {
291         // No conversion needed-- use copyback fastpath
292         ID3D11Texture2D *colorBufferTexture = NULL;
293         unsigned int subresourceIndex = 0;
294
295         if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
296         {
297             D3D11_TEXTURE2D_DESC textureDesc;
298             colorBufferTexture->GetDesc(&textureDesc);
299
300             ID3D11Device *device = mRenderer->getDevice();
301             ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
302
303             ID3D11Texture2D* srcTex = NULL;
304             if (textureDesc.SampleDesc.Count > 1)
305             {
306                 D3D11_TEXTURE2D_DESC resolveDesc;
307                 resolveDesc.Width = textureDesc.Width;
308                 resolveDesc.Height = textureDesc.Height;
309                 resolveDesc.MipLevels = 1;
310                 resolveDesc.ArraySize = 1;
311                 resolveDesc.Format = textureDesc.Format;
312                 resolveDesc.SampleDesc.Count = 1;
313                 resolveDesc.SampleDesc.Quality = 0;
314                 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
315                 resolveDesc.BindFlags = 0;
316                 resolveDesc.CPUAccessFlags = 0;
317                 resolveDesc.MiscFlags = 0;
318
319                 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
320                 if (FAILED(result))
321                 {
322                     ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
323                     return;
324                 }
325
326                 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
327                 subresourceIndex = 0;
328             }
329             else
330             {
331                 srcTex = colorBufferTexture;
332                 srcTex->AddRef();
333             }
334
335             D3D11_BOX srcBox;
336             srcBox.left = x;
337             srcBox.right = x + width;
338             srcBox.top = y;
339             srcBox.bottom = y + height;
340             srcBox.front = 0;
341             srcBox.back = 1;
342
343             deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
344
345             srcTex->Release();
346             colorBufferTexture->Release();
347         }
348     }
349     else
350     {
351         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
352         D3D11_MAPPED_SUBRESOURCE mappedImage;
353         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
354
355         // determine the offset coordinate into the destination buffer
356         GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset;
357         void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset;
358
359         mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat), 
360                               gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset);
361
362         unmap();
363     }
364 }
365
366 ID3D11Texture2D *Image11::getStagingTexture()
367 {
368     createStagingTexture();
369
370     return mStagingTexture;
371 }
372
373 unsigned int Image11::getStagingSubresource()
374 {
375     createStagingTexture();
376
377     return mStagingSubresource;
378 }
379
380 template <typename T, size_t N>
381 static void setDefaultData(ID3D11DeviceContext *deviceContext, ID3D11Texture2D *texture, UINT subresource,
382                            GLsizei width, GLsizei height, const T (&defaultData)[N])
383 {
384     D3D11_MAPPED_SUBRESOURCE map;
385     deviceContext->Map(texture, subresource, D3D11_MAP_WRITE, 0, &map);
386
387     unsigned char* ptr = reinterpret_cast<unsigned char*>(map.pData);
388     size_t pixelSize = sizeof(T) * N;
389
390     for (GLsizei y = 0; y < height; y++)
391     {
392         for (GLsizei x = 0; x < width; x++)
393         {
394             memcpy(ptr + (y * map.RowPitch) + (x * pixelSize), defaultData, pixelSize);
395         }
396     }
397
398     deviceContext->Unmap(texture, subresource);
399 }
400
401 void Image11::createStagingTexture()
402 {
403     if (mStagingTexture)
404     {
405         return;
406     }
407
408     ID3D11Texture2D *newTexture = NULL;
409     int lodOffset = 1;
410     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
411     ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures
412
413     if (mWidth != 0 && mHeight != 0)
414     {
415         GLsizei width = mWidth;
416         GLsizei height = mHeight;
417
418         // adjust size if needed for compressed textures
419         gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset);
420         ID3D11Device *device = mRenderer->getDevice();
421
422         D3D11_TEXTURE2D_DESC desc;
423         desc.Width = width;
424         desc.Height = height;
425         desc.MipLevels = lodOffset + 1;
426         desc.ArraySize = 1;
427         desc.Format = dxgiFormat;
428         desc.SampleDesc.Count = 1;
429         desc.SampleDesc.Quality = 0;
430         desc.Usage = D3D11_USAGE_STAGING;
431         desc.BindFlags = 0;
432         desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
433         desc.MiscFlags = 0;
434
435         HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
436
437         if (FAILED(result))
438         {
439             ASSERT(result == E_OUTOFMEMORY);
440             ERR("Creating image failed.");
441             return gl::error(GL_OUT_OF_MEMORY);
442         }
443     }
444
445     mStagingTexture = newTexture;
446     mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
447     mDirty = false;
448
449     if (mDXGIFormat == DXGI_FORMAT_R8G8B8A8_UNORM && gl::GetAlphaSize(mInternalFormat) == 0)
450     {
451         unsigned char defaultPixel[4] = { 0, 0, 0, 255 };
452         setDefaultData(mRenderer->getDeviceContext(), mStagingTexture, mStagingSubresource, mWidth, mHeight, defaultPixel);
453     }
454     else if (mDXGIFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && gl::GetAlphaSize(mInternalFormat) == 0)
455     {
456         float defaultPixel[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
457         setDefaultData(mRenderer->getDeviceContext(), mStagingTexture, mStagingSubresource, mWidth, mHeight, defaultPixel);
458     }
459 }
460
461 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
462 {
463     createStagingTexture();
464
465     HRESULT result = E_FAIL;
466
467     if (mStagingTexture)
468     {
469         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
470         result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
471
472         // this can fail if the device is removed (from TDR)
473         if (d3d11::isDeviceLostError(result))
474         {
475             mRenderer->notifyDeviceLost();
476         }
477         else if (SUCCEEDED(result))
478         {
479             mDirty = true;
480         }
481     }
482
483     return result;
484 }
485
486 void Image11::unmap()
487 {
488     if (mStagingTexture)
489     {
490         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
491         deviceContext->Unmap(mStagingTexture, mStagingSubresource);
492     }
493 }
494
495 }