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 ®ion)
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 markDirty();
205 }
206
207 return angle::Result::Continue;
208 }
209
disassociateStorage()210 void Image11::disassociateStorage()
211 {
212 if (mRecoverFromStorage)
213 {
214 // Make the texturestorage release the Image11 too
215 mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this);
216
217 mRecoverFromStorage = false;
218 mAssociatedStorage = nullptr;
219 mAssociatedImageIndex = gl::ImageIndex();
220 }
221 }
222
redefine(gl::TextureType type,GLenum internalformat,const gl::Extents & size,bool forceRelease)223 bool Image11::redefine(gl::TextureType type,
224 GLenum internalformat,
225 const gl::Extents &size,
226 bool forceRelease)
227 {
228 if (mWidth != size.width || mHeight != size.height || mDepth != size.depth ||
229 mInternalFormat != internalformat || forceRelease)
230 {
231 // End the association with the TextureStorage, since that data will be out of date.
232 // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
233 disassociateStorage();
234 mRecoveredFromStorageCount = 0;
235
236 mWidth = size.width;
237 mHeight = size.height;
238 mDepth = size.depth;
239 mInternalFormat = internalformat;
240 mType = type;
241
242 // compute the d3d format that will be used
243 const d3d11::Format &formatInfo =
244 d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps());
245 mDXGIFormat = formatInfo.texFormat;
246 mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
247
248 releaseStagingTexture();
249 mDirty = (formatInfo.dataInitializerFunction != nullptr);
250
251 return true;
252 }
253
254 return false;
255 }
256
getDXGIFormat() const257 DXGI_FORMAT Image11::getDXGIFormat() const
258 {
259 // this should only happen if the image hasn't been redefined first
260 // which would be a bug by the caller
261 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
262
263 return mDXGIFormat;
264 }
265
266 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
267 // format/type at input
268 // 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)269 angle::Result Image11::loadData(const gl::Context *context,
270 const gl::Box &area,
271 const gl::PixelUnpackState &unpack,
272 GLenum type,
273 const void *input,
274 bool applySkipImages)
275 {
276 Context11 *context11 = GetImplAs<Context11>(context);
277
278 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
279 GLuint inputRowPitch = 0;
280 ANGLE_CHECK_GL_MATH(context11, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
281 unpack.rowLength, &inputRowPitch));
282 GLuint inputDepthPitch = 0;
283 ANGLE_CHECK_GL_MATH(context11, formatInfo.computeDepthPitch(area.height, unpack.imageHeight,
284 inputRowPitch, &inputDepthPitch));
285 GLuint inputSkipBytes = 0;
286 ANGLE_CHECK_GL_MATH(context11,
287 formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack,
288 applySkipImages, &inputSkipBytes));
289
290 const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
291 GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
292
293 const d3d11::Format &d3dFormatInfo =
294 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
295 LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction;
296
297 D3D11_MAPPED_SUBRESOURCE mappedImage;
298 ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
299
300 uint8_t *offsetMappedData = (static_cast<uint8_t *>(mappedImage.pData) +
301 (area.y * mappedImage.RowPitch + area.x * outputPixelSize +
302 area.z * mappedImage.DepthPitch));
303 loadFunction(area.width, area.height, area.depth,
304 static_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch,
305 inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
306
307 unmap();
308
309 return angle::Result::Continue;
310 }
311
loadCompressedData(const gl::Context * context,const gl::Box & area,const void * input)312 angle::Result Image11::loadCompressedData(const gl::Context *context,
313 const gl::Box &area,
314 const void *input)
315 {
316 Context11 *context11 = GetImplAs<Context11>(context);
317
318 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
319 GLuint inputRowPitch = 0;
320 ANGLE_CHECK_GL_MATH(
321 context11, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
322 GLuint inputDepthPitch = 0;
323 ANGLE_CHECK_GL_MATH(
324 context11, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
325
326 const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
327 GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
328 GLuint outputBlockWidth = dxgiFormatInfo.blockWidth;
329 GLuint outputBlockHeight = dxgiFormatInfo.blockHeight;
330
331 ASSERT(area.x % outputBlockWidth == 0);
332 ASSERT(area.y % outputBlockHeight == 0);
333
334 const d3d11::Format &d3dFormatInfo =
335 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
336 LoadImageFunction loadFunction =
337 d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction;
338
339 D3D11_MAPPED_SUBRESOURCE mappedImage;
340 ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
341
342 uint8_t *offsetMappedData =
343 static_cast<uint8_t *>(mappedImage.pData) +
344 ((area.y / outputBlockHeight) * mappedImage.RowPitch +
345 (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch);
346
347 loadFunction(area.width, area.height, area.depth, static_cast<const uint8_t *>(input),
348 inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch,
349 mappedImage.DepthPitch);
350
351 unmap();
352
353 return angle::Result::Continue;
354 }
355
copyFromTexStorage(const gl::Context * context,const gl::ImageIndex & imageIndex,TextureStorage * source)356 angle::Result Image11::copyFromTexStorage(const gl::Context *context,
357 const gl::ImageIndex &imageIndex,
358 TextureStorage *source)
359 {
360 TextureStorage11 *storage11 = GetAs<TextureStorage11>(source);
361
362 const TextureHelper11 *textureHelper = nullptr;
363 ANGLE_TRY(storage11->getResource(context, &textureHelper));
364
365 UINT subresourceIndex = 0;
366 ANGLE_TRY(storage11->getSubresourceIndex(context, imageIndex, &subresourceIndex));
367
368 gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth);
369 return copyWithoutConversion(context, gl::Offset(), sourceBox, *textureHelper,
370 subresourceIndex);
371 }
372
copyFromFramebuffer(const gl::Context * context,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::Framebuffer * sourceFBO)373 angle::Result Image11::copyFromFramebuffer(const gl::Context *context,
374 const gl::Offset &destOffset,
375 const gl::Rectangle &sourceArea,
376 const gl::Framebuffer *sourceFBO)
377 {
378 const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorAttachment();
379 ASSERT(srcAttachment);
380
381 GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat;
382 const auto &d3d11Format =
383 d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps());
384
385 if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat)
386 {
387 RenderTarget11 *rt11 = nullptr;
388 ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &rt11));
389 ASSERT(rt11->getTexture().get());
390
391 TextureHelper11 textureHelper = rt11->getTexture();
392 unsigned int sourceSubResource = rt11->getSubresourceIndex();
393
394 gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
395 return copyWithoutConversion(context, destOffset, sourceBox, textureHelper,
396 sourceSubResource);
397 }
398
399 // This format requires conversion, so we must copy the texture to staging and manually convert
400 // via readPixels
401 D3D11_MAPPED_SUBRESOURCE mappedImage;
402 ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
403
404 // determine the offset coordinate into the destination buffer
405 const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
406 GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x;
407
408 uint8_t *dataOffset = static_cast<uint8_t *>(mappedImage.pData) +
409 mappedImage.RowPitch * destOffset.y + rowOffset +
410 destOffset.z * mappedImage.DepthPitch;
411
412 const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
413 const auto &destD3D11Format =
414 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
415
416 auto loadFunction = destD3D11Format.getLoadFunctions()(destFormatInfo.type);
417 angle::Result result = angle::Result::Continue;
418 if (loadFunction.requiresConversion)
419 {
420 size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height;
421 angle::MemoryBuffer *memoryBuffer = nullptr;
422 result = mRenderer->getScratchMemoryBuffer(GetImplAs<Context11>(context), bufferSize,
423 &memoryBuffer);
424
425 if (result == angle::Result::Continue)
426 {
427 GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width;
428
429 result = mRenderer->readFromAttachment(
430 context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
431 memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data());
432
433 loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(),
434 memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch,
435 mappedImage.DepthPitch);
436 }
437 }
438 else
439 {
440 result = mRenderer->readFromAttachment(
441 context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
442 mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
443 }
444
445 unmap();
446 mDirty = true;
447
448 return result;
449 }
450
copyWithoutConversion(const gl::Context * context,const gl::Offset & destOffset,const gl::Box & sourceArea,const TextureHelper11 & textureHelper,UINT sourceSubResource)451 angle::Result Image11::copyWithoutConversion(const gl::Context *context,
452 const gl::Offset &destOffset,
453 const gl::Box &sourceArea,
454 const TextureHelper11 &textureHelper,
455 UINT sourceSubResource)
456 {
457 // No conversion needed-- use copyback fastpath
458 const TextureHelper11 *stagingTexture = nullptr;
459 unsigned int stagingSubresourceIndex = 0;
460 ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
461
462 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
463
464 const gl::Extents &extents = textureHelper.getExtents();
465
466 D3D11_BOX srcBox;
467 srcBox.left = sourceArea.x;
468 srcBox.right = sourceArea.x + sourceArea.width;
469 srcBox.top = sourceArea.y;
470 srcBox.bottom = sourceArea.y + sourceArea.height;
471 srcBox.front = sourceArea.z;
472 srcBox.back = sourceArea.z + sourceArea.depth;
473
474 if (textureHelper.is2D() && textureHelper.getSampleCount() > 1)
475 {
476 D3D11_TEXTURE2D_DESC resolveDesc;
477 resolveDesc.Width = extents.width;
478 resolveDesc.Height = extents.height;
479 resolveDesc.MipLevels = 1;
480 resolveDesc.ArraySize = 1;
481 resolveDesc.Format = textureHelper.getFormat();
482 resolveDesc.SampleDesc.Count = 1;
483 resolveDesc.SampleDesc.Quality = 0;
484 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
485 resolveDesc.BindFlags = 0;
486 resolveDesc.CPUAccessFlags = 0;
487 resolveDesc.MiscFlags = 0;
488
489 d3d11::Texture2D resolveTex;
490 ANGLE_TRY(
491 mRenderer->allocateResource(GetImplAs<Context11>(context), resolveDesc, &resolveTex));
492
493 deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(),
494 sourceSubResource, textureHelper.getFormat());
495
496 deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
497 destOffset.x, destOffset.y, destOffset.z,
498 resolveTex.get(), 0, &srcBox);
499 }
500 else
501 {
502 deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
503 destOffset.x, destOffset.y, destOffset.z,
504 textureHelper.get(), sourceSubResource, &srcBox);
505 }
506
507 mDirty = true;
508 return angle::Result::Continue;
509 }
510
getStagingTexture(const gl::Context * context,const TextureHelper11 ** outStagingTexture,unsigned int * outSubresourceIndex)511 angle::Result Image11::getStagingTexture(const gl::Context *context,
512 const TextureHelper11 **outStagingTexture,
513 unsigned int *outSubresourceIndex)
514 {
515 ANGLE_TRY(createStagingTexture(context));
516
517 *outStagingTexture = &mStagingTexture;
518 *outSubresourceIndex = mStagingSubresource;
519 return angle::Result::Continue;
520 }
521
releaseStagingTexture()522 void Image11::releaseStagingTexture()
523 {
524 mStagingTexture.reset();
525 mStagingTextureSubresourceVerifier.reset();
526 }
527
createStagingTexture(const gl::Context * context)528 angle::Result Image11::createStagingTexture(const gl::Context *context)
529 {
530 if (mStagingTexture.valid())
531 {
532 return angle::Result::Continue;
533 }
534
535 ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0);
536
537 const DXGI_FORMAT dxgiFormat = getDXGIFormat();
538 const auto &formatInfo =
539 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
540
541 int lodOffset = 1;
542 GLsizei width = mWidth;
543 GLsizei height = mHeight;
544
545 // adjust size if needed for compressed textures
546 d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
547
548 Context11 *context11 = GetImplAs<Context11>(context);
549
550 switch (mType)
551 {
552 case gl::TextureType::_3D:
553 {
554 D3D11_TEXTURE3D_DESC desc;
555 desc.Width = width;
556 desc.Height = height;
557 desc.Depth = mDepth;
558 desc.MipLevels = lodOffset + 1;
559 desc.Format = dxgiFormat;
560 desc.Usage = D3D11_USAGE_STAGING;
561 desc.BindFlags = 0;
562 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
563 desc.MiscFlags = 0;
564
565 if (formatInfo.dataInitializerFunction != nullptr)
566 {
567 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
568 ANGLE_TRY(d3d11::GenerateInitialTextureData(
569 context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
570 mDepth, lodOffset + 1, &initialData));
571
572 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
573 initialData.data(), &mStagingTexture));
574 }
575 else
576 {
577 ANGLE_TRY(
578 mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
579 }
580
581 mStagingTexture.setDebugName("Image11::StagingTexture3D");
582 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
583 mStagingTextureSubresourceVerifier.setDesc(desc);
584 }
585 break;
586
587 case gl::TextureType::_2D:
588 case gl::TextureType::_2DArray:
589 case gl::TextureType::CubeMap:
590 {
591 D3D11_TEXTURE2D_DESC desc;
592 desc.Width = width;
593 desc.Height = height;
594 desc.MipLevels = lodOffset + 1;
595 desc.ArraySize = 1;
596 desc.Format = dxgiFormat;
597 desc.SampleDesc.Count = 1;
598 desc.SampleDesc.Quality = 0;
599 desc.Usage = D3D11_USAGE_STAGING;
600 desc.BindFlags = 0;
601 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
602 desc.MiscFlags = 0;
603
604 if (formatInfo.dataInitializerFunction != nullptr)
605 {
606 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
607 ANGLE_TRY(d3d11::GenerateInitialTextureData(
608 context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
609 1, lodOffset + 1, &initialData));
610
611 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
612 initialData.data(), &mStagingTexture));
613 }
614 else
615 {
616 ANGLE_TRY(
617 mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
618 }
619
620 mStagingTexture.setDebugName("Image11::StagingTexture2D");
621 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
622 mStagingTextureSubresourceVerifier.setDesc(desc);
623 }
624 break;
625
626 default:
627 UNREACHABLE();
628 }
629
630 mDirty = false;
631 return angle::Result::Continue;
632 }
633
map(const gl::Context * context,D3D11_MAP mapType,D3D11_MAPPED_SUBRESOURCE * map)634 angle::Result Image11::map(const gl::Context *context,
635 D3D11_MAP mapType,
636 D3D11_MAPPED_SUBRESOURCE *map)
637 {
638 // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
639 ANGLE_TRY(recoverFromAssociatedStorage(context));
640
641 const TextureHelper11 *stagingTexture = nullptr;
642 unsigned int subresourceIndex = 0;
643 ANGLE_TRY(getStagingTexture(context, &stagingTexture, &subresourceIndex));
644
645 ASSERT(stagingTexture && stagingTexture->valid());
646
647 ANGLE_TRY(
648 mRenderer->mapResource(context, stagingTexture->get(), subresourceIndex, mapType, 0, map));
649
650 if (!mStagingTextureSubresourceVerifier.wrap(mapType, map))
651 {
652 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
653 deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
654 Context11 *context11 = GetImplAs<Context11>(context);
655 context11->handleError(GL_OUT_OF_MEMORY,
656 "Failed to allocate staging texture mapping verifier buffer.",
657 __FILE__, ANGLE_FUNCTION, __LINE__);
658 return angle::Result::Stop;
659 }
660
661 mDirty = true;
662
663 return angle::Result::Continue;
664 }
665
unmap()666 void Image11::unmap()
667 {
668 if (mStagingTexture.valid())
669 {
670 mStagingTextureSubresourceVerifier.unwrap();
671 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
672 deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
673 }
674 }
675
676 } // namespace rx
677