1 //
2 // Copyright 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 "libANGLE/renderer/d3d/d3d11/Image11.h"
11 
12 #include "common/utilities.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Framebuffer.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/formatutils.h"
17 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
18 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
19 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
20 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
21 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
22 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
23 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
24 
25 namespace rx
26 {
27 
Image11(Renderer11 * renderer)28 Image11::Image11(Renderer11 *renderer)
29     : mRenderer(renderer),
30       mDXGIFormat(DXGI_FORMAT_UNKNOWN),
31       mStagingTexture(),
32       mStagingSubresource(0),
33       mRecoverFromStorage(false),
34       mAssociatedStorage(nullptr),
35       mAssociatedImageIndex(),
36       mRecoveredFromStorageCount(0)
37 {}
38 
~Image11()39 Image11::~Image11()
40 {
41     disassociateStorage();
42     releaseStagingTexture();
43 }
44 
45 // static
GenerateMipmap(const gl::Context * context,Image11 * dest,Image11 * src,const Renderer11DeviceCaps & rendererCaps)46 angle::Result Image11::GenerateMipmap(const gl::Context *context,
47                                       Image11 *dest,
48                                       Image11 *src,
49                                       const Renderer11DeviceCaps &rendererCaps)
50 {
51     ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
52     ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
53     ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
54 
55     D3D11_MAPPED_SUBRESOURCE destMapped;
56     ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped));
57     d3d11::ScopedUnmapper<Image11> destRAII(dest);
58 
59     D3D11_MAPPED_SUBRESOURCE srcMapped;
60     ANGLE_TRY(src->map(context, D3D11_MAP_READ, &srcMapped));
61     d3d11::ScopedUnmapper<Image11> srcRAII(src);
62 
63     const uint8_t *sourceData = static_cast<const uint8_t *>(srcMapped.pData);
64     uint8_t *destData         = static_cast<uint8_t *>(destMapped.pData);
65 
66     auto mipGenerationFunction =
67         d3d11::Format::Get(src->getInternalFormat(), rendererCaps).format().mipGenerationFunction;
68     mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData,
69                           srcMapped.RowPitch, srcMapped.DepthPitch, destData, destMapped.RowPitch,
70                           destMapped.DepthPitch);
71 
72     dest->markDirty();
73 
74     return angle::Result::Continue;
75 }
76 
77 // static
CopyImage(const gl::Context * context,Image11 * dest,Image11 * source,const gl::Box & sourceBox,const gl::Offset & destOffset,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const Renderer11DeviceCaps & rendererCaps)78 angle::Result Image11::CopyImage(const gl::Context *context,
79                                  Image11 *dest,
80                                  Image11 *source,
81                                  const gl::Box &sourceBox,
82                                  const gl::Offset &destOffset,
83                                  bool unpackFlipY,
84                                  bool unpackPremultiplyAlpha,
85                                  bool unpackUnmultiplyAlpha,
86                                  const Renderer11DeviceCaps &rendererCaps)
87 {
88     D3D11_MAPPED_SUBRESOURCE destMapped;
89     ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped));
90     d3d11::ScopedUnmapper<Image11> destRAII(dest);
91 
92     D3D11_MAPPED_SUBRESOURCE srcMapped;
93     ANGLE_TRY(source->map(context, D3D11_MAP_READ, &srcMapped));
94     d3d11::ScopedUnmapper<Image11> sourceRAII(source);
95 
96     const auto &sourceFormat =
97         d3d11::Format::Get(source->getInternalFormat(), rendererCaps).format();
98     GLuint sourcePixelBytes =
99         gl::GetSizedInternalFormatInfo(sourceFormat.fboImplementationInternalFormat).pixelBytes;
100 
101     GLenum destUnsizedFormat = gl::GetUnsizedFormat(dest->getInternalFormat());
102     const auto &destFormat   = d3d11::Format::Get(dest->getInternalFormat(), rendererCaps).format();
103     const auto &destFormatInfo =
104         gl::GetSizedInternalFormatInfo(destFormat.fboImplementationInternalFormat);
105     GLuint destPixelBytes = destFormatInfo.pixelBytes;
106 
107     const uint8_t *sourceData = static_cast<const uint8_t *>(srcMapped.pData) +
108                                 sourceBox.x * sourcePixelBytes + sourceBox.y * srcMapped.RowPitch +
109                                 sourceBox.z * srcMapped.DepthPitch;
110     uint8_t *destData = static_cast<uint8_t *>(destMapped.pData) + destOffset.x * destPixelBytes +
111                         destOffset.y * destMapped.RowPitch + destOffset.z * destMapped.DepthPitch;
112 
113     CopyImageCHROMIUM(sourceData, srcMapped.RowPitch, sourcePixelBytes, srcMapped.DepthPitch,
114                       sourceFormat.pixelReadFunction, destData, destMapped.RowPitch, destPixelBytes,
115                       destMapped.DepthPitch, destFormat.pixelWriteFunction, destUnsizedFormat,
116                       destFormatInfo.componentType, sourceBox.width, sourceBox.height,
117                       sourceBox.depth, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
118 
119     dest->markDirty();
120 
121     return angle::Result::Continue;
122 }
123 
isDirty() const124 bool Image11::isDirty() const
125 {
126     // If mDirty is true AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be
127     // recovered from TextureStorage AND the texture doesn't require init data (i.e. a blank new
128     // texture will suffice) AND robust resource initialization is not enabled then isDirty should
129     // still return false.
130     if (mDirty && !mStagingTexture.valid() && !mRecoverFromStorage)
131     {
132         const Renderer11DeviceCaps &deviceCaps = mRenderer->getRenderer11DeviceCaps();
133         const auto &formatInfo                 = d3d11::Format::Get(mInternalFormat, deviceCaps);
134         if (formatInfo.dataInitializerFunction == nullptr)
135         {
136             return false;
137         }
138     }
139 
140     return mDirty;
141 }
142 
copyToStorage(const gl::Context * context,TextureStorage * storage,const gl::ImageIndex & index,const gl::Box & region)143 angle::Result Image11::copyToStorage(const gl::Context *context,
144                                      TextureStorage *storage,
145                                      const gl::ImageIndex &index,
146                                      const gl::Box &region)
147 {
148     TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage);
149 
150     // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage
151     // multiple times, then we should just keep the staging texture around to prevent the copying
152     // from impacting perf. We allow the Image11 to copy its data to/from TextureStorage once. This
153     // accounts for an app making a late call to glGenerateMipmap.
154     bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2);
155 
156     if (attemptToReleaseStagingTexture)
157     {
158         // If another image is relying on this Storage for its data, then we must let it recover its
159         // data before we overwrite it.
160         ANGLE_TRY(storage11->releaseAssociatedImage(context, index, this));
161     }
162 
163     const TextureHelper11 *stagingTexture = nullptr;
164     unsigned int stagingSubresourceIndex  = 0;
165     ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
166     ANGLE_TRY(storage11->updateSubresourceLevel(context, *stagingTexture, stagingSubresourceIndex,
167                                                 index, region));
168 
169     // Once the image data has been copied into the Storage, we can release it locally.
170     if (attemptToReleaseStagingTexture)
171     {
172         storage11->associateImage(this, index);
173         releaseStagingTexture();
174         mRecoverFromStorage   = true;
175         mAssociatedStorage    = storage11;
176         mAssociatedImageIndex = index;
177     }
178 
179     return angle::Result::Continue;
180 }
181 
verifyAssociatedStorageValid(TextureStorage11 * textureStorage) const182 void Image11::verifyAssociatedStorageValid(TextureStorage11 *textureStorage) const
183 {
184     ASSERT(mAssociatedStorage == textureStorage);
185 }
186 
recoverFromAssociatedStorage(const gl::Context * context)187 angle::Result Image11::recoverFromAssociatedStorage(const gl::Context *context)
188 {
189     if (mRecoverFromStorage)
190     {
191         ANGLE_TRY(createStagingTexture(context));
192 
193         mAssociatedStorage->verifyAssociatedImageValid(mAssociatedImageIndex, this);
194 
195         // CopySubResource from the Storage to the Staging texture
196         gl::Box region(0, 0, 0, mWidth, mHeight, mDepth);
197         ANGLE_TRY(mAssociatedStorage->copySubresourceLevel(
198             context, mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region));
199         mRecoveredFromStorageCount += 1;
200 
201         // Reset all the recovery parameters, even if the texture storage association is broken.
202         disassociateStorage();
203     }
204 
205     return angle::Result::Continue;
206 }
207 
disassociateStorage()208 void Image11::disassociateStorage()
209 {
210     if (mRecoverFromStorage)
211     {
212         // Make the texturestorage release the Image11 too
213         mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this);
214 
215         mRecoverFromStorage   = false;
216         mAssociatedStorage    = nullptr;
217         mAssociatedImageIndex = gl::ImageIndex();
218     }
219 }
220 
redefine(gl::TextureType type,GLenum internalformat,const gl::Extents & size,bool forceRelease)221 bool Image11::redefine(gl::TextureType type,
222                        GLenum internalformat,
223                        const gl::Extents &size,
224                        bool forceRelease)
225 {
226     if (mWidth != size.width || mHeight != size.height || mInternalFormat != internalformat ||
227         forceRelease)
228     {
229         // End the association with the TextureStorage, since that data will be out of date.
230         // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
231         disassociateStorage();
232         mRecoveredFromStorageCount = 0;
233 
234         mWidth          = size.width;
235         mHeight         = size.height;
236         mDepth          = size.depth;
237         mInternalFormat = internalformat;
238         mType           = type;
239 
240         // compute the d3d format that will be used
241         const d3d11::Format &formatInfo =
242             d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps());
243         mDXGIFormat = formatInfo.texFormat;
244         mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
245 
246         releaseStagingTexture();
247         mDirty = (formatInfo.dataInitializerFunction != nullptr);
248 
249         return true;
250     }
251 
252     return false;
253 }
254 
getDXGIFormat() const255 DXGI_FORMAT Image11::getDXGIFormat() const
256 {
257     // this should only happen if the image hasn't been redefined first
258     // which would be a bug by the caller
259     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
260 
261     return mDXGIFormat;
262 }
263 
264 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
265 // format/type at input
266 // into the target pixel rectangle.
loadData(const gl::Context * context,const gl::Box & area,const gl::PixelUnpackState & unpack,GLenum type,const void * input,bool applySkipImages)267 angle::Result Image11::loadData(const gl::Context *context,
268                                 const gl::Box &area,
269                                 const gl::PixelUnpackState &unpack,
270                                 GLenum type,
271                                 const void *input,
272                                 bool applySkipImages)
273 {
274     Context11 *context11 = GetImplAs<Context11>(context);
275 
276     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
277     GLuint inputRowPitch                 = 0;
278     ANGLE_CHECK_GL_MATH(context11, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
279                                                               unpack.rowLength, &inputRowPitch));
280     GLuint inputDepthPitch = 0;
281     ANGLE_CHECK_GL_MATH(context11, formatInfo.computeDepthPitch(area.height, unpack.imageHeight,
282                                                                 inputRowPitch, &inputDepthPitch));
283     GLuint inputSkipBytes = 0;
284     ANGLE_CHECK_GL_MATH(context11,
285                         formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack,
286                                                     applySkipImages, &inputSkipBytes));
287 
288     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
289     GLuint outputPixelSize                      = dxgiFormatInfo.pixelBytes;
290 
291     const d3d11::Format &d3dFormatInfo =
292         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
293     LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction;
294 
295     D3D11_MAPPED_SUBRESOURCE mappedImage;
296     ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
297 
298     uint8_t *offsetMappedData = (static_cast<uint8_t *>(mappedImage.pData) +
299                                  (area.y * mappedImage.RowPitch + area.x * outputPixelSize +
300                                   area.z * mappedImage.DepthPitch));
301     loadFunction(area.width, area.height, area.depth,
302                  static_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch,
303                  inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
304 
305     unmap();
306 
307     return angle::Result::Continue;
308 }
309 
loadCompressedData(const gl::Context * context,const gl::Box & area,const void * input)310 angle::Result Image11::loadCompressedData(const gl::Context *context,
311                                           const gl::Box &area,
312                                           const void *input)
313 {
314     Context11 *context11 = GetImplAs<Context11>(context);
315 
316     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
317     GLuint inputRowPitch                 = 0;
318     ANGLE_CHECK_GL_MATH(
319         context11, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
320     GLuint inputDepthPitch = 0;
321     ANGLE_CHECK_GL_MATH(
322         context11, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
323 
324     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
325     GLuint outputPixelSize                      = dxgiFormatInfo.pixelBytes;
326     GLuint outputBlockWidth                     = dxgiFormatInfo.blockWidth;
327     GLuint outputBlockHeight                    = dxgiFormatInfo.blockHeight;
328 
329     ASSERT(area.x % outputBlockWidth == 0);
330     ASSERT(area.y % outputBlockHeight == 0);
331 
332     const d3d11::Format &d3dFormatInfo =
333         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
334     LoadImageFunction loadFunction =
335         d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction;
336 
337     D3D11_MAPPED_SUBRESOURCE mappedImage;
338     ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
339 
340     uint8_t *offsetMappedData =
341         static_cast<uint8_t *>(mappedImage.pData) +
342         ((area.y / outputBlockHeight) * mappedImage.RowPitch +
343          (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch);
344 
345     loadFunction(area.width, area.height, area.depth, static_cast<const uint8_t *>(input),
346                  inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch,
347                  mappedImage.DepthPitch);
348 
349     unmap();
350 
351     return angle::Result::Continue;
352 }
353 
copyFromTexStorage(const gl::Context * context,const gl::ImageIndex & imageIndex,TextureStorage * source)354 angle::Result Image11::copyFromTexStorage(const gl::Context *context,
355                                           const gl::ImageIndex &imageIndex,
356                                           TextureStorage *source)
357 {
358     TextureStorage11 *storage11 = GetAs<TextureStorage11>(source);
359 
360     const TextureHelper11 *textureHelper = nullptr;
361     ANGLE_TRY(storage11->getResource(context, &textureHelper));
362 
363     UINT subresourceIndex = 0;
364     ANGLE_TRY(storage11->getSubresourceIndex(context, imageIndex, &subresourceIndex));
365 
366     gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth);
367     return copyWithoutConversion(context, gl::Offset(), sourceBox, *textureHelper,
368                                  subresourceIndex);
369 }
370 
copyFromFramebuffer(const gl::Context * context,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::Framebuffer * sourceFBO)371 angle::Result Image11::copyFromFramebuffer(const gl::Context *context,
372                                            const gl::Offset &destOffset,
373                                            const gl::Rectangle &sourceArea,
374                                            const gl::Framebuffer *sourceFBO)
375 {
376     const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorAttachment();
377     ASSERT(srcAttachment);
378 
379     GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat;
380     const auto &d3d11Format =
381         d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps());
382 
383     if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat)
384     {
385         RenderTarget11 *rt11 = nullptr;
386         ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &rt11));
387         ASSERT(rt11->getTexture().get());
388 
389         TextureHelper11 textureHelper  = rt11->getTexture();
390         unsigned int sourceSubResource = rt11->getSubresourceIndex();
391 
392         gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
393         return copyWithoutConversion(context, destOffset, sourceBox, textureHelper,
394                                      sourceSubResource);
395     }
396 
397     // This format requires conversion, so we must copy the texture to staging and manually convert
398     // via readPixels
399     D3D11_MAPPED_SUBRESOURCE mappedImage;
400     ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
401 
402     // determine the offset coordinate into the destination buffer
403     const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
404     GLsizei rowOffset          = dxgiFormatInfo.pixelBytes * destOffset.x;
405 
406     uint8_t *dataOffset = static_cast<uint8_t *>(mappedImage.pData) +
407                           mappedImage.RowPitch * destOffset.y + rowOffset +
408                           destOffset.z * mappedImage.DepthPitch;
409 
410     const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
411     const auto &destD3D11Format =
412         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
413 
414     auto loadFunction    = destD3D11Format.getLoadFunctions()(destFormatInfo.type);
415     angle::Result result = angle::Result::Continue;
416     if (loadFunction.requiresConversion)
417     {
418         size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height;
419         angle::MemoryBuffer *memoryBuffer = nullptr;
420         result = mRenderer->getScratchMemoryBuffer(GetImplAs<Context11>(context), bufferSize,
421                                                    &memoryBuffer);
422 
423         if (result == angle::Result::Continue)
424         {
425             GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width;
426 
427             result = mRenderer->readFromAttachment(
428                 context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
429                 memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data());
430 
431             loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(),
432                                       memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch,
433                                       mappedImage.DepthPitch);
434         }
435     }
436     else
437     {
438         result = mRenderer->readFromAttachment(
439             context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
440             mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
441     }
442 
443     unmap();
444     mDirty = true;
445 
446     return result;
447 }
448 
copyWithoutConversion(const gl::Context * context,const gl::Offset & destOffset,const gl::Box & sourceArea,const TextureHelper11 & textureHelper,UINT sourceSubResource)449 angle::Result Image11::copyWithoutConversion(const gl::Context *context,
450                                              const gl::Offset &destOffset,
451                                              const gl::Box &sourceArea,
452                                              const TextureHelper11 &textureHelper,
453                                              UINT sourceSubResource)
454 {
455     // No conversion needed-- use copyback fastpath
456     const TextureHelper11 *stagingTexture = nullptr;
457     unsigned int stagingSubresourceIndex  = 0;
458     ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
459 
460     ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
461 
462     const gl::Extents &extents = textureHelper.getExtents();
463 
464     D3D11_BOX srcBox;
465     srcBox.left   = sourceArea.x;
466     srcBox.right  = sourceArea.x + sourceArea.width;
467     srcBox.top    = sourceArea.y;
468     srcBox.bottom = sourceArea.y + sourceArea.height;
469     srcBox.front  = sourceArea.z;
470     srcBox.back   = sourceArea.z + sourceArea.depth;
471 
472     if (textureHelper.is2D() && textureHelper.getSampleCount() > 1)
473     {
474         D3D11_TEXTURE2D_DESC resolveDesc;
475         resolveDesc.Width              = extents.width;
476         resolveDesc.Height             = extents.height;
477         resolveDesc.MipLevels          = 1;
478         resolveDesc.ArraySize          = 1;
479         resolveDesc.Format             = textureHelper.getFormat();
480         resolveDesc.SampleDesc.Count   = 1;
481         resolveDesc.SampleDesc.Quality = 0;
482         resolveDesc.Usage              = D3D11_USAGE_DEFAULT;
483         resolveDesc.BindFlags          = 0;
484         resolveDesc.CPUAccessFlags     = 0;
485         resolveDesc.MiscFlags          = 0;
486 
487         d3d11::Texture2D resolveTex;
488         ANGLE_TRY(
489             mRenderer->allocateResource(GetImplAs<Context11>(context), resolveDesc, &resolveTex));
490 
491         deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(),
492                                           sourceSubResource, textureHelper.getFormat());
493 
494         deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
495                                              destOffset.x, destOffset.y, destOffset.z,
496                                              resolveTex.get(), 0, &srcBox);
497     }
498     else
499     {
500         deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
501                                              destOffset.x, destOffset.y, destOffset.z,
502                                              textureHelper.get(), sourceSubResource, &srcBox);
503     }
504 
505     mDirty = true;
506     return angle::Result::Continue;
507 }
508 
getStagingTexture(const gl::Context * context,const TextureHelper11 ** outStagingTexture,unsigned int * outSubresourceIndex)509 angle::Result Image11::getStagingTexture(const gl::Context *context,
510                                          const TextureHelper11 **outStagingTexture,
511                                          unsigned int *outSubresourceIndex)
512 {
513     ANGLE_TRY(createStagingTexture(context));
514 
515     *outStagingTexture   = &mStagingTexture;
516     *outSubresourceIndex = mStagingSubresource;
517     return angle::Result::Continue;
518 }
519 
releaseStagingTexture()520 void Image11::releaseStagingTexture()
521 {
522     mStagingTexture.reset();
523     mStagingTextureSubresourceVerifier.reset();
524 }
525 
createStagingTexture(const gl::Context * context)526 angle::Result Image11::createStagingTexture(const gl::Context *context)
527 {
528     if (mStagingTexture.valid())
529     {
530         return angle::Result::Continue;
531     }
532 
533     ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0);
534 
535     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
536     const auto &formatInfo =
537         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
538 
539     int lodOffset  = 1;
540     GLsizei width  = mWidth;
541     GLsizei height = mHeight;
542 
543     // adjust size if needed for compressed textures
544     d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
545 
546     Context11 *context11 = GetImplAs<Context11>(context);
547 
548     switch (mType)
549     {
550         case gl::TextureType::_3D:
551         {
552             D3D11_TEXTURE3D_DESC desc;
553             desc.Width          = width;
554             desc.Height         = height;
555             desc.Depth          = mDepth;
556             desc.MipLevels      = lodOffset + 1;
557             desc.Format         = dxgiFormat;
558             desc.Usage          = D3D11_USAGE_STAGING;
559             desc.BindFlags      = 0;
560             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
561             desc.MiscFlags      = 0;
562 
563             if (formatInfo.dataInitializerFunction != nullptr)
564             {
565                 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
566                 ANGLE_TRY(d3d11::GenerateInitialTextureData(
567                     context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
568                     mDepth, lodOffset + 1, &initialData));
569 
570                 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
571                                                      initialData.data(), &mStagingTexture));
572             }
573             else
574             {
575                 ANGLE_TRY(
576                     mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
577             }
578 
579             mStagingTexture.setDebugName("Image11::StagingTexture3D");
580             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
581             mStagingTextureSubresourceVerifier.setDesc(desc);
582         }
583         break;
584 
585         case gl::TextureType::_2D:
586         case gl::TextureType::_2DArray:
587         case gl::TextureType::CubeMap:
588         {
589             D3D11_TEXTURE2D_DESC desc;
590             desc.Width              = width;
591             desc.Height             = height;
592             desc.MipLevels          = lodOffset + 1;
593             desc.ArraySize          = 1;
594             desc.Format             = dxgiFormat;
595             desc.SampleDesc.Count   = 1;
596             desc.SampleDesc.Quality = 0;
597             desc.Usage              = D3D11_USAGE_STAGING;
598             desc.BindFlags          = 0;
599             desc.CPUAccessFlags     = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
600             desc.MiscFlags          = 0;
601 
602             if (formatInfo.dataInitializerFunction != nullptr)
603             {
604                 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
605                 ANGLE_TRY(d3d11::GenerateInitialTextureData(
606                     context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
607                     1, lodOffset + 1, &initialData));
608 
609                 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
610                                                      initialData.data(), &mStagingTexture));
611             }
612             else
613             {
614                 ANGLE_TRY(
615                     mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
616             }
617 
618             mStagingTexture.setDebugName("Image11::StagingTexture2D");
619             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
620             mStagingTextureSubresourceVerifier.setDesc(desc);
621         }
622         break;
623 
624         default:
625             UNREACHABLE();
626     }
627 
628     mDirty = false;
629     return angle::Result::Continue;
630 }
631 
map(const gl::Context * context,D3D11_MAP mapType,D3D11_MAPPED_SUBRESOURCE * map)632 angle::Result Image11::map(const gl::Context *context,
633                            D3D11_MAP mapType,
634                            D3D11_MAPPED_SUBRESOURCE *map)
635 {
636     // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
637     ANGLE_TRY(recoverFromAssociatedStorage(context));
638 
639     const TextureHelper11 *stagingTexture = nullptr;
640     unsigned int subresourceIndex         = 0;
641     ANGLE_TRY(getStagingTexture(context, &stagingTexture, &subresourceIndex));
642 
643     ASSERT(stagingTexture && stagingTexture->valid());
644 
645     ANGLE_TRY(
646         mRenderer->mapResource(context, stagingTexture->get(), subresourceIndex, mapType, 0, map));
647 
648     if (!mStagingTextureSubresourceVerifier.wrap(mapType, map))
649     {
650         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
651         deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
652         Context11 *context11 = GetImplAs<Context11>(context);
653         context11->handleError(GL_OUT_OF_MEMORY,
654                                "Failed to allocate staging texture mapping verifier buffer.",
655                                __FILE__, ANGLE_FUNCTION, __LINE__);
656         return angle::Result::Stop;
657     }
658 
659     mDirty = true;
660 
661     return angle::Result::Continue;
662 }
663 
unmap()664 void Image11::unmap()
665 {
666     if (mStagingTexture.valid())
667     {
668         mStagingTextureSubresourceVerifier.unwrap();
669         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
670         deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
671     }
672 }
673 
674 }  // namespace rx
675