Upstream version 9.37.197.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 "common/utilities.h"
19 #include "libGLESv2/renderer/d3d11/formatutils11.h"
20 #include "libGLESv2/renderer/d3d11/renderer11_utils.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     SafeRelease(mStagingTexture);
35 }
36
37 Image11 *Image11::makeImage11(Image *img)
38 {
39     ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
40     return static_cast<rx::Image11*>(img);
41 }
42
43 void Image11::generateMipmap(GLuint clientVersion, Image11 *dest, Image11 *src)
44 {
45     ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
46     ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
47     ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
48
49     MipGenerationFunction mipFunction = d3d11::GetMipGenerationFunction(src->getDXGIFormat());
50     ASSERT(mipFunction != NULL);
51
52     D3D11_MAPPED_SUBRESOURCE destMapped;
53     HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped);
54     if (FAILED(destMapResult))
55     {
56         ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult);
57         return;
58     }
59
60     D3D11_MAPPED_SUBRESOURCE srcMapped;
61     HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped);
62     if (FAILED(srcMapResult))
63     {
64         ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult);
65
66         dest->unmap();
67         return;
68     }
69
70     const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
71     unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
72
73     mipFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData, srcMapped.RowPitch, srcMapped.DepthPitch,
74                 destData, destMapped.RowPitch, destMapped.DepthPitch);
75
76     dest->unmap();
77     src->unmap();
78
79     dest->markDirty();
80 }
81
82 bool Image11::isDirty() const
83 {
84     // Make sure that this image is marked as dirty even if the staging texture hasn't been created yet
85     // if initialization is required before use.
86     return (mDirty && (mStagingTexture || gl_d3d11::RequiresTextureDataInitialization(mInternalFormat)));
87 }
88
89 bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
90 {
91     TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
92     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1);
93 }
94
95 bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
96 {
97     TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
98     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1);
99 }
100
101 bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
102 {
103     TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance());
104     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth);
105 }
106
107 bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
108 {
109     TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance());
110     return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1);
111 }
112
113 bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
114 {
115     if (mWidth != width ||
116         mHeight != height ||
117         mInternalFormat != internalformat ||
118         forceRelease)
119     {
120         mRenderer = Renderer11::makeRenderer11(renderer);
121         GLuint clientVersion = mRenderer->getCurrentClientVersion();
122
123         mWidth = width;
124         mHeight = height;
125         mDepth = depth;
126         mInternalFormat = internalformat;
127         mTarget = target;
128
129         // compute the d3d format that will be used
130         mDXGIFormat = gl_d3d11::GetTexFormat(internalformat, clientVersion);
131         mActualFormat = d3d11_gl::GetInternalFormat(mDXGIFormat, clientVersion);
132         mRenderable = gl_d3d11::GetRTVFormat(internalformat, clientVersion) != DXGI_FORMAT_UNKNOWN;
133
134         SafeRelease(mStagingTexture);
135         mDirty = gl_d3d11::RequiresTextureDataInitialization(mInternalFormat);
136
137         return true;
138     }
139
140     return false;
141 }
142
143 DXGI_FORMAT Image11::getDXGIFormat() const
144 {
145     // this should only happen if the image hasn't been redefined first
146     // which would be a bug by the caller
147     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
148
149     return mDXGIFormat;
150 }
151
152 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
153 // into the target pixel rectangle.
154 void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
155                        GLint unpackAlignment, GLenum type, const void *input)
156 {
157     GLuint clientVersion = mRenderer->getCurrentClientVersion();
158     GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, type, clientVersion, width, unpackAlignment);
159     GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, type, clientVersion, width, height, unpackAlignment);
160     GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
161
162     LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, type, clientVersion);
163     ASSERT(loadFunction != NULL);
164
165     D3D11_MAPPED_SUBRESOURCE mappedImage;
166     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
167     if (FAILED(result))
168     {
169         ERR("Could not map image for loading.");
170         return;
171     }
172
173     void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch));
174     loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
175
176     unmap();
177 }
178
179 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
180                                  const void *input)
181 {
182     GLuint clientVersion = mRenderer->getCurrentClientVersion();
183     GLsizei inputRowPitch = gl::GetRowPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, 1);
184     GLsizei inputDepthPitch = gl::GetDepthPitch(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
185
186     GLuint outputPixelSize = d3d11::GetFormatPixelBytes(mDXGIFormat);
187     GLuint outputBlockWidth = d3d11::GetBlockWidth(mDXGIFormat);
188     GLuint outputBlockHeight = d3d11::GetBlockHeight(mDXGIFormat);
189
190     ASSERT(xoffset % outputBlockWidth == 0);
191     ASSERT(yoffset % outputBlockHeight == 0);
192
193     LoadImageFunction loadFunction = d3d11::GetImageLoadFunction(mInternalFormat, GL_UNSIGNED_BYTE, clientVersion);
194     ASSERT(loadFunction != NULL);
195
196     D3D11_MAPPED_SUBRESOURCE mappedImage;
197     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
198     if (FAILED(result))
199     {
200         ERR("Could not map image for loading.");
201         return;
202     }
203
204     void* offsetMappedData = (void*)((BYTE*)mappedImage.pData + ((yoffset / outputBlockHeight) * mappedImage.RowPitch +
205                                                                  (xoffset / outputBlockWidth) * outputPixelSize +
206                                                                  zoffset * mappedImage.DepthPitch));
207
208     loadFunction(width, height, depth, input, inputRowPitch, inputDepthPitch,
209                  offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
210
211     unmap();
212 }
213
214 void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
215 {
216     gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
217
218     if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat)
219     {
220         // No conversion needed-- use copyback fastpath
221         ID3D11Texture2D *colorBufferTexture = NULL;
222         unsigned int subresourceIndex = 0;
223
224         if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
225         {
226             D3D11_TEXTURE2D_DESC textureDesc;
227             colorBufferTexture->GetDesc(&textureDesc);
228
229             ID3D11Device *device = mRenderer->getDevice();
230             ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
231
232             ID3D11Texture2D* srcTex = NULL;
233             if (textureDesc.SampleDesc.Count > 1)
234             {
235                 D3D11_TEXTURE2D_DESC resolveDesc;
236                 resolveDesc.Width = textureDesc.Width;
237                 resolveDesc.Height = textureDesc.Height;
238                 resolveDesc.MipLevels = 1;
239                 resolveDesc.ArraySize = 1;
240                 resolveDesc.Format = textureDesc.Format;
241                 resolveDesc.SampleDesc.Count = 1;
242                 resolveDesc.SampleDesc.Quality = 0;
243                 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
244                 resolveDesc.BindFlags = 0;
245                 resolveDesc.CPUAccessFlags = 0;
246                 resolveDesc.MiscFlags = 0;
247
248                 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
249                 if (FAILED(result))
250                 {
251                     ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
252                     return;
253                 }
254
255                 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
256                 subresourceIndex = 0;
257             }
258             else
259             {
260                 srcTex = colorBufferTexture;
261                 srcTex->AddRef();
262             }
263
264             D3D11_BOX srcBox;
265             srcBox.left = x;
266             srcBox.right = x + width;
267             srcBox.top = y;
268             srcBox.bottom = y + height;
269             srcBox.front = 0;
270             srcBox.back = 1;
271
272             deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox);
273
274             SafeRelease(srcTex);
275             SafeRelease(colorBufferTexture);
276         }
277     }
278     else
279     {
280         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
281         D3D11_MAPPED_SUBRESOURCE mappedImage;
282         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
283         if (FAILED(result))
284         {
285             ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result);
286             return;
287         }
288
289         // determine the offset coordinate into the destination buffer
290         GLuint clientVersion = mRenderer->getCurrentClientVersion();
291         GLsizei rowOffset = gl::GetPixelBytes(mActualFormat, clientVersion) * xoffset;
292         void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
293
294         GLenum format = gl::GetFormat(mInternalFormat, clientVersion);
295         GLenum type = gl::GetType(mInternalFormat, clientVersion);
296
297         mRenderer->readPixels(source, x, y, width, height, format, type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
298
299         unmap();
300     }
301 }
302
303 ID3D11Resource *Image11::getStagingTexture()
304 {
305     createStagingTexture();
306
307     return mStagingTexture;
308 }
309
310 unsigned int Image11::getStagingSubresource()
311 {
312     createStagingTexture();
313
314     return mStagingSubresource;
315 }
316
317 void Image11::createStagingTexture()
318 {
319     if (mStagingTexture)
320     {
321         return;
322     }
323
324     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
325
326     if (mWidth > 0 && mHeight > 0 && mDepth > 0)
327     {
328         ID3D11Device *device = mRenderer->getDevice();
329         HRESULT result;
330
331         int lodOffset = 1;
332         GLsizei width = mWidth;
333         GLsizei height = mHeight;
334
335         // adjust size if needed for compressed textures
336         d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
337
338         if (mTarget == GL_TEXTURE_3D)
339         {
340             ID3D11Texture3D *newTexture = NULL;
341
342             D3D11_TEXTURE3D_DESC desc;
343             desc.Width = width;
344             desc.Height = height;
345             desc.Depth = mDepth;
346             desc.MipLevels = lodOffset + 1;
347             desc.Format = dxgiFormat;
348             desc.Usage = D3D11_USAGE_STAGING;
349             desc.BindFlags = 0;
350             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
351             desc.MiscFlags = 0;
352
353             if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))
354             {
355                 std::vector<D3D11_SUBRESOURCE_DATA> initialData;
356                 std::vector< std::vector<BYTE> > textureData;
357                 d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getCurrentClientVersion(), width, height,
358                                                   mDepth, lodOffset + 1, &initialData, &textureData);
359
360                 result = device->CreateTexture3D(&desc, initialData.data(), &newTexture);
361             }
362             else
363             {
364                 result = device->CreateTexture3D(&desc, NULL, &newTexture);
365             }
366
367             if (FAILED(result))
368             {
369                 ASSERT(result == E_OUTOFMEMORY);
370                 ERR("Creating image failed.");
371                 return gl::error(GL_OUT_OF_MEMORY);
372             }
373
374             mStagingTexture = newTexture;
375             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
376         }
377         else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP)
378         {
379             ID3D11Texture2D *newTexture = NULL;
380
381             D3D11_TEXTURE2D_DESC desc;
382             desc.Width = width;
383             desc.Height = height;
384             desc.MipLevels = lodOffset + 1;
385             desc.ArraySize = 1;
386             desc.Format = dxgiFormat;
387             desc.SampleDesc.Count = 1;
388             desc.SampleDesc.Quality = 0;
389             desc.Usage = D3D11_USAGE_STAGING;
390             desc.BindFlags = 0;
391             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
392             desc.MiscFlags = 0;
393
394             if (gl_d3d11::RequiresTextureDataInitialization(mInternalFormat))
395             {
396                 std::vector<D3D11_SUBRESOURCE_DATA> initialData;
397                 std::vector< std::vector<BYTE> > textureData;
398                 d3d11::GenerateInitialTextureData(mInternalFormat, mRenderer->getCurrentClientVersion(), width, height,
399                                                   1, lodOffset + 1, &initialData, &textureData);
400
401                 result = device->CreateTexture2D(&desc, initialData.data(), &newTexture);
402             }
403             else
404             {
405                 result = device->CreateTexture2D(&desc, NULL, &newTexture);
406             }
407
408             if (FAILED(result))
409             {
410                 ASSERT(result == E_OUTOFMEMORY);
411                 ERR("Creating image failed.");
412                 return gl::error(GL_OUT_OF_MEMORY);
413             }
414
415             mStagingTexture = newTexture;
416             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
417         }
418         else
419         {
420             UNREACHABLE();
421         }
422     }
423
424     mDirty = false;
425 }
426
427 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
428 {
429     createStagingTexture();
430
431     HRESULT result = E_FAIL;
432
433     if (mStagingTexture)
434     {
435         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
436         result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
437
438         // this can fail if the device is removed (from TDR)
439         if (d3d11::isDeviceLostError(result))
440         {
441             mRenderer->notifyDeviceLost();
442         }
443         else if (SUCCEEDED(result))
444         {
445             mDirty = true;
446         }
447     }
448
449     return result;
450 }
451
452 void Image11::unmap()
453 {
454     if (mStagingTexture)
455     {
456         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
457         deviceContext->Unmap(mStagingTexture, mStagingSubresource);
458     }
459 }
460
461 }