Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d / d3d11 / Image11.cpp
1 //
2 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
8 // the actual underlying resources of a Texture
9
10 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
11 #include "libGLESv2/renderer/d3d/d3d11/Image11.h"
12 #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h"
13 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
14 #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
15 #include "libGLESv2/Framebuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/main.h"
18
19 #include "common/utilities.h"
20
21 namespace rx
22 {
23
24 Image11::Image11()
25 {
26     mStagingTexture = NULL;
27     mRenderer = NULL;
28     mDXGIFormat = DXGI_FORMAT_UNKNOWN;
29     mRecoverFromStorage = false;
30     mAssociatedStorage = NULL;
31     mAssociatedStorageLevel = 0;
32     mAssociatedStorageLayerTarget = 0;
33     mRecoveredFromStorageCount = 0;
34 }
35
36 Image11::~Image11()
37 {
38     disassociateStorage();
39     releaseStagingTexture();
40 }
41
42 Image11 *Image11::makeImage11(Image *img)
43 {
44     ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
45     return static_cast<rx::Image11*>(img);
46 }
47
48 void Image11::generateMipmap(Image11 *dest, Image11 *src)
49 {
50     ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
51     ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
52     ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
53
54     const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(src->getDXGIFormat());
55     ASSERT(dxgiFormatInfo.mipGenerationFunction != NULL);
56
57     D3D11_MAPPED_SUBRESOURCE destMapped;
58     HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped);
59     if (FAILED(destMapResult))
60     {
61         ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult);
62         return;
63     }
64
65     D3D11_MAPPED_SUBRESOURCE srcMapped;
66     HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped);
67     if (FAILED(srcMapResult))
68     {
69         ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult);
70
71         dest->unmap();
72         return;
73     }
74
75     const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(srcMapped.pData);
76     uint8_t *destData = reinterpret_cast<uint8_t*>(destMapped.pData);
77
78     dxgiFormatInfo.mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(),
79                                          sourceData, srcMapped.RowPitch, srcMapped.DepthPitch,
80                                          destData, destMapped.RowPitch, destMapped.DepthPitch);
81
82     dest->unmap();
83     src->unmap();
84
85     dest->markDirty();
86 }
87
88 bool Image11::isDirty() const
89 {
90     // If mDirty is true
91     // AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage
92     // AND the texture doesn't require init data (i.e. a blank new texture will suffice)
93     // then isDirty should still return false.
94     if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL))
95     {
96         return false;
97     }
98
99     return mDirty;
100 }
101
102 bool Image11::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
103 {
104     TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage);
105     return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
106 }
107
108 bool Image11::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
109 {
110     TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage);
111     return copyToStorageImpl(storage11, level, face, xoffset, yoffset, width, height);
112 }
113
114 bool Image11::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
115 {
116     TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage);
117     return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
118 }
119
120 bool Image11::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
121 {
122     TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage);
123     return copyToStorageImpl(storage11, level, arrayLayer, xoffset, yoffset, width, height);
124 }
125
126 bool Image11::copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
127 {
128     // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times,
129     // then we should just keep the staging texture around to prevent the copying from impacting perf.
130     // We allow the Image11 to copy its data to/from TextureStorage once.
131     // This accounts for an app making a late call to glGenerateMipmap.
132     bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2);
133
134     if (attemptToReleaseStagingTexture)
135     {
136         // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it.
137         storage11->releaseAssociatedImage(level, layerTarget, this);
138     }
139
140     bool updateSubresourceSuccess = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, layerTarget, xoffset, yoffset, 0, width, height, 1);
141
142     // Once the image data has been copied into the Storage, we can release it locally.
143     if (attemptToReleaseStagingTexture && updateSubresourceSuccess)
144     {
145         storage11->associateImage(this, level, layerTarget);
146         releaseStagingTexture();
147         mRecoverFromStorage = true;
148         mAssociatedStorage = storage11;
149         mAssociatedStorageLevel = level;
150         mAssociatedStorageLayerTarget = layerTarget;
151     }
152
153     return updateSubresourceSuccess;
154 }
155
156 bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const
157 {
158     return (mAssociatedStorage == textureStorage);
159 }
160
161 bool Image11::recoverFromAssociatedStorage()
162 {
163     if (mRecoverFromStorage)
164     {
165         createStagingTexture();
166
167         bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this);
168
169         // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. 
170         // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten.
171         ASSERT(textureStorageCorrect);
172
173         if (textureStorageCorrect)
174         {
175             // CopySubResource from the Storage to the Staging texture
176             mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedStorageLevel, mAssociatedStorageLayerTarget, 0, 0, 0, mWidth, mHeight, mDepth);
177             mRecoveredFromStorageCount += 1;
178         }
179
180         // Reset all the recovery parameters, even if the texture storage association is broken.
181         disassociateStorage();
182
183         return textureStorageCorrect;
184     }
185
186     return false;
187 }
188
189 void Image11::disassociateStorage()
190 {
191     if (mRecoverFromStorage)
192     {
193         // Make the texturestorage release the Image11 too
194         mAssociatedStorage->disassociateImage(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this);
195
196         mRecoverFromStorage = false;
197         mAssociatedStorage = NULL;
198         mAssociatedStorageLevel = 0;
199         mAssociatedStorageLayerTarget = 0;
200     }
201 }
202
203 bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
204 {
205     if (mWidth != width ||
206         mHeight != height ||
207         mInternalFormat != internalformat ||
208         forceRelease)
209     {
210         // End the association with the TextureStorage, since that data will be out of date.
211         // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
212         disassociateStorage();
213         mRecoveredFromStorageCount = 0;
214
215         mRenderer = Renderer11::makeRenderer11(renderer);
216
217         mWidth = width;
218         mHeight = height;
219         mDepth = depth;
220         mInternalFormat = internalformat;
221         mTarget = target;
222
223         // compute the d3d format that will be used
224         const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat);
225         const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat);
226         mDXGIFormat = formatInfo.texFormat;
227         mActualFormat = dxgiFormatInfo.internalFormat;
228         mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
229
230         SafeRelease(mStagingTexture);
231         mDirty = (formatInfo.dataInitializerFunction != NULL);
232
233         return true;
234     }
235
236     return false;
237 }
238
239 DXGI_FORMAT Image11::getDXGIFormat() const
240 {
241     // this should only happen if the image hasn't been redefined first
242     // which would be a bug by the caller
243     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
244
245     return mDXGIFormat;
246 }
247
248 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
249 // into the target pixel rectangle.
250 void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
251                        GLint unpackAlignment, GLenum type, const void *input)
252 {
253     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
254     GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment);
255     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpackAlignment);
256
257     const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat);
258     GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
259
260     const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat);
261     LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type);
262
263     D3D11_MAPPED_SUBRESOURCE mappedImage;
264     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
265     if (FAILED(result))
266     {
267         ERR("Could not map image for loading.");
268         return;
269     }
270
271     uint8_t* offsetMappedData = (reinterpret_cast<uint8_t*>(mappedImage.pData) + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch));
272     loadFunction(width, height, depth,
273                  reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch,
274                  offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
275
276     unmap();
277 }
278
279 void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
280                                  const void *input)
281 {
282     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
283     GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1);
284     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
285
286     const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat);
287     GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
288     GLuint outputBlockWidth = dxgiFormatInfo.blockWidth;
289     GLuint outputBlockHeight = dxgiFormatInfo.blockHeight;
290
291     ASSERT(xoffset % outputBlockWidth == 0);
292     ASSERT(yoffset % outputBlockHeight == 0);
293
294     const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat);
295     LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE);
296
297     D3D11_MAPPED_SUBRESOURCE mappedImage;
298     HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
299     if (FAILED(result))
300     {
301         ERR("Could not map image for loading.");
302         return;
303     }
304
305     uint8_t* offsetMappedData = reinterpret_cast<uint8_t*>(mappedImage.pData) + ((yoffset / outputBlockHeight) * mappedImage.RowPitch +
306                                                                            (xoffset / outputBlockWidth) * outputPixelSize +
307                                                                            zoffset * mappedImage.DepthPitch);
308
309     loadFunction(width, height, depth,
310                  reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch,
311                  offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
312
313     unmap();
314 }
315
316 void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
317 {
318     gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
319
320     if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat)
321     {
322         // No conversion needed-- use copyback fastpath
323         ID3D11Texture2D *colorBufferTexture = NULL;
324         unsigned int subresourceIndex = 0;
325
326         if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
327         {
328             D3D11_TEXTURE2D_DESC textureDesc;
329             colorBufferTexture->GetDesc(&textureDesc);
330
331             ID3D11Device *device = mRenderer->getDevice();
332             ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
333
334             ID3D11Texture2D* srcTex = NULL;
335             if (textureDesc.SampleDesc.Count > 1)
336             {
337                 D3D11_TEXTURE2D_DESC resolveDesc;
338                 resolveDesc.Width = textureDesc.Width;
339                 resolveDesc.Height = textureDesc.Height;
340                 resolveDesc.MipLevels = 1;
341                 resolveDesc.ArraySize = 1;
342                 resolveDesc.Format = textureDesc.Format;
343                 resolveDesc.SampleDesc.Count = 1;
344                 resolveDesc.SampleDesc.Quality = 0;
345                 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
346                 resolveDesc.BindFlags = 0;
347                 resolveDesc.CPUAccessFlags = 0;
348                 resolveDesc.MiscFlags = 0;
349
350                 HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
351                 if (FAILED(result))
352                 {
353                     ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
354                     return;
355                 }
356
357                 deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
358                 subresourceIndex = 0;
359             }
360             else
361             {
362                 srcTex = colorBufferTexture;
363                 srcTex->AddRef();
364             }
365
366             D3D11_BOX srcBox;
367             srcBox.left = x;
368             srcBox.right = x + width;
369             srcBox.top = y;
370             srcBox.bottom = y + height;
371             srcBox.front = 0;
372             srcBox.back = 1;
373
374             deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox);
375
376             SafeRelease(srcTex);
377             SafeRelease(colorBufferTexture);
378         }
379     }
380     else
381     {
382         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
383         D3D11_MAPPED_SUBRESOURCE mappedImage;
384         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
385         if (FAILED(result))
386         {
387             ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result);
388             return;
389         }
390
391         // determine the offset coordinate into the destination buffer
392         GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset;
393         uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
394
395         const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
396
397         mRenderer->readPixels(source, x, y, width, height, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
398
399         unmap();
400     }
401 }
402
403 ID3D11Resource *Image11::getStagingTexture()
404 {
405     createStagingTexture();
406
407     return mStagingTexture;
408 }
409
410 void Image11::releaseStagingTexture()
411 {
412     SafeRelease(mStagingTexture);
413 }
414
415 unsigned int Image11::getStagingSubresource()
416 {
417     createStagingTexture();
418
419     return mStagingSubresource;
420 }
421
422 void Image11::createStagingTexture()
423 {
424     if (mStagingTexture)
425     {
426         return;
427     }
428
429     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
430
431     if (mWidth > 0 && mHeight > 0 && mDepth > 0)
432     {
433         ID3D11Device *device = mRenderer->getDevice();
434         HRESULT result;
435
436         int lodOffset = 1;
437         GLsizei width = mWidth;
438         GLsizei height = mHeight;
439
440         // adjust size if needed for compressed textures
441         d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
442
443         if (mTarget == GL_TEXTURE_3D)
444         {
445             ID3D11Texture3D *newTexture = NULL;
446
447             D3D11_TEXTURE3D_DESC desc;
448             desc.Width = width;
449             desc.Height = height;
450             desc.Depth = mDepth;
451             desc.MipLevels = lodOffset + 1;
452             desc.Format = dxgiFormat;
453             desc.Usage = D3D11_USAGE_STAGING;
454             desc.BindFlags = 0;
455             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
456             desc.MiscFlags = 0;
457
458             if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL)
459             {
460                 std::vector<D3D11_SUBRESOURCE_DATA> initialData;
461                 std::vector< std::vector<BYTE> > textureData;
462                 d3d11::GenerateInitialTextureData(mInternalFormat, width, height, mDepth,
463                                                   lodOffset + 1, &initialData, &textureData);
464
465                 result = device->CreateTexture3D(&desc, initialData.data(), &newTexture);
466             }
467             else
468             {
469                 result = device->CreateTexture3D(&desc, NULL, &newTexture);
470             }
471
472             if (FAILED(result))
473             {
474                 ASSERT(result == E_OUTOFMEMORY);
475                 ERR("Creating image failed.");
476                 return gl::error(GL_OUT_OF_MEMORY);
477             }
478
479             mStagingTexture = newTexture;
480             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
481         }
482         else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP)
483         {
484             ID3D11Texture2D *newTexture = NULL;
485
486             D3D11_TEXTURE2D_DESC desc;
487             desc.Width = width;
488             desc.Height = height;
489             desc.MipLevels = lodOffset + 1;
490             desc.ArraySize = 1;
491             desc.Format = dxgiFormat;
492             desc.SampleDesc.Count = 1;
493             desc.SampleDesc.Quality = 0;
494             desc.Usage = D3D11_USAGE_STAGING;
495             desc.BindFlags = 0;
496             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
497             desc.MiscFlags = 0;
498
499             if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL)
500             {
501                 std::vector<D3D11_SUBRESOURCE_DATA> initialData;
502                 std::vector< std::vector<BYTE> > textureData;
503                 d3d11::GenerateInitialTextureData(mInternalFormat, width, height, 1,
504                                                   lodOffset + 1, &initialData, &textureData);
505
506                 result = device->CreateTexture2D(&desc, initialData.data(), &newTexture);
507             }
508             else
509             {
510                 result = device->CreateTexture2D(&desc, NULL, &newTexture);
511             }
512
513             if (FAILED(result))
514             {
515                 ASSERT(result == E_OUTOFMEMORY);
516                 ERR("Creating image failed.");
517                 return gl::error(GL_OUT_OF_MEMORY);
518             }
519
520             mStagingTexture = newTexture;
521             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
522         }
523         else
524         {
525             UNREACHABLE();
526         }
527     }
528
529     mDirty = false;
530 }
531
532 HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
533 {
534     createStagingTexture();
535
536     // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
537     recoverFromAssociatedStorage();
538
539     HRESULT result = E_FAIL;
540
541     if (mStagingTexture)
542     {
543         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
544         result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map);
545
546         // this can fail if the device is removed (from TDR)
547         if (d3d11::isDeviceLostError(result))
548         {
549             mRenderer->notifyDeviceLost();
550         }
551         else if (SUCCEEDED(result))
552         {
553             mDirty = true;
554         }
555     }
556
557     return result;
558 }
559
560 void Image11::unmap()
561 {
562     if (mStagingTexture)
563     {
564         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
565         deviceContext->Unmap(mStagingTexture, mStagingSubresource);
566     }
567 }
568
569 }