187afd90cac4a905fc97a302399874aee3008e57
[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 bool Image11::isDirty() const
110 {
111     return (mStagingTexture && mDirty);
112 }
113
114 bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
115 {
116     TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
117     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height);
118 }
119
120 bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
121 {
122     TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
123     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height);
124 }
125
126 bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
127 {
128     if (mWidth != width ||
129         mHeight != height ||
130         mInternalFormat != internalformat ||
131         forceRelease)
132     {
133         mRenderer = Renderer11::makeRenderer11(renderer);
134
135         mWidth = width;
136         mHeight = height;
137         mInternalFormat = internalformat;
138         // compute the d3d format that will be used
139         mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
140         mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
141
142         if (mStagingTexture)
143         {
144             mStagingTexture->Release();
145             mStagingTexture = NULL;
146         }
147         
148         return true;
149     }
150
151     return false;
152 }
153
154 bool Image11::isRenderableFormat() const
155 {
156     return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
157 }
158
159 DXGI_FORMAT Image11::getDXGIFormat() const
160 {
161     // this should only happen if the image hasn't been redefined first
162     // which would be a bug by the caller
163     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
164
165     return mDXGIFormat;
166 }
167
168 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
169 // into the target pixel rectangle.
170 void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
171                        GLint unpackAlignment, const void *input)
172 {
173     D3D11_MAPPED_SUBRESOURCE mappedImage;
174     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
175     if (FAILED(result))
176     {
177         ERR("Could not map image for loading.");
178         return;
179     }
180     
181     GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
182     size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
183     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
184
185     switch (mInternalFormat)
186     {
187       case GL_ALPHA8_EXT:
188         loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
189         break;
190       case GL_LUMINANCE8_EXT:
191         loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
192         break;
193       case GL_ALPHA32F_EXT:
194         loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
195         break;
196       case GL_LUMINANCE32F_EXT:
197         loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
198         break;
199       case GL_ALPHA16F_EXT:
200         loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
201         break;
202       case GL_LUMINANCE16F_EXT:
203         loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
204         break;
205       case GL_LUMINANCE8_ALPHA8_EXT:
206         loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
207         break;
208       case GL_LUMINANCE_ALPHA32F_EXT:
209         loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
210         break;
211       case GL_LUMINANCE_ALPHA16F_EXT:
212         loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
213         break;
214       case GL_RGB8_OES:
215         loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
216         break;
217       case GL_RGB565:
218         loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
219         break;
220       case GL_RGBA8_OES:
221         loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
222         break;
223       case GL_RGBA4:
224         loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
225         break;
226       case GL_RGB5_A1:
227         loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
228         break;
229       case GL_BGRA8_EXT:
230         loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
231         break;
232       case GL_RGB32F_EXT:
233         loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
234         break;
235       case GL_RGB16F_EXT:
236         loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
237         break;
238       case GL_RGBA32F_EXT:
239         loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
240         break;
241       case GL_RGBA16F_EXT:
242         loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
243         break;
244       default: UNREACHABLE(); 
245     }
246
247     unmap();
248 }
249
250 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
251                                 const void *input)
252 {
253     ASSERT(xoffset % 4 == 0);
254     ASSERT(yoffset % 4 == 0);
255
256     D3D11_MAPPED_SUBRESOURCE mappedImage;
257     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
258     if (FAILED(result))
259     {
260         ERR("Could not map image for loading.");
261         return;
262     }
263
264     // Size computation assumes a 4x4 block compressed texture format
265     size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
266     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
267
268     GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
269     GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
270     int rows = inputSize / inputPitch;
271     for (int i = 0; i < rows; ++i)
272     {
273         memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
274     }
275
276     unmap();
277 }
278
279 void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
280 {
281     gl::Renderbuffer *colorbuffer = source->getReadColorbuffer();
282
283     if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat)
284     {
285         // No conversion needed-- use copyback fastpath
286         ID3D11Texture2D *colorBufferTexture = NULL;
287         unsigned int subresourceIndex = 0;
288
289         if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
290         {
291             D3D11_TEXTURE2D_DESC textureDesc;
292             colorBufferTexture->GetDesc(&textureDesc);
293
294             ID3D11Device *device = mRenderer->getDevice();
295             ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
296
297             ID3D11Texture2D* srcTex = NULL;
298             if (textureDesc.SampleDesc.Count > 1)
299             {
300                 D3D11_TEXTURE2D_DESC resolveDesc;
301                 resolveDesc.Width = textureDesc.Width;
302                 resolveDesc.Height = textureDesc.Height;
303                 resolveDesc.MipLevels = 1;
304                 resolveDesc.ArraySize = 1;
305                 resolveDesc.Format = textureDesc.Format;
306                 resolveDesc.SampleDesc.Count = 1;
307                 resolveDesc.SampleDesc.Quality = 0;
308                 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
309                 resolveDesc.BindFlags = 0;
310                 resolveDesc.CPUAccessFlags = 0;
311                 resolveDesc.MiscFlags = 0;
312
313                 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
314                 if (FAILED(result))
315                 {
316                     ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
317                     return;
318                 }
319
320                 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
321                 subresourceIndex = 0;
322             }
323             else
324             {
325                 srcTex = colorBufferTexture;
326                 srcTex->AddRef();
327             }
328
329             D3D11_BOX srcBox;
330             srcBox.left = x;
331             srcBox.right = x + width;
332             srcBox.top = y;
333             srcBox.bottom = y + height;
334             srcBox.front = 0;
335             srcBox.back = 1;
336
337             deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
338
339             srcTex->Release();
340             colorBufferTexture->Release();
341         }
342     }
343     else
344     {
345         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
346         D3D11_MAPPED_SUBRESOURCE mappedImage;
347         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
348
349         // determine the offset coordinate into the destination buffer
350         GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset;
351         void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset;
352
353         mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat), 
354                               gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset);
355
356         unmap();
357     }
358 }
359
360 ID3D11Texture2D *Image11::getStagingTexture()
361 {
362     createStagingTexture();
363
364     return mStagingTexture;
365 }
366
367 unsigned int Image11::getStagingSubresource()
368 {
369     createStagingTexture();
370
371     return mStagingSubresource;
372 }
373
374 void Image11::createStagingTexture()
375 {
376     if (mStagingTexture)
377     {
378         return;
379     }
380
381     ID3D11Texture2D *newTexture = NULL;
382     int lodOffset = 1;
383     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
384     ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures
385
386     if (mWidth != 0 && mHeight != 0)
387     {
388         GLsizei width = mWidth;
389         GLsizei height = mHeight;
390
391         // adjust size if needed for compressed textures
392         gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset);
393         ID3D11Device *device = mRenderer->getDevice();
394
395         D3D11_TEXTURE2D_DESC desc;
396         desc.Width = width;
397         desc.Height = height;
398         desc.MipLevels = lodOffset + 1;
399         desc.ArraySize = 1;
400         desc.Format = dxgiFormat;
401         desc.SampleDesc.Count = 1;
402         desc.SampleDesc.Quality = 0;
403         desc.Usage = D3D11_USAGE_STAGING;
404         desc.BindFlags = 0;
405         desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
406         desc.MiscFlags = 0;
407
408         HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
409
410         if (FAILED(result))
411         {
412             ASSERT(result == E_OUTOFMEMORY);
413             ERR("Creating image failed.");
414             return gl::error(GL_OUT_OF_MEMORY);
415         }
416     }
417
418     mStagingTexture = newTexture;
419     mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
420     mDirty = false;
421 }
422
423 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
424 {
425     createStagingTexture();
426
427     HRESULT result = E_FAIL;
428
429     if (mStagingTexture)
430     {
431         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
432         result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
433
434         // this can fail if the device is removed (from TDR)
435         if (d3d11::isDeviceLostError(result))
436         {
437             mRenderer->notifyDeviceLost();
438         }
439         else if (SUCCEEDED(result))
440         {
441             mDirty = true;
442         }
443     }
444
445     return result;
446 }
447
448 void Image11::unmap()
449 {
450     if (mStagingTexture)
451     {
452         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
453         deviceContext->Unmap(mStagingTexture, mStagingSubresource);
454     }
455 }
456
457 }