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