1 //
2 // Copyright 2014 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 // TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
9 #include "libANGLE/renderer/d3d/TextureD3D.h"
10
11 #include "common/mathutil.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Buffer.h"
14 #include "libANGLE/Config.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Framebuffer.h"
17 #include "libANGLE/Image.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/Texture.h"
20 #include "libANGLE/formatutils.h"
21 #include "libANGLE/renderer/BufferImpl.h"
22 #include "libANGLE/renderer/d3d/BufferD3D.h"
23 #include "libANGLE/renderer/d3d/ContextD3D.h"
24 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
25 #include "libANGLE/renderer/d3d/ImageD3D.h"
26 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
27 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
28 #include "libANGLE/renderer/d3d/TextureStorage.h"
29
30 namespace rx
31 {
32
33 namespace
34 {
35
GetUnpackPointer(const gl::Context * context,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,ptrdiff_t layerOffset,const uint8_t ** pointerOut)36 angle::Result GetUnpackPointer(const gl::Context *context,
37 const gl::PixelUnpackState &unpack,
38 gl::Buffer *unpackBuffer,
39 const uint8_t *pixels,
40 ptrdiff_t layerOffset,
41 const uint8_t **pointerOut)
42 {
43 if (unpackBuffer)
44 {
45 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not
46 // supported
47 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
48
49 // TODO: this is the only place outside of renderer that asks for a buffers raw data.
50 // This functionality should be moved into renderer and the getData method of BufferImpl
51 // removed.
52 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(unpackBuffer);
53 ASSERT(bufferD3D);
54 const uint8_t *bufferData = nullptr;
55 ANGLE_TRY(bufferD3D->getData(context, &bufferData));
56 *pointerOut = bufferData + offset;
57 }
58 else
59 {
60 *pointerOut = pixels;
61 }
62
63 // Offset the pointer for 2D array layer (if it's valid)
64 if (*pointerOut != nullptr)
65 {
66 *pointerOut += layerOffset;
67 }
68
69 return angle::Result::Continue;
70 }
71
IsRenderTargetUsage(GLenum usage)72 bool IsRenderTargetUsage(GLenum usage)
73 {
74 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
75 }
76 } // namespace
77
TextureD3D(const gl::TextureState & state,RendererD3D * renderer)78 TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer)
79 : TextureImpl(state),
80 mRenderer(renderer),
81 mDirtyImages(true),
82 mImmutable(false),
83 mTexStorage(nullptr),
84 mTexStorageObserverBinding(this, kTextureStorageObserverMessageIndex),
85 mBaseLevel(0)
86 {}
87
~TextureD3D()88 TextureD3D::~TextureD3D()
89 {
90 ASSERT(!mTexStorage);
91 }
92
getNativeTexture(const gl::Context * context,TextureStorage ** outStorage)93 angle::Result TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage)
94 {
95 // ensure the underlying texture is created
96 ANGLE_TRY(initializeStorage(context, false));
97
98 if (mTexStorage)
99 {
100 ANGLE_TRY(updateStorage(context));
101 }
102
103 ASSERT(outStorage);
104
105 *outStorage = mTexStorage;
106 return angle::Result::Continue;
107 }
108
getImageAndSyncFromStorage(const gl::Context * context,const gl::ImageIndex & index,ImageD3D ** outImage)109 angle::Result TextureD3D::getImageAndSyncFromStorage(const gl::Context *context,
110 const gl::ImageIndex &index,
111 ImageD3D **outImage)
112 {
113 ImageD3D *image = getImage(index);
114 if (mTexStorage && mTexStorage->isRenderTarget())
115 {
116 ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage));
117 mDirtyImages = true;
118 }
119 *outImage = image;
120 return angle::Result::Continue;
121 }
122
getLevelZeroWidth() const123 GLint TextureD3D::getLevelZeroWidth() const
124 {
125 ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelWidth())) > getBaseLevel());
126 return getBaseLevelWidth() << mBaseLevel;
127 }
128
getLevelZeroHeight() const129 GLint TextureD3D::getLevelZeroHeight() const
130 {
131 ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelHeight())) > getBaseLevel());
132 return getBaseLevelHeight() << mBaseLevel;
133 }
134
getLevelZeroDepth() const135 GLint TextureD3D::getLevelZeroDepth() const
136 {
137 return getBaseLevelDepth();
138 }
139
getBaseLevelWidth() const140 GLint TextureD3D::getBaseLevelWidth() const
141 {
142 const ImageD3D *baseImage = getBaseLevelImage();
143 return (baseImage ? baseImage->getWidth() : 0);
144 }
145
getBaseLevelHeight() const146 GLint TextureD3D::getBaseLevelHeight() const
147 {
148 const ImageD3D *baseImage = getBaseLevelImage();
149 return (baseImage ? baseImage->getHeight() : 0);
150 }
151
getBaseLevelDepth() const152 GLint TextureD3D::getBaseLevelDepth() const
153 {
154 const ImageD3D *baseImage = getBaseLevelImage();
155 return (baseImage ? baseImage->getDepth() : 0);
156 }
157
158 // Note: "base level image" is loosely defined to be any image from the base level,
159 // where in the base of 2D array textures and cube maps there are several. Don't use
160 // the base level image for anything except querying texture format and size.
getBaseLevelInternalFormat() const161 GLenum TextureD3D::getBaseLevelInternalFormat() const
162 {
163 const ImageD3D *baseImage = getBaseLevelImage();
164 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
165 }
166
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)167 angle::Result TextureD3D::setStorage(const gl::Context *context,
168 gl::TextureType type,
169 size_t levels,
170 GLenum internalFormat,
171 const gl::Extents &size)
172 {
173 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
174 return angle::Result::Continue;
175 }
176
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)177 angle::Result TextureD3D::setStorageMultisample(const gl::Context *context,
178 gl::TextureType type,
179 GLsizei samples,
180 GLint internalformat,
181 const gl::Extents &size,
182 bool fixedSampleLocations)
183 {
184 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
185 return angle::Result::Continue;
186 }
187
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)188 angle::Result TextureD3D::setStorageExternalMemory(const gl::Context *context,
189 gl::TextureType type,
190 size_t levels,
191 GLenum internalFormat,
192 const gl::Extents &size,
193 gl::MemoryObject *memoryObject,
194 GLuint64 offset,
195 GLbitfield createFlags,
196 GLbitfield usageFlags,
197 const void *imageCreateInfoPNext)
198 {
199 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
200 return angle::Result::Continue;
201 }
202
shouldUseSetData(const ImageD3D * image) const203 bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
204 {
205 if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled)
206 {
207 return false;
208 }
209
210 if (image->isDirty())
211 {
212 return false;
213 }
214
215 gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat());
216
217 // We can only handle full updates for depth-stencil textures, so to avoid complications
218 // disable them entirely.
219 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
220 {
221 return false;
222 }
223
224 // TODO(jmadill): Handle compressed internal formats
225 return (mTexStorage && !internalFormat.compressed);
226 }
227
setImageImpl(const gl::Context * context,const gl::ImageIndex & index,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,ptrdiff_t layerOffset)228 angle::Result TextureD3D::setImageImpl(const gl::Context *context,
229 const gl::ImageIndex &index,
230 GLenum type,
231 const gl::PixelUnpackState &unpack,
232 gl::Buffer *unpackBuffer,
233 const uint8_t *pixels,
234 ptrdiff_t layerOffset)
235 {
236 ImageD3D *image = getImage(index);
237 ASSERT(image);
238
239 // No-op
240 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
241 {
242 return angle::Result::Continue;
243 }
244
245 // We no longer need the "GLenum format" parameter to TexImage to determine what data format
246 // "pixels" contains. From our image internal format we know how many channels to expect, and
247 // "type" gives the format of pixel's components.
248 const uint8_t *pixelData = nullptr;
249 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
250
251 if (pixelData != nullptr)
252 {
253 if (shouldUseSetData(image))
254 {
255 ANGLE_TRY(
256 mTexStorage->setData(context, index, image, nullptr, type, unpack, pixelData));
257 }
258 else
259 {
260 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(),
261 image->getDepth());
262 ANGLE_TRY(image->loadData(context, fullImageArea, unpack, type, pixelData,
263 index.usesTex3D()));
264 }
265
266 mDirtyImages = true;
267 }
268
269 return angle::Result::Continue;
270 }
271
subImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,ptrdiff_t layerOffset)272 angle::Result TextureD3D::subImage(const gl::Context *context,
273 const gl::ImageIndex &index,
274 const gl::Box &area,
275 GLenum format,
276 GLenum type,
277 const gl::PixelUnpackState &unpack,
278 gl::Buffer *unpackBuffer,
279 const uint8_t *pixels,
280 ptrdiff_t layerOffset)
281 {
282 // CPU readback & copy where direct GPU copy is not supported
283 const uint8_t *pixelData = nullptr;
284 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
285
286 if (pixelData != nullptr)
287 {
288 ImageD3D *image = getImage(index);
289 ASSERT(image);
290
291 if (shouldUseSetData(image))
292 {
293 return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData);
294 }
295
296 ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.usesTex3D()));
297 ANGLE_TRY(commitRegion(context, index, area));
298 mDirtyImages = true;
299 }
300
301 return angle::Result::Continue;
302 }
303
setCompressedImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::PixelUnpackState & unpack,const uint8_t * pixels,ptrdiff_t layerOffset)304 angle::Result TextureD3D::setCompressedImageImpl(const gl::Context *context,
305 const gl::ImageIndex &index,
306 const gl::PixelUnpackState &unpack,
307 const uint8_t *pixels,
308 ptrdiff_t layerOffset)
309 {
310 ImageD3D *image = getImage(index);
311 ASSERT(image);
312
313 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
314 {
315 return angle::Result::Continue;
316 }
317
318 // We no longer need the "GLenum format" parameter to TexImage to determine what data format
319 // "pixels" contains. From our image internal format we know how many channels to expect, and
320 // "type" gives the format of pixel's components.
321 const uint8_t *pixelData = nullptr;
322 gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
323 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
324
325 if (pixelData != nullptr)
326 {
327 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
328 ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData));
329
330 mDirtyImages = true;
331 }
332
333 return angle::Result::Continue;
334 }
335
subImageCompressed(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,const uint8_t * pixels,ptrdiff_t layerOffset)336 angle::Result TextureD3D::subImageCompressed(const gl::Context *context,
337 const gl::ImageIndex &index,
338 const gl::Box &area,
339 GLenum format,
340 const gl::PixelUnpackState &unpack,
341 const uint8_t *pixels,
342 ptrdiff_t layerOffset)
343 {
344 const uint8_t *pixelData = nullptr;
345 gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
346 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
347
348 if (pixelData != nullptr)
349 {
350 ImageD3D *image = getImage(index);
351 ASSERT(image);
352
353 ANGLE_TRY(image->loadCompressedData(context, area, pixelData));
354
355 mDirtyImages = true;
356 }
357
358 return angle::Result::Continue;
359 }
360
isFastUnpackable(const gl::Buffer * unpackBuffer,const gl::PixelUnpackState & unpack,GLenum sizedInternalFormat)361 bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer,
362 const gl::PixelUnpackState &unpack,
363 GLenum sizedInternalFormat)
364 {
365 return unpackBuffer != nullptr && unpack.skipRows == 0 && unpack.skipPixels == 0 &&
366 unpack.imageHeight == 0 && unpack.skipImages == 0 &&
367 mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
368 }
369
fastUnpackPixels(const gl::Context * context,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,const gl::Box & destArea,GLenum sizedInternalFormat,GLenum type,RenderTargetD3D * destRenderTarget)370 angle::Result TextureD3D::fastUnpackPixels(const gl::Context *context,
371 const gl::PixelUnpackState &unpack,
372 gl::Buffer *unpackBuffer,
373 const uint8_t *pixels,
374 const gl::Box &destArea,
375 GLenum sizedInternalFormat,
376 GLenum type,
377 RenderTargetD3D *destRenderTarget)
378 {
379 bool check = (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 ||
380 unpack.skipImages != 0);
381 ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
382 "Unimplemented pixel store parameters in fastUnpackPixels", GL_INVALID_OPERATION);
383
384 // No-op
385 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
386 {
387 return angle::Result::Continue;
388 }
389
390 // In order to perform the fast copy through the shader, we must have the right format, and be
391 // able to create a render target.
392 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
393
394 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
395
396 ANGLE_TRY(mRenderer->fastCopyBufferToTexture(
397 context, unpack, unpackBuffer, static_cast<unsigned int>(offset), destRenderTarget,
398 sizedInternalFormat, type, destArea));
399
400 return angle::Result::Continue;
401 }
402
creationLevels(GLsizei width,GLsizei height,GLsizei depth) const403 GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
404 {
405 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) ||
406 mRenderer->getNativeExtensions().textureNpotOES)
407 {
408 // Maximum number of levels
409 return gl::log2(std::max(std::max(width, height), depth)) + 1;
410 }
411 else
412 {
413 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
414 return 1;
415 }
416 }
417
getStorage()418 TextureStorage *TextureD3D::getStorage()
419 {
420 ASSERT(mTexStorage);
421 return mTexStorage;
422 }
423
getBaseLevelImage() const424 ImageD3D *TextureD3D::getBaseLevelImage() const
425 {
426 if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
427 {
428 return nullptr;
429 }
430 return getImage(getImageIndex(mBaseLevel, 0));
431 }
432
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)433 angle::Result TextureD3D::setImageExternal(const gl::Context *context,
434 gl::TextureType type,
435 egl::Stream *stream,
436 const egl::Stream::GLTextureDescription &desc)
437 {
438 // Only external images can accept external textures
439 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
440 return angle::Result::Continue;
441 }
442
generateMipmap(const gl::Context * context)443 angle::Result TextureD3D::generateMipmap(const gl::Context *context)
444 {
445 const GLuint baseLevel = mState.getEffectiveBaseLevel();
446 const GLuint maxLevel = mState.getMipmapMaxLevel();
447 ASSERT(maxLevel > baseLevel); // Should be checked before calling this.
448
449 if (mTexStorage && mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
450 {
451 // Switch to using the mipmapped texture.
452 TextureStorage *textureStorageEXT = nullptr;
453 ANGLE_TRY(getNativeTexture(context, &textureStorageEXT));
454 ANGLE_TRY(textureStorageEXT->useLevelZeroWorkaroundTexture(context, false));
455 }
456
457 // Set up proper mipmap chain in our Image array.
458 ANGLE_TRY(initMipmapImages(context));
459
460 if (mTexStorage && mTexStorage->supportsNativeMipmapFunction())
461 {
462 ANGLE_TRY(updateStorage(context));
463
464 // Generate the mipmap chain using the ad-hoc DirectX function.
465 ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState));
466 }
467 else
468 {
469 // Generate the mipmap chain, one level at a time.
470 ANGLE_TRY(generateMipmapUsingImages(context, maxLevel));
471 }
472
473 return angle::Result::Continue;
474 }
475
generateMipmapUsingImages(const gl::Context * context,const GLuint maxLevel)476 angle::Result TextureD3D::generateMipmapUsingImages(const gl::Context *context,
477 const GLuint maxLevel)
478 {
479 // We know that all layers have the same dimension, for the texture to be complete
480 GLint layerCount = static_cast<GLint>(getLayerCount(mBaseLevel));
481
482 if (mTexStorage && !mTexStorage->isRenderTarget() &&
483 canCreateRenderTargetForImage(getImageIndex(mBaseLevel, 0)) &&
484 mRenderer->getRendererClass() == RENDERER_D3D11)
485 {
486 if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled)
487 {
488 ANGLE_TRY(updateStorage(context));
489 }
490 ANGLE_TRY(ensureRenderTarget(context));
491 }
492 else if (mRenderer->getFeatures().setDataFasterThanImageUpload.enabled && mTexStorage)
493 {
494 // When making mipmaps with the setData workaround enabled, the texture storage has
495 // the image data already. For non-render-target storage, we have to pull it out into
496 // an image layer.
497 if (!mTexStorage->isRenderTarget())
498 {
499 // Copy from the storage mip 0 to Image mip 0
500 for (GLint layer = 0; layer < layerCount; ++layer)
501 {
502 gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer);
503
504 ImageD3D *image = getImage(srcIndex);
505 ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage));
506 }
507 }
508 else
509 {
510 ANGLE_TRY(updateStorage(context));
511 }
512 }
513
514 // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to
515 // zeroMaxLodWorkaround. The restriction is because Feature Level 9_3 can't create SRVs on
516 // individual levels of the texture. As a result, even if the storage is a rendertarget, we
517 // can't use the GPU to generate the mipmaps without further work. The D3D9 renderer works
518 // around this by copying each level of the texture into its own single-layer GPU texture (in
519 // Blit9::boxFilter). Feature Level 9_3 could do something similar, or it could continue to use
520 // CPU-side mipmap generation, or something else.
521 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() &&
522 !(mRenderer->getFeatures().zeroMaxLodWorkaround.enabled));
523
524 for (GLint layer = 0; layer < layerCount; ++layer)
525 {
526 for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip)
527 {
528 ASSERT(getLayerCount(mip) == layerCount);
529
530 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
531 gl::ImageIndex destIndex = getImageIndex(mip, layer);
532
533 if (renderableStorage)
534 {
535 // GPU-side mipmapping
536 ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex));
537 }
538 else
539 {
540 // CPU-side mipmapping
541 ANGLE_TRY(
542 mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex)));
543 }
544 }
545 }
546
547 mDirtyImages = !renderableStorage;
548
549 if (mTexStorage && mDirtyImages)
550 {
551 ANGLE_TRY(updateStorage(context));
552 }
553
554 return angle::Result::Continue;
555 }
556
isBaseImageZeroSize() const557 bool TextureD3D::isBaseImageZeroSize() const
558 {
559 ImageD3D *baseImage = getBaseLevelImage();
560
561 if (!baseImage || baseImage->getWidth() <= 0 || baseImage->getHeight() <= 0)
562 {
563 return true;
564 }
565
566 if (baseImage->getType() == gl::TextureType::_3D && baseImage->getDepth() <= 0)
567 {
568 return true;
569 }
570
571 if (baseImage->getType() == gl::TextureType::_2DArray && getLayerCount(getBaseLevel()) <= 0)
572 {
573 return true;
574 }
575
576 return false;
577 }
578
ensureRenderTarget(const gl::Context * context)579 angle::Result TextureD3D::ensureRenderTarget(const gl::Context *context)
580 {
581 ANGLE_TRY(initializeStorage(context, true));
582
583 // initializeStorage can fail with NoError if the texture is not complete. This is not
584 // an error for incomplete sampling, but it is a big problem for rendering.
585 if (!mTexStorage)
586 {
587 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
588 return angle::Result::Stop;
589 }
590
591 if (!isBaseImageZeroSize())
592 {
593 ASSERT(mTexStorage);
594 if (!mTexStorage->isRenderTarget())
595 {
596 TexStoragePointer newRenderTargetStorage(context);
597 ANGLE_TRY(createCompleteStorage(true, &newRenderTargetStorage));
598
599 ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get()));
600 ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get()));
601 newRenderTargetStorage.release();
602 // If this texture is used in compute shader, we should invalidate this texture so that
603 // the UAV/SRV is rebound again with this new texture storage in next dispatch call.
604 mTexStorage->invalidateTextures();
605 }
606 }
607
608 return angle::Result::Continue;
609 }
610
canCreateRenderTargetForImage(const gl::ImageIndex & index) const611 bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
612 {
613 if (index.getType() == gl::TextureType::_2DMultisample ||
614 index.getType() == gl::TextureType::_2DMultisampleArray)
615 {
616 ASSERT(index.getType() != gl::TextureType::_2DMultisampleArray || index.hasLayer());
617 return true;
618 }
619
620 ImageD3D *image = getImage(index);
621 ASSERT(image);
622 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
623 return (image->isRenderableFormat() && levelsComplete);
624 }
625
commitRegion(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & region)626 angle::Result TextureD3D::commitRegion(const gl::Context *context,
627 const gl::ImageIndex &index,
628 const gl::Box ®ion)
629 {
630 if (mTexStorage)
631 {
632 ASSERT(isValidIndex(index));
633 ImageD3D *image = getImage(index);
634 ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region));
635 image->markClean();
636 }
637
638 return angle::Result::Continue;
639 }
640
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)641 angle::Result TextureD3D::getAttachmentRenderTarget(const gl::Context *context,
642 GLenum binding,
643 const gl::ImageIndex &imageIndex,
644 GLsizei samples,
645 FramebufferAttachmentRenderTarget **rtOut)
646 {
647 RenderTargetD3D *rtD3D = nullptr;
648 ANGLE_TRY(getRenderTarget(context, imageIndex, samples, &rtD3D));
649 *rtOut = static_cast<FramebufferAttachmentRenderTarget *>(rtD3D);
650 return angle::Result::Continue;
651 }
652
setBaseLevel(const gl::Context * context,GLuint baseLevel)653 angle::Result TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel)
654 {
655 const int oldStorageWidth = std::max(1, getLevelZeroWidth());
656 const int oldStorageHeight = std::max(1, getLevelZeroHeight());
657 const int oldStorageDepth = std::max(1, getLevelZeroDepth());
658 const int oldStorageFormat = getBaseLevelInternalFormat();
659 mBaseLevel = baseLevel;
660
661 // When the base level changes, the texture storage might not be valid anymore, since it could
662 // have been created based on the dimensions of the previous specified level range.
663 const int newStorageWidth = std::max(1, getLevelZeroWidth());
664 const int newStorageHeight = std::max(1, getLevelZeroHeight());
665 const int newStorageDepth = std::max(1, getLevelZeroDepth());
666 const int newStorageFormat = getBaseLevelInternalFormat();
667 if (mTexStorage &&
668 (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight ||
669 newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat))
670 {
671 markAllImagesDirty();
672
673 // Iterate over all images, and backup the content if it's been used as a render target. The
674 // D3D11 backend can automatically restore images on storage destroy, but it only works for
675 // images that have been associated with the texture storage before, which is insufficient
676 // here.
677 if (mTexStorage->isRenderTarget())
678 {
679 gl::ImageIndexIterator iterator = imageIterator();
680 while (iterator.hasNext())
681 {
682 const gl::ImageIndex index = iterator.next();
683 const GLsizei samples = getRenderToTextureSamples();
684 RenderTargetD3D *renderTarget = nullptr;
685 ANGLE_TRY(mTexStorage->findRenderTarget(context, index, samples, &renderTarget));
686 if (renderTarget)
687 {
688 ANGLE_TRY(getImage(index)->copyFromTexStorage(context, index, mTexStorage));
689 }
690 }
691 }
692
693 ANGLE_TRY(releaseTexStorage(context));
694 }
695
696 return angle::Result::Continue;
697 }
698
onLabelUpdate()699 void TextureD3D::onLabelUpdate()
700 {
701 if (mTexStorage)
702 {
703 mTexStorage->onLabelUpdate();
704 }
705 }
706
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)707 angle::Result TextureD3D::syncState(const gl::Context *context,
708 const gl::Texture::DirtyBits &dirtyBits,
709 gl::Command source)
710 {
711 // This could be improved using dirty bits.
712 return angle::Result::Continue;
713 }
714
releaseTexStorage(const gl::Context * context)715 angle::Result TextureD3D::releaseTexStorage(const gl::Context *context)
716 {
717 if (!mTexStorage)
718 {
719 return angle::Result::Continue;
720 }
721
722 onStateChange(angle::SubjectMessage::StorageReleased);
723
724 auto err = mTexStorage->onDestroy(context);
725 SafeDelete(mTexStorage);
726 return err;
727 }
728
onDestroy(const gl::Context * context)729 void TextureD3D::onDestroy(const gl::Context *context)
730 {
731 (void)releaseTexStorage(context);
732 }
733
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)734 angle::Result TextureD3D::initializeContents(const gl::Context *context,
735 const gl::ImageIndex &imageIndex)
736 {
737 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
738 gl::ImageIndex index = imageIndex;
739
740 // Special case for D3D11 3D textures. We can't create render targets for individual layers of a
741 // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we
742 // would lose existing data.
743 if (index.getType() == gl::TextureType::_3D)
744 {
745 index = gl::ImageIndex::Make3D(index.getLevelIndex(), gl::ImageIndex::kEntireLevel);
746 }
747 else if (index.getType() == gl::TextureType::_2DArray && !index.hasLayer())
748 {
749 std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts;
750
751 GLint levelIndex = index.getLevelIndex();
752 tempLayerCounts[levelIndex] = getLayerCount(levelIndex);
753 gl::ImageIndexIterator iterator =
754 gl::ImageIndexIterator::Make2DArray(levelIndex, levelIndex + 1, tempLayerCounts.data());
755 while (iterator.hasNext())
756 {
757 ANGLE_TRY(initializeContents(context, iterator.next()));
758 }
759 return angle::Result::Continue;
760 }
761 else if (index.getType() == gl::TextureType::_2DMultisampleArray && !index.hasLayer())
762 {
763 std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts;
764
765 ASSERT(index.getLevelIndex() == 0);
766 tempLayerCounts[0] = getLayerCount(0);
767 gl::ImageIndexIterator iterator =
768 gl::ImageIndexIterator::Make2DMultisampleArray(tempLayerCounts.data());
769 while (iterator.hasNext())
770 {
771 ANGLE_TRY(initializeContents(context, iterator.next()));
772 }
773 return angle::Result::Continue;
774 }
775
776 // Force image clean.
777 ImageD3D *image = getImage(index);
778 if (image)
779 {
780 image->markClean();
781 }
782
783 // Fast path: can use a render target clear.
784 // We don't use the fast path with the zero max lod workaround because it would introduce a race
785 // between the rendertarget and the staging images.
786 const angle::FeaturesD3D &features = mRenderer->getFeatures();
787 bool shouldUseClear = (image == nullptr);
788 if (canCreateRenderTargetForImage(index) && !features.zeroMaxLodWorkaround.enabled &&
789 (shouldUseClear || features.allowClearForRobustResourceInit.enabled))
790 {
791 ANGLE_TRY(ensureRenderTarget(context));
792 ASSERT(mTexStorage);
793 RenderTargetD3D *renderTarget = nullptr;
794 ANGLE_TRY(mTexStorage->getRenderTarget(context, index, 0, &renderTarget));
795 ANGLE_TRY(mRenderer->initRenderTarget(context, renderTarget));
796
797 // Force image clean again, the texture storage may have been re-created and the image used.
798 if (image)
799 {
800 image->markClean();
801 }
802
803 return angle::Result::Continue;
804 }
805
806 ASSERT(image != nullptr);
807
808 // Slow path: non-renderable texture or the texture levels aren't set up.
809 const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat());
810
811 GLuint imageBytes = 0;
812 ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeRowPitch(formatInfo.type, image->getWidth(),
813 1, 0, &imageBytes));
814 imageBytes *= image->getHeight() * image->getDepth();
815
816 gl::PixelUnpackState zeroDataUnpackState;
817 zeroDataUnpackState.alignment = 1;
818
819 angle::MemoryBuffer *zeroBuffer = nullptr;
820 ANGLE_CHECK_GL_ALLOC(contextD3D, context->getZeroFilledBuffer(imageBytes, &zeroBuffer));
821
822 if (shouldUseSetData(image))
823 {
824 ANGLE_TRY(mTexStorage->setData(context, index, image, nullptr, formatInfo.type,
825 zeroDataUnpackState, zeroBuffer->data()));
826 }
827 else
828 {
829 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
830 ANGLE_TRY(image->loadData(context, fullImageArea, zeroDataUnpackState, formatInfo.type,
831 zeroBuffer->data(), false));
832
833 // Force an update to the tex storage so we avoid problems with subImage and dirty regions.
834 if (mTexStorage)
835 {
836 ANGLE_TRY(commitRegion(context, index, fullImageArea));
837 image->markClean();
838 }
839 else
840 {
841 mDirtyImages = true;
842 }
843 }
844 return angle::Result::Continue;
845 }
846
getRenderToTextureSamples()847 GLsizei TextureD3D::getRenderToTextureSamples()
848 {
849 if (mTexStorage)
850 {
851 return mTexStorage->getRenderToTextureSamples();
852 }
853 return 0;
854 }
855
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)856 void TextureD3D::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
857 {
858 onStateChange(message);
859 }
860
TextureD3D_2D(const gl::TextureState & state,RendererD3D * renderer)861 TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer)
862 : TextureD3D(state, renderer)
863 {
864 mEGLImageTarget = false;
865 for (auto &image : mImageArray)
866 {
867 image.reset(renderer->createImage());
868 }
869 }
870
onDestroy(const gl::Context * context)871 void TextureD3D_2D::onDestroy(const gl::Context *context)
872 {
873 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
874 // for some of their data. If TextureStorage is deleted before the Images, then their data will
875 // be wastefully copied back from the GPU before we delete the Images.
876 for (auto &image : mImageArray)
877 {
878 image.reset();
879 }
880 return TextureD3D::onDestroy(context);
881 }
882
~TextureD3D_2D()883 TextureD3D_2D::~TextureD3D_2D() {}
884
getImage(int level,int layer) const885 ImageD3D *TextureD3D_2D::getImage(int level, int layer) const
886 {
887 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
888 ASSERT(layer == 0);
889 return mImageArray[level].get();
890 }
891
getImage(const gl::ImageIndex & index) const892 ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
893 {
894 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
895 ASSERT(!index.hasLayer());
896 ASSERT(index.getType() == gl::TextureType::_2D ||
897 index.getType() == gl::TextureType::VideoImage);
898 return mImageArray[index.getLevelIndex()].get();
899 }
900
getLayerCount(int level) const901 GLsizei TextureD3D_2D::getLayerCount(int level) const
902 {
903 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
904 return 1;
905 }
906
getWidth(GLint level) const907 GLsizei TextureD3D_2D::getWidth(GLint level) const
908 {
909 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
910 return mImageArray[level]->getWidth();
911 else
912 return 0;
913 }
914
getHeight(GLint level) const915 GLsizei TextureD3D_2D::getHeight(GLint level) const
916 {
917 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
918 return mImageArray[level]->getHeight();
919 else
920 return 0;
921 }
922
getInternalFormat(GLint level) const923 GLenum TextureD3D_2D::getInternalFormat(GLint level) const
924 {
925 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
926 return mImageArray[level]->getInternalFormat();
927 else
928 return GL_NONE;
929 }
930
isDepth(GLint level) const931 bool TextureD3D_2D::isDepth(GLint level) const
932 {
933 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
934 }
935
isSRGB(GLint level) const936 bool TextureD3D_2D::isSRGB(GLint level) const
937 {
938 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
939 }
940
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)941 angle::Result TextureD3D_2D::setImage(const gl::Context *context,
942 const gl::ImageIndex &index,
943 GLenum internalFormat,
944 const gl::Extents &size,
945 GLenum format,
946 GLenum type,
947 const gl::PixelUnpackState &unpack,
948 gl::Buffer *unpackBuffer,
949 const uint8_t *pixels)
950 {
951 ASSERT((index.getTarget() == gl::TextureTarget::_2D ||
952 index.getTarget() == gl::TextureTarget::VideoImage) &&
953 size.depth == 1);
954
955 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
956
957 bool fastUnpacked = false;
958
959 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
960 size, false));
961
962 // Attempt a fast gpu copy of the pixel data to the surface
963 if (mTexStorage)
964 {
965 ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex()));
966 }
967 if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) &&
968 isLevelComplete(index.getLevelIndex()))
969 {
970 // Will try to create RT storage if it does not exist
971 RenderTargetD3D *destRenderTarget = nullptr;
972 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
973
974 gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
975 1);
976
977 ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
978 internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
979
980 // Ensure we don't overwrite our newly initialized data
981 mImageArray[index.getLevelIndex()]->markClean();
982
983 fastUnpacked = true;
984 }
985
986 if (!fastUnpacked)
987 {
988 ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
989 }
990
991 return angle::Result::Continue;
992 }
993
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)994 angle::Result TextureD3D_2D::setSubImage(const gl::Context *context,
995 const gl::ImageIndex &index,
996 const gl::Box &area,
997 GLenum format,
998 GLenum type,
999 const gl::PixelUnpackState &unpack,
1000 gl::Buffer *unpackBuffer,
1001 const uint8_t *pixels)
1002 {
1003 ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0);
1004
1005 GLenum mipFormat = getInternalFormat(index.getLevelIndex());
1006 if (mTexStorage)
1007 {
1008 ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex()));
1009 }
1010 if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex()))
1011 {
1012 RenderTargetD3D *renderTarget = nullptr;
1013 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &renderTarget));
1014 ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
1015
1016 return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
1017 renderTarget);
1018 }
1019 else
1020 {
1021 return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
1022 pixels, 0);
1023 }
1024 }
1025
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1026 angle::Result TextureD3D_2D::setCompressedImage(const gl::Context *context,
1027 const gl::ImageIndex &index,
1028 GLenum internalFormat,
1029 const gl::Extents &size,
1030 const gl::PixelUnpackState &unpack,
1031 size_t imageSize,
1032 const uint8_t *pixels)
1033 {
1034 ASSERT(index.getTarget() == gl::TextureTarget::_2D && size.depth == 1);
1035
1036 // compressed formats don't have separate sized internal formats-- we can just use the
1037 // compressed format directly
1038 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
1039
1040 return setCompressedImageImpl(context, index, unpack, pixels, 0);
1041 }
1042
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1043 angle::Result TextureD3D_2D::setCompressedSubImage(const gl::Context *context,
1044 const gl::ImageIndex &index,
1045 const gl::Box &area,
1046 GLenum format,
1047 const gl::PixelUnpackState &unpack,
1048 size_t imageSize,
1049 const uint8_t *pixels)
1050 {
1051 ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0);
1052 ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
1053
1054 return commitRegion(context, index, area);
1055 }
1056
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)1057 angle::Result TextureD3D_2D::copyImage(const gl::Context *context,
1058 const gl::ImageIndex &index,
1059 const gl::Rectangle &sourceArea,
1060 GLenum internalFormat,
1061 gl::Framebuffer *source)
1062 {
1063 ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1064
1065 const gl::InternalFormat &internalFormatInfo =
1066 gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1067 gl::Extents sourceExtents(sourceArea.width, sourceArea.height, 1);
1068 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
1069 sourceExtents, false));
1070
1071 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1072
1073 // Does the read area extend beyond the framebuffer?
1074 bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
1075 sourceArea.x + sourceArea.width > fbSize.width ||
1076 sourceArea.y + sourceArea.height > fbSize.height;
1077
1078 // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
1079 // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
1080 // Same thing for robust resource init.
1081 if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled()))
1082 {
1083 ANGLE_TRY(initializeContents(context, index));
1084 }
1085
1086 gl::Rectangle clippedArea;
1087 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1088 {
1089 // Empty source area, nothing to do.
1090 return angle::Result::Continue;
1091 }
1092
1093 gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
1094
1095 // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1096 // framebuffer in shaders, so we should use the non-rendering copy path.
1097 if (!canCreateRenderTargetForImage(index) ||
1098 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1099 {
1100 ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, destOffset,
1101 clippedArea, source));
1102 mDirtyImages = true;
1103 }
1104 else
1105 {
1106 ANGLE_TRY(ensureRenderTarget(context));
1107
1108 if (clippedArea.width != 0 && clippedArea.height != 0 &&
1109 isValidLevel(index.getLevelIndex()))
1110 {
1111 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1112 ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea, internalFormat,
1113 destOffset, mTexStorage, index.getLevelIndex()));
1114 }
1115 }
1116
1117 return angle::Result::Continue;
1118 }
1119
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1120 angle::Result TextureD3D_2D::copySubImage(const gl::Context *context,
1121 const gl::ImageIndex &index,
1122 const gl::Offset &destOffset,
1123 const gl::Rectangle &sourceArea,
1124 gl::Framebuffer *source)
1125 {
1126 ASSERT(index.getTarget() == gl::TextureTarget::_2D && destOffset.z == 0);
1127
1128 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1129 gl::Rectangle clippedArea;
1130 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1131 {
1132 return angle::Result::Continue;
1133 }
1134 const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1135 destOffset.y + clippedArea.y - sourceArea.y, 0);
1136
1137 // can only make our texture storage to a render target if level 0 is defined (with a width &
1138 // height) and the current level we're copying to is defined (with appropriate format, width &
1139 // height)
1140
1141 // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1142 // framebuffer in shaders, so we should use the non-rendering copy path.
1143 if (!canCreateRenderTargetForImage(index) ||
1144 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1145 {
1146 ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedOffset,
1147 clippedArea, source));
1148 mDirtyImages = true;
1149 }
1150 else
1151 {
1152 ANGLE_TRY(ensureRenderTarget(context));
1153
1154 if (isValidLevel(index.getLevelIndex()))
1155 {
1156 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1157 ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea,
1158 gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1159 clippedOffset, mTexStorage, index.getLevelIndex()));
1160 }
1161 }
1162
1163 return angle::Result::Continue;
1164 }
1165
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1166 angle::Result TextureD3D_2D::copyTexture(const gl::Context *context,
1167 const gl::ImageIndex &index,
1168 GLenum internalFormat,
1169 GLenum type,
1170 GLint sourceLevel,
1171 bool unpackFlipY,
1172 bool unpackPremultiplyAlpha,
1173 bool unpackUnmultiplyAlpha,
1174 const gl::Texture *source)
1175 {
1176 ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1177
1178 gl::TextureType sourceType = source->getType();
1179
1180 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1181 gl::Extents size(
1182 static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1183 static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1184 1);
1185 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
1186 size, false));
1187
1188 gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1189 gl::Offset destOffset(0, 0, 0);
1190
1191 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1192 {
1193 ANGLE_TRY(ensureRenderTarget(context));
1194 ASSERT(isValidLevel(index.getLevelIndex()));
1195 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1196
1197 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1198 sourceBox, internalFormatInfo.format,
1199 internalFormatInfo.type, destOffset, mTexStorage,
1200 index.getTarget(), index.getLevelIndex(), unpackFlipY,
1201 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1202 }
1203 else
1204 {
1205 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1206 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
1207 ImageD3D *sourceImage = nullptr;
1208 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1209
1210 ImageD3D *destImage = nullptr;
1211 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1212
1213 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1214 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1215
1216 mDirtyImages = true;
1217
1218 gl::Box destRegion(destOffset, size);
1219 ANGLE_TRY(commitRegion(context, index, destRegion));
1220 }
1221
1222 return angle::Result::Continue;
1223 }
1224
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1225 angle::Result TextureD3D_2D::copySubTexture(const gl::Context *context,
1226 const gl::ImageIndex &index,
1227 const gl::Offset &destOffset,
1228 GLint sourceLevel,
1229 const gl::Box &sourceBox,
1230 bool unpackFlipY,
1231 bool unpackPremultiplyAlpha,
1232 bool unpackUnmultiplyAlpha,
1233 const gl::Texture *source)
1234 {
1235 ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1236
1237 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1238 {
1239 ANGLE_TRY(ensureRenderTarget(context));
1240 ASSERT(isValidLevel(index.getLevelIndex()));
1241 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1242
1243 const gl::InternalFormat &internalFormatInfo =
1244 gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
1245 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1246 sourceBox, internalFormatInfo.format,
1247 internalFormatInfo.type, destOffset, mTexStorage,
1248 index.getTarget(), index.getLevelIndex(), unpackFlipY,
1249 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1250 }
1251 else
1252 {
1253 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1254 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
1255 ImageD3D *sourceImage = nullptr;
1256 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1257
1258 ImageD3D *destImage = nullptr;
1259 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1260
1261 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1262 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1263
1264 mDirtyImages = true;
1265
1266 gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
1267 ANGLE_TRY(commitRegion(context, index, destRegion));
1268 }
1269
1270 return angle::Result::Continue;
1271 }
1272
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)1273 angle::Result TextureD3D_2D::copyCompressedTexture(const gl::Context *context,
1274 const gl::Texture *source)
1275 {
1276 gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1277 GLint sourceLevel = 0;
1278
1279 GLint destLevel = 0;
1280
1281 GLenum sizedInternalFormat =
1282 source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat;
1283 gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1284 static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1285 ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false));
1286
1287 ANGLE_TRY(initializeStorage(context, false));
1288 ASSERT(mTexStorage);
1289
1290 ANGLE_TRY(
1291 mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel));
1292
1293 return angle::Result::Continue;
1294 }
1295
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1296 angle::Result TextureD3D_2D::setStorage(const gl::Context *context,
1297 gl::TextureType type,
1298 size_t levels,
1299 GLenum internalFormat,
1300 const gl::Extents &size)
1301 {
1302 ASSERT(type == gl::TextureType::_2D && size.depth == 1);
1303
1304 for (size_t level = 0; level < levels; level++)
1305 {
1306 gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
1307 1);
1308 ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true));
1309 }
1310
1311 for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1312 {
1313 ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1314 }
1315
1316 // TODO(geofflang): Verify storage creation had no errors
1317 bool renderTarget = IsRenderTargetUsage(mState.getUsage());
1318 TexStoragePointer storage(context);
1319 storage.reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width,
1320 size.height, static_cast<int>(levels),
1321 mState.getLabel(), false));
1322
1323 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1324 storage.release();
1325
1326 ANGLE_TRY(updateStorage(context));
1327
1328 mImmutable = true;
1329
1330 return angle::Result::Continue;
1331 }
1332
bindTexImage(const gl::Context * context,egl::Surface * surface)1333 angle::Result TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface)
1334 {
1335 GLenum internalformat = surface->getConfig()->renderTargetFormat;
1336
1337 gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
1338 ANGLE_TRY(redefineImage(context, 0, internalformat, size, true));
1339
1340 ANGLE_TRY(releaseTexStorage(context));
1341
1342 SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
1343 ASSERT(surfaceD3D);
1344
1345 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain(), mState.getLabel());
1346 mEGLImageTarget = false;
1347
1348 mDirtyImages = false;
1349 mImageArray[0]->markClean();
1350
1351 return angle::Result::Continue;
1352 }
1353
releaseTexImage(const gl::Context * context)1354 angle::Result TextureD3D_2D::releaseTexImage(const gl::Context *context)
1355 {
1356 if (mTexStorage)
1357 {
1358 ANGLE_TRY(releaseTexStorage(context));
1359 }
1360
1361 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1362 {
1363 ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true));
1364 }
1365
1366 return angle::Result::Continue;
1367 }
1368
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1369 angle::Result TextureD3D_2D::setEGLImageTarget(const gl::Context *context,
1370 gl::TextureType type,
1371 egl::Image *image)
1372 {
1373 EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
1374
1375 // Set the properties of the base mip level from the EGL image
1376 const auto &format = image->getFormat();
1377 gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1);
1378 ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true));
1379
1380 // Clear all other images.
1381 for (size_t level = 1; level < mImageArray.size(); level++)
1382 {
1383 ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1384 }
1385
1386 ANGLE_TRY(releaseTexStorage(context));
1387 mImageArray[0]->markClean();
1388
1389 // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
1390 RenderTargetD3D *renderTargetD3D = nullptr;
1391 ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
1392
1393 mTexStorage =
1394 mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
1395 mEGLImageTarget = true;
1396
1397 return angle::Result::Continue;
1398 }
1399
initMipmapImages(const gl::Context * context)1400 angle::Result TextureD3D_2D::initMipmapImages(const gl::Context *context)
1401 {
1402 const GLuint baseLevel = mState.getEffectiveBaseLevel();
1403 const GLuint maxLevel = mState.getMipmapMaxLevel();
1404 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
1405 // levels.
1406 for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
1407 {
1408 gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
1409 std::max(getLevelZeroHeight() >> level, 1), 1);
1410
1411 ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
1412 }
1413 return angle::Result::Continue;
1414 }
1415
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)1416 angle::Result TextureD3D_2D::getRenderTarget(const gl::Context *context,
1417 const gl::ImageIndex &index,
1418 GLsizei samples,
1419 RenderTargetD3D **outRT)
1420 {
1421 ASSERT(!index.hasLayer());
1422
1423 // ensure the underlying texture is created
1424 ANGLE_TRY(ensureRenderTarget(context));
1425 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1426
1427 return mTexStorage->getRenderTarget(context, index, samples, outRT);
1428 }
1429
isValidLevel(int level) const1430 bool TextureD3D_2D::isValidLevel(int level) const
1431 {
1432 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1433 }
1434
isLevelComplete(int level) const1435 bool TextureD3D_2D::isLevelComplete(int level) const
1436 {
1437 if (isImmutable())
1438 {
1439 return true;
1440 }
1441
1442 GLsizei width = getLevelZeroWidth();
1443 GLsizei height = getLevelZeroHeight();
1444
1445 if (width <= 0 || height <= 0)
1446 {
1447 return false;
1448 }
1449
1450 // The base image level is complete if the width and height are positive
1451 if (level == static_cast<int>(getBaseLevel()))
1452 {
1453 return true;
1454 }
1455
1456 ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) &&
1457 mImageArray[level] != nullptr);
1458 ImageD3D *image = mImageArray[level].get();
1459
1460 if (image->getInternalFormat() != getBaseLevelInternalFormat())
1461 {
1462 return false;
1463 }
1464
1465 if (image->getWidth() != std::max(1, width >> level))
1466 {
1467 return false;
1468 }
1469
1470 if (image->getHeight() != std::max(1, height >> level))
1471 {
1472 return false;
1473 }
1474
1475 return true;
1476 }
1477
isImageComplete(const gl::ImageIndex & index) const1478 bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
1479 {
1480 return isLevelComplete(index.getLevelIndex());
1481 }
1482
1483 // Constructs a native texture resource from the texture images
initializeStorage(const gl::Context * context,bool renderTarget)1484 angle::Result TextureD3D_2D::initializeStorage(const gl::Context *context, bool renderTarget)
1485 {
1486 // Only initialize the first time this texture is used as a render target or shader resource
1487 if (mTexStorage)
1488 {
1489 return angle::Result::Continue;
1490 }
1491
1492 // do not attempt to create storage for nonexistant data
1493 if (!isLevelComplete(getBaseLevel()))
1494 {
1495 return angle::Result::Continue;
1496 }
1497
1498 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
1499
1500 TexStoragePointer storage(context);
1501 ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
1502
1503 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1504 storage.release();
1505
1506 ASSERT(mTexStorage);
1507
1508 // flush image data to the storage
1509 ANGLE_TRY(updateStorage(context));
1510
1511 return angle::Result::Continue;
1512 }
1513
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const1514 angle::Result TextureD3D_2D::createCompleteStorage(bool renderTarget,
1515 TexStoragePointer *outStorage) const
1516 {
1517 GLsizei width = getLevelZeroWidth();
1518 GLsizei height = getLevelZeroHeight();
1519 GLenum internalFormat = getBaseLevelInternalFormat();
1520
1521 ASSERT(width > 0 && height > 0);
1522
1523 // use existing storage level count, when previously specified by TexStorage*D
1524 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1525
1526 bool hintLevelZeroOnly = false;
1527 if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1528 {
1529 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use
1530 // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
1531 hintLevelZeroOnly = true;
1532 for (int level = 1; level < levels && hintLevelZeroOnly; level++)
1533 {
1534 hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
1535 }
1536 }
1537
1538 // TODO(geofflang): Determine if the texture creation succeeded
1539 outStorage->reset(mRenderer->createTextureStorage2D(
1540 internalFormat, renderTarget, width, height, levels, mState.getLabel(), hintLevelZeroOnly));
1541
1542 return angle::Result::Continue;
1543 }
1544
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)1545 angle::Result TextureD3D_2D::setCompleteTexStorage(const gl::Context *context,
1546 TextureStorage *newCompleteTexStorage)
1547 {
1548 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
1549 {
1550 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
1551 {
1552 ANGLE_TRY(
1553 mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level));
1554 }
1555 }
1556
1557 ANGLE_TRY(releaseTexStorage(context));
1558 mTexStorage = newCompleteTexStorage;
1559 mTexStorageObserverBinding.bind(mTexStorage);
1560
1561 mDirtyImages = true;
1562
1563 return angle::Result::Continue;
1564 }
1565
updateStorage(const gl::Context * context)1566 angle::Result TextureD3D_2D::updateStorage(const gl::Context *context)
1567 {
1568 if (!mDirtyImages)
1569 {
1570 return angle::Result::Continue;
1571 }
1572
1573 ASSERT(mTexStorage != nullptr);
1574 GLint storageLevels = mTexStorage->getLevelCount();
1575 for (int level = 0; level < storageLevels; level++)
1576 {
1577 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1578 {
1579 ANGLE_TRY(updateStorageLevel(context, level));
1580 }
1581 }
1582
1583 mDirtyImages = false;
1584 return angle::Result::Continue;
1585 }
1586
updateStorageLevel(const gl::Context * context,int level)1587 angle::Result TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level)
1588 {
1589 ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr);
1590 ASSERT(isLevelComplete(level));
1591
1592 if (mImageArray[level]->isDirty())
1593 {
1594 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1595 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
1596 ANGLE_TRY(commitRegion(context, index, region));
1597 }
1598
1599 return angle::Result::Continue;
1600 }
1601
redefineImage(const gl::Context * context,size_t level,GLenum internalformat,const gl::Extents & size,bool forceRelease)1602 angle::Result TextureD3D_2D::redefineImage(const gl::Context *context,
1603 size_t level,
1604 GLenum internalformat,
1605 const gl::Extents &size,
1606 bool forceRelease)
1607 {
1608 ASSERT(size.depth == 1);
1609
1610 // If there currently is a corresponding storage texture image, it has these parameters
1611 const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
1612 const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
1613 const GLenum storageFormat = getBaseLevelInternalFormat();
1614
1615 mImageArray[level]->redefine(gl::TextureType::_2D, internalformat, size, forceRelease);
1616 mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
1617
1618 if (mTexStorage)
1619 {
1620 const size_t storageLevels = mTexStorage->getLevelCount();
1621
1622 // If the storage was from an EGL image, copy it back into local images to preserve it
1623 // while orphaning
1624 if (level != 0 && mEGLImageTarget)
1625 {
1626 ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0),
1627 mTexStorage));
1628 }
1629
1630 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
1631 size.height != storageHeight || internalformat != storageFormat ||
1632 mEGLImageTarget) // Discard mismatched storage
1633 {
1634 ANGLE_TRY(releaseTexStorage(context));
1635 markAllImagesDirty();
1636 }
1637 }
1638
1639 // Can't be an EGL image target after being redefined
1640 mEGLImageTarget = false;
1641
1642 return angle::Result::Continue;
1643 }
1644
imageIterator() const1645 gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1646 {
1647 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1648 }
1649
getImageIndex(GLint mip,GLint) const1650 gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1651 {
1652 // "layer" does not apply to 2D Textures.
1653 return gl::ImageIndex::Make2D(mip);
1654 }
1655
isValidIndex(const gl::ImageIndex & index) const1656 bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1657 {
1658 return (mTexStorage && index.getType() == gl::TextureType::_2D && index.getLevelIndex() >= 0 &&
1659 index.getLevelIndex() < mTexStorage->getLevelCount());
1660 }
1661
markAllImagesDirty()1662 void TextureD3D_2D::markAllImagesDirty()
1663 {
1664 for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1665 {
1666 mImageArray[i]->markDirty();
1667 }
1668 mDirtyImages = true;
1669 }
1670
TextureD3D_Cube(const gl::TextureState & state,RendererD3D * renderer)1671 TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer)
1672 : TextureD3D(state, renderer)
1673 {
1674 for (auto &face : mImageArray)
1675 {
1676 for (auto &image : face)
1677 {
1678 image.reset(renderer->createImage());
1679 }
1680 }
1681 }
1682
onDestroy(const gl::Context * context)1683 void TextureD3D_Cube::onDestroy(const gl::Context *context)
1684 {
1685 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
1686 // for some of their data. If TextureStorage is deleted before the Images, then their data will
1687 // be wastefully copied back from the GPU before we delete the Images.
1688 for (auto &face : mImageArray)
1689 {
1690 for (auto &image : face)
1691 {
1692 image.reset();
1693 }
1694 }
1695 return TextureD3D::onDestroy(context);
1696 }
1697
~TextureD3D_Cube()1698 TextureD3D_Cube::~TextureD3D_Cube() {}
1699
getImage(int level,int layer) const1700 ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
1701 {
1702 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1703 ASSERT(layer >= 0 && static_cast<size_t>(layer) < gl::kCubeFaceCount);
1704 return mImageArray[layer][level].get();
1705 }
1706
getImage(const gl::ImageIndex & index) const1707 ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1708 {
1709 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1710 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1711 return mImageArray[index.cubeMapFaceIndex()][index.getLevelIndex()].get();
1712 }
1713
getLayerCount(int level) const1714 GLsizei TextureD3D_Cube::getLayerCount(int level) const
1715 {
1716 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1717 return gl::kCubeFaceCount;
1718 }
1719
getInternalFormat(GLint level,GLint layer) const1720 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
1721 {
1722 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1723 return mImageArray[layer][level]->getInternalFormat();
1724 else
1725 return GL_NONE;
1726 }
1727
isDepth(GLint level,GLint layer) const1728 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
1729 {
1730 return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
1731 }
1732
isSRGB(GLint level,GLint layer) const1733 bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const
1734 {
1735 return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB;
1736 }
1737
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1738 angle::Result TextureD3D_Cube::setEGLImageTarget(const gl::Context *context,
1739 gl::TextureType type,
1740 egl::Image *image)
1741 {
1742 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
1743 return angle::Result::Continue;
1744 }
1745
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)1746 angle::Result TextureD3D_Cube::setImage(const gl::Context *context,
1747 const gl::ImageIndex &index,
1748 GLenum internalFormat,
1749 const gl::Extents &size,
1750 GLenum format,
1751 GLenum type,
1752 const gl::PixelUnpackState &unpack,
1753 gl::Buffer *unpackBuffer,
1754 const uint8_t *pixels)
1755 {
1756 ASSERT(size.depth == 1);
1757
1758 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1759 ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1760 internalFormatInfo.sizedInternalFormat, size, false));
1761
1762 return setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0);
1763 }
1764
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)1765 angle::Result TextureD3D_Cube::setSubImage(const gl::Context *context,
1766 const gl::ImageIndex &index,
1767 const gl::Box &area,
1768 GLenum format,
1769 GLenum type,
1770 const gl::PixelUnpackState &unpack,
1771 gl::Buffer *unpackBuffer,
1772 const uint8_t *pixels)
1773 {
1774 ASSERT(area.depth == 1 && area.z == 0);
1775 return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, pixels,
1776 0);
1777 }
1778
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1779 angle::Result TextureD3D_Cube::setCompressedImage(const gl::Context *context,
1780 const gl::ImageIndex &index,
1781 GLenum internalFormat,
1782 const gl::Extents &size,
1783 const gl::PixelUnpackState &unpack,
1784 size_t imageSize,
1785 const uint8_t *pixels)
1786 {
1787 ASSERT(size.depth == 1);
1788
1789 // compressed formats don't have separate sized internal formats-- we can just use the
1790 // compressed format directly
1791 ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1792 internalFormat, size, false));
1793
1794 return setCompressedImageImpl(context, index, unpack, pixels, 0);
1795 }
1796
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1797 angle::Result TextureD3D_Cube::setCompressedSubImage(const gl::Context *context,
1798 const gl::ImageIndex &index,
1799 const gl::Box &area,
1800 GLenum format,
1801 const gl::PixelUnpackState &unpack,
1802 size_t imageSize,
1803 const uint8_t *pixels)
1804 {
1805 ASSERT(area.depth == 1 && area.z == 0);
1806
1807 ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
1808 return commitRegion(context, index, area);
1809 }
1810
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)1811 angle::Result TextureD3D_Cube::copyImage(const gl::Context *context,
1812 const gl::ImageIndex &index,
1813 const gl::Rectangle &sourceArea,
1814 GLenum internalFormat,
1815 gl::Framebuffer *source)
1816 {
1817 GLint faceIndex = index.cubeMapFaceIndex();
1818 const gl::InternalFormat &internalFormatInfo =
1819 gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1820
1821 gl::Extents size(sourceArea.width, sourceArea.height, 1);
1822 ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1823 internalFormatInfo.sizedInternalFormat, size, false));
1824
1825 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1826
1827 // Does the read area extend beyond the framebuffer?
1828 bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
1829 sourceArea.x + sourceArea.width > fbSize.width ||
1830 sourceArea.y + sourceArea.height > fbSize.height;
1831
1832 // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
1833 // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
1834 // Same thing for robust resource init.
1835 if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled()))
1836 {
1837 ANGLE_TRY(initializeContents(context, index));
1838 }
1839
1840 gl::Rectangle clippedArea;
1841 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1842 {
1843 // Empty source area, nothing to do.
1844 return angle::Result::Continue;
1845 }
1846
1847 gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
1848
1849 // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1850 // framebuffer in shaders, so we should use the non-rendering copy path.
1851 if (!canCreateRenderTargetForImage(index) ||
1852 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1853 {
1854 ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1855 context, destOffset, clippedArea, source));
1856 mDirtyImages = true;
1857 }
1858 else
1859 {
1860 ANGLE_TRY(ensureRenderTarget(context));
1861
1862 ASSERT(size.width == size.height);
1863
1864 if (size.width > 0 && isValidFaceLevel(faceIndex, index.getLevelIndex()))
1865 {
1866 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1867 ANGLE_TRY(mRenderer->copyImageCube(context, source, clippedArea, internalFormat,
1868 destOffset, mTexStorage, index.getTarget(),
1869 index.getLevelIndex()));
1870 }
1871 }
1872
1873 return angle::Result::Continue;
1874 }
1875
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1876 angle::Result TextureD3D_Cube::copySubImage(const gl::Context *context,
1877 const gl::ImageIndex &index,
1878 const gl::Offset &destOffset,
1879 const gl::Rectangle &sourceArea,
1880 gl::Framebuffer *source)
1881 {
1882 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1883 gl::Rectangle clippedArea;
1884 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1885 {
1886 return angle::Result::Continue;
1887 }
1888 const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1889 destOffset.y + clippedArea.y - sourceArea.y, 0);
1890
1891 GLint faceIndex = index.cubeMapFaceIndex();
1892
1893 // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1894 // framebuffer in shaders, so we should use the non-rendering copy path.
1895 if (!canCreateRenderTargetForImage(index) ||
1896 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1897 {
1898 ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1899 context, clippedOffset, clippedArea, source));
1900 mDirtyImages = true;
1901 }
1902 else
1903 {
1904 ANGLE_TRY(ensureRenderTarget(context));
1905 if (isValidFaceLevel(faceIndex, index.getLevelIndex()))
1906 {
1907 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1908 ANGLE_TRY(mRenderer->copyImageCube(
1909 context, source, clippedArea, gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1910 clippedOffset, mTexStorage, index.getTarget(), index.getLevelIndex()));
1911 }
1912 }
1913
1914 return angle::Result::Continue;
1915 }
1916
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1917 angle::Result TextureD3D_Cube::copyTexture(const gl::Context *context,
1918 const gl::ImageIndex &index,
1919 GLenum internalFormat,
1920 GLenum type,
1921 GLint sourceLevel,
1922 bool unpackFlipY,
1923 bool unpackPremultiplyAlpha,
1924 bool unpackUnmultiplyAlpha,
1925 const gl::Texture *source)
1926 {
1927 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1928
1929 gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1930
1931 GLint faceIndex = index.cubeMapFaceIndex();
1932
1933 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1934 gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1935 static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1936 ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1937 internalFormatInfo.sizedInternalFormat, size, false));
1938
1939 gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1940 gl::Offset destOffset(0, 0, 0);
1941
1942 if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
1943 {
1944
1945 ANGLE_TRY(ensureRenderTarget(context));
1946 ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
1947 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1948
1949 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1950 sourceBox, internalFormatInfo.format,
1951 internalFormatInfo.type, destOffset, mTexStorage,
1952 index.getTarget(), index.getLevelIndex(), unpackFlipY,
1953 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1954 }
1955 else
1956 {
1957 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1958 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
1959 ImageD3D *sourceImage = nullptr;
1960 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1961
1962 ImageD3D *destImage = nullptr;
1963 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1964
1965 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1966 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1967
1968 mDirtyImages = true;
1969
1970 gl::Box destRegion(destOffset, size);
1971 ANGLE_TRY(commitRegion(context, index, destRegion));
1972 }
1973
1974 return angle::Result::Continue;
1975 }
1976
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1977 angle::Result TextureD3D_Cube::copySubTexture(const gl::Context *context,
1978 const gl::ImageIndex &index,
1979 const gl::Offset &destOffset,
1980 GLint sourceLevel,
1981 const gl::Box &sourceBox,
1982 bool unpackFlipY,
1983 bool unpackPremultiplyAlpha,
1984 bool unpackUnmultiplyAlpha,
1985 const gl::Texture *source)
1986 {
1987 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1988
1989 GLint faceIndex = index.cubeMapFaceIndex();
1990
1991 if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
1992 {
1993 ANGLE_TRY(ensureRenderTarget(context));
1994 ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
1995 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1996
1997 const gl::InternalFormat &internalFormatInfo =
1998 gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex(), faceIndex));
1999 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
2000 sourceBox, internalFormatInfo.format,
2001 internalFormatInfo.type, destOffset, mTexStorage,
2002 index.getTarget(), index.getLevelIndex(), unpackFlipY,
2003 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2004 }
2005 else
2006 {
2007 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
2008 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
2009 ImageD3D *sourceImage = nullptr;
2010 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2011
2012 ImageD3D *destImage = nullptr;
2013 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
2014
2015 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2016 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2017
2018 mDirtyImages = true;
2019
2020 gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
2021 ANGLE_TRY(commitRegion(context, index, destRegion));
2022 }
2023
2024 return angle::Result::Continue;
2025 }
2026
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2027 angle::Result TextureD3D_Cube::setStorage(const gl::Context *context,
2028 gl::TextureType type,
2029 size_t levels,
2030 GLenum internalFormat,
2031 const gl::Extents &size)
2032 {
2033 ASSERT(size.width == size.height);
2034 ASSERT(size.depth == 1);
2035
2036 for (size_t level = 0; level < levels; level++)
2037 {
2038 GLsizei mipSize = std::max(1, size.width >> level);
2039 for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2040 {
2041 mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalFormat,
2042 gl::Extents(mipSize, mipSize, 1), true);
2043 }
2044 }
2045
2046 for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2047 {
2048 for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2049 {
2050 mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, GL_NONE,
2051 gl::Extents(0, 0, 0), true);
2052 }
2053 }
2054
2055 // TODO(geofflang): Verify storage creation had no errors
2056 bool renderTarget = IsRenderTargetUsage(mState.getUsage());
2057
2058 TexStoragePointer storage(context);
2059 storage.reset(mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width,
2060 static_cast<int>(levels), false,
2061 mState.getLabel()));
2062
2063 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2064 storage.release();
2065
2066 ANGLE_TRY(updateStorage(context));
2067
2068 mImmutable = true;
2069
2070 return angle::Result::Continue;
2071 }
2072
2073 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isCubeComplete() const2074 bool TextureD3D_Cube::isCubeComplete() const
2075 {
2076 int baseWidth = getBaseLevelWidth();
2077 int baseHeight = getBaseLevelHeight();
2078 GLenum baseFormat = getBaseLevelInternalFormat();
2079
2080 if (baseWidth <= 0 || baseWidth != baseHeight)
2081 {
2082 return false;
2083 }
2084
2085 for (size_t faceIndex = 1; faceIndex < gl::kCubeFaceCount; faceIndex++)
2086 {
2087 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
2088
2089 if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight ||
2090 faceBaseImage.getInternalFormat() != baseFormat)
2091 {
2092 return false;
2093 }
2094 }
2095
2096 return true;
2097 }
2098
bindTexImage(const gl::Context * context,egl::Surface * surface)2099 angle::Result TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface)
2100 {
2101 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2102 return angle::Result::Continue;
2103 }
2104
releaseTexImage(const gl::Context * context)2105 angle::Result TextureD3D_Cube::releaseTexImage(const gl::Context *context)
2106 {
2107 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2108 return angle::Result::Continue;
2109 }
2110
initMipmapImages(const gl::Context * context)2111 angle::Result TextureD3D_Cube::initMipmapImages(const gl::Context *context)
2112 {
2113 const GLuint baseLevel = mState.getEffectiveBaseLevel();
2114 const GLuint maxLevel = mState.getMipmapMaxLevel();
2115 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2116 // levels.
2117 for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2118 {
2119 for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2120 {
2121 int faceLevelSize =
2122 (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1));
2123 ANGLE_TRY(redefineImage(context, faceIndex, level,
2124 mImageArray[faceIndex][baseLevel]->getInternalFormat(),
2125 gl::Extents(faceLevelSize, faceLevelSize, 1), false));
2126 }
2127 }
2128 return angle::Result::Continue;
2129 }
2130
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2131 angle::Result TextureD3D_Cube::getRenderTarget(const gl::Context *context,
2132 const gl::ImageIndex &index,
2133 GLsizei samples,
2134 RenderTargetD3D **outRT)
2135 {
2136 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
2137
2138 // ensure the underlying texture is created
2139 ANGLE_TRY(ensureRenderTarget(context));
2140 ANGLE_TRY(updateStorageFaceLevel(context, index.cubeMapFaceIndex(), index.getLevelIndex()));
2141
2142 return mTexStorage->getRenderTarget(context, index, samples, outRT);
2143 }
2144
initializeStorage(const gl::Context * context,bool renderTarget)2145 angle::Result TextureD3D_Cube::initializeStorage(const gl::Context *context, bool renderTarget)
2146 {
2147 // Only initialize the first time this texture is used as a render target or shader resource
2148 if (mTexStorage)
2149 {
2150 return angle::Result::Continue;
2151 }
2152
2153 // do not attempt to create storage for nonexistant data
2154 if (!isFaceLevelComplete(0, getBaseLevel()))
2155 {
2156 return angle::Result::Continue;
2157 }
2158
2159 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
2160
2161 TexStoragePointer storage(context);
2162 ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
2163
2164 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2165 storage.release();
2166
2167 ASSERT(mTexStorage);
2168
2169 // flush image data to the storage
2170 ANGLE_TRY(updateStorage(context));
2171
2172 return angle::Result::Continue;
2173 }
2174
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const2175 angle::Result TextureD3D_Cube::createCompleteStorage(bool renderTarget,
2176 TexStoragePointer *outStorage) const
2177 {
2178 GLsizei size = getLevelZeroWidth();
2179
2180 ASSERT(size > 0);
2181
2182 // use existing storage level count, when previously specified by TexStorage*D
2183 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
2184
2185 bool hintLevelZeroOnly = false;
2186 if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
2187 {
2188 // If any of the CPU images (levels >= 1) are dirty, then the textureStorageEXT should use
2189 // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
2190 hintLevelZeroOnly = true;
2191 for (int faceIndex = 0;
2192 faceIndex < static_cast<int>(gl::kCubeFaceCount) && hintLevelZeroOnly; faceIndex++)
2193 {
2194 for (int level = 1; level < levels && hintLevelZeroOnly; level++)
2195 {
2196 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() &&
2197 isFaceLevelComplete(faceIndex, level));
2198 }
2199 }
2200 }
2201
2202 // TODO (geofflang): detect if storage creation succeeded
2203 outStorage->reset(mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(),
2204 renderTarget, size, levels,
2205 hintLevelZeroOnly, mState.getLabel()));
2206
2207 return angle::Result::Continue;
2208 }
2209
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2210 angle::Result TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context,
2211 TextureStorage *newCompleteTexStorage)
2212 {
2213 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
2214 {
2215 for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2216 {
2217 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
2218 {
2219 ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube(
2220 context, newCompleteTexStorage, faceIndex, level));
2221 }
2222 }
2223 }
2224
2225 ANGLE_TRY(releaseTexStorage(context));
2226 mTexStorage = newCompleteTexStorage;
2227 mTexStorageObserverBinding.bind(mTexStorage);
2228
2229 mDirtyImages = true;
2230 return angle::Result::Continue;
2231 }
2232
updateStorage(const gl::Context * context)2233 angle::Result TextureD3D_Cube::updateStorage(const gl::Context *context)
2234 {
2235 if (!mDirtyImages)
2236 {
2237 return angle::Result::Continue;
2238 }
2239
2240 ASSERT(mTexStorage != nullptr);
2241 GLint storageLevels = mTexStorage->getLevelCount();
2242 for (int face = 0; face < static_cast<int>(gl::kCubeFaceCount); face++)
2243 {
2244 for (int level = 0; level < storageLevels; level++)
2245 {
2246 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
2247 {
2248 ANGLE_TRY(updateStorageFaceLevel(context, face, level));
2249 }
2250 }
2251 }
2252
2253 mDirtyImages = false;
2254 return angle::Result::Continue;
2255 }
2256
isValidFaceLevel(int faceIndex,int level) const2257 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
2258 {
2259 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2260 }
2261
isFaceLevelComplete(int faceIndex,int level) const2262 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
2263 {
2264 if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2265 {
2266 return false;
2267 }
2268 ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2269 level < static_cast<int>(mImageArray[faceIndex].size()) &&
2270 mImageArray[faceIndex][level] != nullptr);
2271
2272 if (isImmutable())
2273 {
2274 return true;
2275 }
2276
2277 int levelZeroSize = getLevelZeroWidth();
2278
2279 if (levelZeroSize <= 0)
2280 {
2281 return false;
2282 }
2283
2284 // Check that non-zero levels are consistent with the base level.
2285 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get();
2286
2287 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
2288 {
2289 return false;
2290 }
2291
2292 if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
2293 {
2294 return false;
2295 }
2296
2297 return true;
2298 }
2299
isImageComplete(const gl::ImageIndex & index) const2300 bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
2301 {
2302 return isFaceLevelComplete(index.cubeMapFaceIndex(), index.getLevelIndex());
2303 }
2304
updateStorageFaceLevel(const gl::Context * context,int faceIndex,int level)2305 angle::Result TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
2306 int faceIndex,
2307 int level)
2308 {
2309 ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2310 level < static_cast<int>(mImageArray[faceIndex].size()) &&
2311 mImageArray[faceIndex][level] != nullptr);
2312 ImageD3D *image = mImageArray[faceIndex][level].get();
2313
2314 if (image->isDirty())
2315 {
2316 gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex);
2317 gl::ImageIndex index = gl::ImageIndex::MakeCubeMapFace(faceTarget, level);
2318 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
2319 ANGLE_TRY(commitRegion(context, index, region));
2320 }
2321
2322 return angle::Result::Continue;
2323 }
2324
redefineImage(const gl::Context * context,int faceIndex,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2325 angle::Result TextureD3D_Cube::redefineImage(const gl::Context *context,
2326 int faceIndex,
2327 GLint level,
2328 GLenum internalformat,
2329 const gl::Extents &size,
2330 bool forceRelease)
2331 {
2332 // If there currently is a corresponding storage texture image, it has these parameters
2333 const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
2334 const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
2335 const GLenum storageFormat = getBaseLevelInternalFormat();
2336
2337 mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalformat, size,
2338 forceRelease);
2339 mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty();
2340
2341 if (mTexStorage)
2342 {
2343 const int storageLevels = mTexStorage->getLevelCount();
2344
2345 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
2346 size.height != storageHeight ||
2347 internalformat != storageFormat) // Discard mismatched storage
2348 {
2349 markAllImagesDirty();
2350 ANGLE_TRY(releaseTexStorage(context));
2351 }
2352 }
2353
2354 return angle::Result::Continue;
2355 }
2356
imageIterator() const2357 gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
2358 {
2359 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
2360 }
2361
getImageIndex(GLint mip,GLint layer) const2362 gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
2363 {
2364 // The "layer" of the image index corresponds to the cube face
2365 return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip);
2366 }
2367
isValidIndex(const gl::ImageIndex & index) const2368 bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
2369 {
2370 return (mTexStorage && index.getType() == gl::TextureType::CubeMap &&
2371 gl::IsCubeMapFaceTarget(index.getTarget()) && index.getLevelIndex() >= 0 &&
2372 index.getLevelIndex() < mTexStorage->getLevelCount());
2373 }
2374
markAllImagesDirty()2375 void TextureD3D_Cube::markAllImagesDirty()
2376 {
2377 for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
2378 {
2379 for (size_t dirtyFace = 0; dirtyFace < gl::kCubeFaceCount; dirtyFace++)
2380 {
2381 mImageArray[dirtyFace][dirtyLevel]->markDirty();
2382 }
2383 }
2384 mDirtyImages = true;
2385 }
2386
TextureD3D_3D(const gl::TextureState & state,RendererD3D * renderer)2387 TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer)
2388 : TextureD3D(state, renderer)
2389 {
2390 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
2391 {
2392 mImageArray[i].reset(renderer->createImage());
2393 }
2394 }
2395
onDestroy(const gl::Context * context)2396 void TextureD3D_3D::onDestroy(const gl::Context *context)
2397 {
2398 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
2399 // for some of their data. If TextureStorage is deleted before the Images, then their data will
2400 // be wastefully copied back from the GPU before we delete the Images.
2401 for (auto &image : mImageArray)
2402 {
2403 image.reset();
2404 }
2405 return TextureD3D::onDestroy(context);
2406 }
2407
~TextureD3D_3D()2408 TextureD3D_3D::~TextureD3D_3D() {}
2409
getImage(int level,int layer) const2410 ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
2411 {
2412 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2413 ASSERT(layer == 0);
2414 return mImageArray[level].get();
2415 }
2416
getImage(const gl::ImageIndex & index) const2417 ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
2418 {
2419 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2420 ASSERT(!index.hasLayer());
2421 ASSERT(index.getType() == gl::TextureType::_3D);
2422 return mImageArray[index.getLevelIndex()].get();
2423 }
2424
getLayerCount(int level) const2425 GLsizei TextureD3D_3D::getLayerCount(int level) const
2426 {
2427 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2428 return 1;
2429 }
2430
getWidth(GLint level) const2431 GLsizei TextureD3D_3D::getWidth(GLint level) const
2432 {
2433 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2434 return mImageArray[level]->getWidth();
2435 else
2436 return 0;
2437 }
2438
getHeight(GLint level) const2439 GLsizei TextureD3D_3D::getHeight(GLint level) const
2440 {
2441 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2442 return mImageArray[level]->getHeight();
2443 else
2444 return 0;
2445 }
2446
getDepth(GLint level) const2447 GLsizei TextureD3D_3D::getDepth(GLint level) const
2448 {
2449 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2450 return mImageArray[level]->getDepth();
2451 else
2452 return 0;
2453 }
2454
getInternalFormat(GLint level) const2455 GLenum TextureD3D_3D::getInternalFormat(GLint level) const
2456 {
2457 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2458 return mImageArray[level]->getInternalFormat();
2459 else
2460 return GL_NONE;
2461 }
2462
isDepth(GLint level) const2463 bool TextureD3D_3D::isDepth(GLint level) const
2464 {
2465 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
2466 }
2467
isSRGB(GLint level) const2468 bool TextureD3D_3D::isSRGB(GLint level) const
2469 {
2470 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
2471 }
2472
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)2473 angle::Result TextureD3D_3D::setEGLImageTarget(const gl::Context *context,
2474 gl::TextureType type,
2475 egl::Image *image)
2476 {
2477 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2478 return angle::Result::Continue;
2479 }
2480
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)2481 angle::Result TextureD3D_3D::setImage(const gl::Context *context,
2482 const gl::ImageIndex &index,
2483 GLenum internalFormat,
2484 const gl::Extents &size,
2485 GLenum format,
2486 GLenum type,
2487 const gl::PixelUnpackState &unpack,
2488 gl::Buffer *unpackBuffer,
2489 const uint8_t *pixels)
2490 {
2491 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2492 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2493
2494 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2495 size, false));
2496
2497 bool fastUnpacked = false;
2498
2499 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2500 if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) &&
2501 !size.empty() && isLevelComplete(index.getLevelIndex()))
2502 {
2503 // Will try to create RT storage if it does not exist
2504 RenderTargetD3D *destRenderTarget = nullptr;
2505 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2506
2507 gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
2508 getDepth(index.getLevelIndex()));
2509
2510 ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
2511 internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
2512
2513 // Ensure we don't overwrite our newly initialized data
2514 mImageArray[index.getLevelIndex()]->markClean();
2515
2516 fastUnpacked = true;
2517 }
2518
2519 if (!fastUnpacked)
2520 {
2521 ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
2522 }
2523
2524 return angle::Result::Continue;
2525 }
2526
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)2527 angle::Result TextureD3D_3D::setSubImage(const gl::Context *context,
2528 const gl::ImageIndex &index,
2529 const gl::Box &area,
2530 GLenum format,
2531 GLenum type,
2532 const gl::PixelUnpackState &unpack,
2533 gl::Buffer *unpackBuffer,
2534 const uint8_t *pixels)
2535 {
2536 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2537
2538 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2539 GLenum mipFormat = getInternalFormat(index.getLevelIndex());
2540 if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex()))
2541 {
2542 RenderTargetD3D *destRenderTarget = nullptr;
2543 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2544 ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
2545
2546 return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
2547 destRenderTarget);
2548 }
2549 else
2550 {
2551 return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
2552 pixels, 0);
2553 }
2554 }
2555
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)2556 angle::Result TextureD3D_3D::setCompressedImage(const gl::Context *context,
2557 const gl::ImageIndex &index,
2558 GLenum internalFormat,
2559 const gl::Extents &size,
2560 const gl::PixelUnpackState &unpack,
2561 size_t imageSize,
2562 const uint8_t *pixels)
2563 {
2564 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2565
2566 // compressed formats don't have separate sized internal formats-- we can just use the
2567 // compressed format directly
2568 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
2569
2570 return setCompressedImageImpl(context, index, unpack, pixels, 0);
2571 }
2572
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)2573 angle::Result TextureD3D_3D::setCompressedSubImage(const gl::Context *context,
2574 const gl::ImageIndex &index,
2575 const gl::Box &area,
2576 GLenum format,
2577 const gl::PixelUnpackState &unpack,
2578 size_t imageSize,
2579 const uint8_t *pixels)
2580 {
2581 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2582
2583 ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
2584 return commitRegion(context, index, area);
2585 }
2586
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)2587 angle::Result TextureD3D_3D::copyImage(const gl::Context *context,
2588 const gl::ImageIndex &index,
2589 const gl::Rectangle &sourceArea,
2590 GLenum internalFormat,
2591 gl::Framebuffer *source)
2592 {
2593 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2594 return angle::Result::Continue;
2595 }
2596
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)2597 angle::Result TextureD3D_3D::copySubImage(const gl::Context *context,
2598 const gl::ImageIndex &index,
2599 const gl::Offset &destOffset,
2600 const gl::Rectangle &sourceArea,
2601 gl::Framebuffer *source)
2602 {
2603 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2604
2605 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
2606 gl::Rectangle clippedSourceArea;
2607 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
2608 &clippedSourceArea))
2609 {
2610 return angle::Result::Continue;
2611 }
2612 const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
2613 destOffset.y + clippedSourceArea.y - sourceArea.y,
2614 destOffset.z);
2615
2616 // Currently, copying directly to the storage is not possible because it's not possible to
2617 // create an SRV from a single layer of a 3D texture. Instead, make sure the image is up to
2618 // date before the copy and then copy back to the storage afterwards if needed.
2619 // TODO: Investigate 3D blits in D3D11.
2620
2621 bool syncTexStorage = mTexStorage && isLevelComplete(index.getLevelIndex());
2622 if (syncTexStorage)
2623 {
2624 ANGLE_TRY(
2625 mImageArray[index.getLevelIndex()]->copyFromTexStorage(context, index, mTexStorage));
2626 }
2627 ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedDestOffset,
2628 clippedSourceArea, source));
2629 mDirtyImages = true;
2630
2631 if (syncTexStorage)
2632 {
2633 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2634 }
2635
2636 return angle::Result::Continue;
2637 }
2638
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)2639 angle::Result TextureD3D_3D::copyTexture(const gl::Context *context,
2640 const gl::ImageIndex &index,
2641 GLenum internalFormat,
2642 GLenum type,
2643 GLint sourceLevel,
2644 bool unpackFlipY,
2645 bool unpackPremultiplyAlpha,
2646 bool unpackUnmultiplyAlpha,
2647 const gl::Texture *source)
2648 {
2649 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2650
2651 gl::TextureType sourceType = source->getType();
2652
2653 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2654 gl::Extents size(
2655 static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2656 static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2657 static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
2658
2659 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2660 size, false));
2661
2662 gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
2663 gl::Offset destOffset(0, 0, 0);
2664 gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2665
2666 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2667 {
2668 ANGLE_TRY(ensureRenderTarget(context));
2669 ASSERT(isValidLevel(index.getLevelIndex()));
2670 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2671
2672 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
2673 sourceBox, internalFormatInfo.format,
2674 internalFormatInfo.type, destOffset, mTexStorage,
2675 index.getTarget(), index.getLevelIndex(), unpackFlipY,
2676 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2677 }
2678 else
2679 {
2680 gl::ImageIndex sourceIndex = gl::ImageIndex::Make3D(sourceLevel);
2681 ImageD3D *sourceImage = nullptr;
2682 ImageD3D *destImage = nullptr;
2683 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
2684
2685 ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2686 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceIndex, &sourceImage));
2687
2688 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2689 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2690
2691 mDirtyImages = true;
2692
2693 gl::Box destRegion(0, 0, 0, sourceBox.width, sourceBox.height, sourceBox.depth);
2694 ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2695 }
2696
2697 return angle::Result::Continue;
2698 }
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)2699 angle::Result TextureD3D_3D::copySubTexture(const gl::Context *context,
2700 const gl::ImageIndex &index,
2701 const gl::Offset &destOffset,
2702 GLint sourceLevel,
2703 const gl::Box &sourceBox,
2704 bool unpackFlipY,
2705 bool unpackPremultiplyAlpha,
2706 bool unpackUnmultiplyAlpha,
2707 const gl::Texture *source)
2708 {
2709 ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2710
2711 gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2712
2713 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2714 {
2715 ANGLE_TRY(ensureRenderTarget(context));
2716 ASSERT(isValidLevel(index.getLevelIndex()));
2717 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2718
2719 const gl::InternalFormat &internalFormatInfo =
2720 gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
2721 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
2722 sourceBox, internalFormatInfo.format,
2723 internalFormatInfo.type, destOffset, mTexStorage,
2724 index.getTarget(), index.getLevelIndex(), unpackFlipY,
2725 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2726 }
2727 else
2728 {
2729 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make3D(sourceLevel);
2730 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
2731 ImageD3D *sourceImage = nullptr;
2732 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2733
2734 ImageD3D *destImage = nullptr;
2735 ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2736
2737 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2738 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2739
2740 mDirtyImages = true;
2741
2742 gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
2743 sourceBox.height, sourceBox.depth);
2744 ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2745 }
2746
2747 return angle::Result::Continue;
2748 }
2749
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2750 angle::Result TextureD3D_3D::setStorage(const gl::Context *context,
2751 gl::TextureType type,
2752 size_t levels,
2753 GLenum internalFormat,
2754 const gl::Extents &size)
2755 {
2756 ASSERT(type == gl::TextureType::_3D);
2757
2758 for (size_t level = 0; level < levels; level++)
2759 {
2760 gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
2761 std::max(1, size.depth >> level));
2762 mImageArray[level]->redefine(gl::TextureType::_3D, internalFormat, levelSize, true);
2763 }
2764
2765 for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2766 {
2767 mImageArray[level]->redefine(gl::TextureType::_3D, GL_NONE, gl::Extents(0, 0, 0), true);
2768 }
2769
2770 // TODO(geofflang): Verify storage creation had no errors
2771 bool renderTarget = IsRenderTargetUsage(mState.getUsage());
2772 TexStoragePointer storage(context);
2773 storage.reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width,
2774 size.height, size.depth,
2775 static_cast<int>(levels), mState.getLabel()));
2776
2777 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2778 storage.release();
2779
2780 ANGLE_TRY(updateStorage(context));
2781
2782 mImmutable = true;
2783
2784 return angle::Result::Continue;
2785 }
2786
bindTexImage(const gl::Context * context,egl::Surface * surface)2787 angle::Result TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface)
2788 {
2789 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2790 return angle::Result::Continue;
2791 }
2792
releaseTexImage(const gl::Context * context)2793 angle::Result TextureD3D_3D::releaseTexImage(const gl::Context *context)
2794 {
2795 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2796 return angle::Result::Continue;
2797 }
2798
initMipmapImages(const gl::Context * context)2799 angle::Result TextureD3D_3D::initMipmapImages(const gl::Context *context)
2800 {
2801 const GLuint baseLevel = mState.getEffectiveBaseLevel();
2802 const GLuint maxLevel = mState.getMipmapMaxLevel();
2803 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2804 // levels.
2805 for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2806 {
2807 gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
2808 std::max(getLevelZeroHeight() >> level, 1),
2809 std::max(getLevelZeroDepth() >> level, 1));
2810 ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
2811 }
2812
2813 return angle::Result::Continue;
2814 }
2815
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2816 angle::Result TextureD3D_3D::getRenderTarget(const gl::Context *context,
2817 const gl::ImageIndex &index,
2818 GLsizei samples,
2819 RenderTargetD3D **outRT)
2820 {
2821 // ensure the underlying texture is created
2822 ANGLE_TRY(ensureRenderTarget(context));
2823
2824 if (index.hasLayer())
2825 {
2826 ANGLE_TRY(updateStorage(context));
2827 }
2828 else
2829 {
2830 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2831 }
2832
2833 return mTexStorage->getRenderTarget(context, index, samples, outRT);
2834 }
2835
initializeStorage(const gl::Context * context,bool renderTarget)2836 angle::Result TextureD3D_3D::initializeStorage(const gl::Context *context, bool renderTarget)
2837 {
2838 // Only initialize the first time this texture is used as a render target or shader resource
2839 if (mTexStorage)
2840 {
2841 return angle::Result::Continue;
2842 }
2843
2844 // do not attempt to create storage for nonexistant data
2845 if (!isLevelComplete(getBaseLevel()))
2846 {
2847 return angle::Result::Continue;
2848 }
2849
2850 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
2851
2852 TexStoragePointer storage(context);
2853 ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
2854
2855 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2856 storage.release();
2857
2858 ASSERT(mTexStorage);
2859
2860 // flush image data to the storage
2861 ANGLE_TRY(updateStorage(context));
2862
2863 return angle::Result::Continue;
2864 }
2865
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const2866 angle::Result TextureD3D_3D::createCompleteStorage(bool renderTarget,
2867 TexStoragePointer *outStorage) const
2868 {
2869 GLsizei width = getLevelZeroWidth();
2870 GLsizei height = getLevelZeroHeight();
2871 GLsizei depth = getLevelZeroDepth();
2872 GLenum internalFormat = getBaseLevelInternalFormat();
2873
2874 ASSERT(width > 0 && height > 0 && depth > 0);
2875
2876 // use existing storage level count, when previously specified by TexStorage*D
2877 GLint levels =
2878 (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2879
2880 // TODO: Verify creation of the storage succeeded
2881 outStorage->reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height,
2882 depth, levels, mState.getLabel()));
2883
2884 return angle::Result::Continue;
2885 }
2886
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2887 angle::Result TextureD3D_3D::setCompleteTexStorage(const gl::Context *context,
2888 TextureStorage *newCompleteTexStorage)
2889 {
2890 ANGLE_TRY(releaseTexStorage(context));
2891 mTexStorage = newCompleteTexStorage;
2892 mTexStorageObserverBinding.bind(mTexStorage);
2893 mDirtyImages = true;
2894
2895 // We do not support managed 3D storage, as that is D3D9/ES2-only
2896 ASSERT(!mTexStorage->isManaged());
2897
2898 return angle::Result::Continue;
2899 }
2900
updateStorage(const gl::Context * context)2901 angle::Result TextureD3D_3D::updateStorage(const gl::Context *context)
2902 {
2903 if (!mDirtyImages)
2904 {
2905 return angle::Result::Continue;
2906 }
2907
2908 ASSERT(mTexStorage != nullptr);
2909 GLint storageLevels = mTexStorage->getLevelCount();
2910 for (int level = 0; level < storageLevels; level++)
2911 {
2912 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2913 {
2914 ANGLE_TRY(updateStorageLevel(context, level));
2915 }
2916 }
2917
2918 mDirtyImages = false;
2919 return angle::Result::Continue;
2920 }
2921
isValidLevel(int level) const2922 bool TextureD3D_3D::isValidLevel(int level) const
2923 {
2924 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2925 }
2926
isLevelComplete(int level) const2927 bool TextureD3D_3D::isLevelComplete(int level) const
2928 {
2929 ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
2930 mImageArray[level] != nullptr);
2931
2932 if (isImmutable())
2933 {
2934 return true;
2935 }
2936
2937 GLsizei width = getLevelZeroWidth();
2938 GLsizei height = getLevelZeroHeight();
2939 GLsizei depth = getLevelZeroDepth();
2940
2941 if (width <= 0 || height <= 0 || depth <= 0)
2942 {
2943 return false;
2944 }
2945
2946 if (level == static_cast<int>(getBaseLevel()))
2947 {
2948 return true;
2949 }
2950
2951 ImageD3D *levelImage = mImageArray[level].get();
2952
2953 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2954 {
2955 return false;
2956 }
2957
2958 if (levelImage->getWidth() != std::max(1, width >> level))
2959 {
2960 return false;
2961 }
2962
2963 if (levelImage->getHeight() != std::max(1, height >> level))
2964 {
2965 return false;
2966 }
2967
2968 if (levelImage->getDepth() != std::max(1, depth >> level))
2969 {
2970 return false;
2971 }
2972
2973 return true;
2974 }
2975
isImageComplete(const gl::ImageIndex & index) const2976 bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2977 {
2978 return isLevelComplete(index.getLevelIndex());
2979 }
2980
updateStorageLevel(const gl::Context * context,int level)2981 angle::Result TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level)
2982 {
2983 ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
2984 mImageArray[level] != nullptr);
2985 ASSERT(isLevelComplete(level));
2986
2987 if (mImageArray[level]->isDirty())
2988 {
2989 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2990 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
2991 ANGLE_TRY(commitRegion(context, index, region));
2992 }
2993
2994 return angle::Result::Continue;
2995 }
2996
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2997 angle::Result TextureD3D_3D::redefineImage(const gl::Context *context,
2998 GLint level,
2999 GLenum internalformat,
3000 const gl::Extents &size,
3001 bool forceRelease)
3002 {
3003 // If there currently is a corresponding storage texture image, it has these parameters
3004 const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
3005 const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
3006 const int storageDepth = std::max(1, getLevelZeroDepth() >> level);
3007 const GLenum storageFormat = getBaseLevelInternalFormat();
3008
3009 mImageArray[level]->redefine(gl::TextureType::_3D, internalformat, size, forceRelease);
3010 mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
3011
3012 if (mTexStorage)
3013 {
3014 const int storageLevels = mTexStorage->getLevelCount();
3015
3016 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3017 size.height != storageHeight || size.depth != storageDepth ||
3018 internalformat != storageFormat) // Discard mismatched storage
3019 {
3020 markAllImagesDirty();
3021 ANGLE_TRY(releaseTexStorage(context));
3022 }
3023 }
3024
3025 return angle::Result::Continue;
3026 }
3027
imageIterator() const3028 gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
3029 {
3030 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
3031 gl::ImageIndex::kEntireLevel,
3032 gl::ImageIndex::kEntireLevel);
3033 }
3034
getImageIndex(GLint mip,GLint) const3035 gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
3036 {
3037 // The "layer" here does not apply to 3D images. We use one Image per mip.
3038 return gl::ImageIndex::Make3D(mip);
3039 }
3040
isValidIndex(const gl::ImageIndex & index) const3041 bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
3042 {
3043 return (mTexStorage && index.getType() == gl::TextureType::_3D && index.getLevelIndex() >= 0 &&
3044 index.getLevelIndex() < mTexStorage->getLevelCount());
3045 }
3046
markAllImagesDirty()3047 void TextureD3D_3D::markAllImagesDirty()
3048 {
3049 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
3050 {
3051 mImageArray[i]->markDirty();
3052 }
3053 mDirtyImages = true;
3054 }
3055
getLevelZeroDepth() const3056 GLint TextureD3D_3D::getLevelZeroDepth() const
3057 {
3058 ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel());
3059 return getBaseLevelDepth() << getBaseLevel();
3060 }
3061
TextureD3D_2DArray(const gl::TextureState & state,RendererD3D * renderer)3062 TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer)
3063 : TextureD3D(state, renderer)
3064 {
3065 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3066 {
3067 mLayerCounts[level] = 0;
3068 mImageArray[level] = nullptr;
3069 }
3070 }
3071
onDestroy(const gl::Context * context)3072 void TextureD3D_2DArray::onDestroy(const gl::Context *context)
3073 {
3074 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
3075 // for some of their data. If TextureStorage is deleted before the Images, then their data will
3076 // be wastefully copied back from the GPU before we delete the Images.
3077 deleteImages();
3078 return TextureD3D::onDestroy(context);
3079 }
3080
~TextureD3D_2DArray()3081 TextureD3D_2DArray::~TextureD3D_2DArray() {}
3082
getImage(int level,int layer) const3083 ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
3084 {
3085 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3086 ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]);
3087 return (mImageArray[level] ? mImageArray[level][layer] : nullptr);
3088 }
3089
getImage(const gl::ImageIndex & index) const3090 ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
3091 {
3092 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3093 ASSERT(index.hasLayer());
3094 ASSERT((index.getLayerIndex() == 0 && mLayerCounts[index.getLevelIndex()] == 0) ||
3095 index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]);
3096 ASSERT(index.getType() == gl::TextureType::_2DArray);
3097 return (mImageArray[index.getLevelIndex()]
3098 ? mImageArray[index.getLevelIndex()][index.getLayerIndex()]
3099 : nullptr);
3100 }
3101
getLayerCount(int level) const3102 GLsizei TextureD3D_2DArray::getLayerCount(int level) const
3103 {
3104 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3105 return mLayerCounts[level];
3106 }
3107
getWidth(GLint level) const3108 GLsizei TextureD3D_2DArray::getWidth(GLint level) const
3109 {
3110 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3111 ? mImageArray[level][0]->getWidth()
3112 : 0;
3113 }
3114
getHeight(GLint level) const3115 GLsizei TextureD3D_2DArray::getHeight(GLint level) const
3116 {
3117 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3118 ? mImageArray[level][0]->getHeight()
3119 : 0;
3120 }
3121
getInternalFormat(GLint level) const3122 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
3123 {
3124 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3125 ? mImageArray[level][0]->getInternalFormat()
3126 : GL_NONE;
3127 }
3128
isDepth(GLint level) const3129 bool TextureD3D_2DArray::isDepth(GLint level) const
3130 {
3131 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
3132 }
3133
isSRGB(GLint level) const3134 bool TextureD3D_2DArray::isSRGB(GLint level) const
3135 {
3136 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
3137 }
3138
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3139 angle::Result TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context,
3140 gl::TextureType type,
3141 egl::Image *image)
3142 {
3143 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3144 return angle::Result::Continue;
3145 }
3146
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3147 angle::Result TextureD3D_2DArray::setImage(const gl::Context *context,
3148 const gl::ImageIndex &index,
3149 GLenum internalFormat,
3150 const gl::Extents &size,
3151 GLenum format,
3152 GLenum type,
3153 const gl::PixelUnpackState &unpack,
3154 gl::Buffer *unpackBuffer,
3155 const uint8_t *pixels)
3156 {
3157 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3158
3159 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3160
3161 ANGLE_TRY(
3162 redefineImage(context, index.getLevelIndex(), formatInfo.sizedInternalFormat, size, false));
3163
3164 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3165
3166 GLuint inputDepthPitch = 0;
3167 ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3168 type, size.width, size.height, unpack.alignment,
3169 unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3170
3171 for (int i = 0; i < size.depth; i++)
3172 {
3173 const ptrdiff_t layerOffset = (inputDepthPitch * i);
3174 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3175 ANGLE_TRY(
3176 setImageImpl(context, layerIndex, type, unpack, unpackBuffer, pixels, layerOffset));
3177 }
3178
3179 return angle::Result::Continue;
3180 }
3181
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3182 angle::Result TextureD3D_2DArray::setSubImage(const gl::Context *context,
3183 const gl::ImageIndex &index,
3184 const gl::Box &area,
3185 GLenum format,
3186 GLenum type,
3187 const gl::PixelUnpackState &unpack,
3188 gl::Buffer *unpackBuffer,
3189 const uint8_t *pixels)
3190 {
3191 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3192
3193 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3194 const gl::InternalFormat &formatInfo =
3195 gl::GetInternalFormatInfo(getInternalFormat(index.getLevelIndex()), type);
3196 GLuint inputDepthPitch = 0;
3197 ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3198 type, area.width, area.height, unpack.alignment,
3199 unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3200
3201 for (int i = 0; i < area.depth; i++)
3202 {
3203 int layer = area.z + i;
3204 const ptrdiff_t layerOffset = (inputDepthPitch * i);
3205
3206 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3207
3208 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3209 ANGLE_TRY(TextureD3D::subImage(context, layerIndex, layerArea, format, type, unpack,
3210 unpackBuffer, pixels, layerOffset));
3211 }
3212
3213 return angle::Result::Continue;
3214 }
3215
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3216 angle::Result TextureD3D_2DArray::setCompressedImage(const gl::Context *context,
3217 const gl::ImageIndex &index,
3218 GLenum internalFormat,
3219 const gl::Extents &size,
3220 const gl::PixelUnpackState &unpack,
3221 size_t imageSize,
3222 const uint8_t *pixels)
3223 {
3224 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3225
3226 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3227
3228 // compressed formats don't have separate sized internal formats-- we can just use the
3229 // compressed format directly
3230 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
3231
3232 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
3233 GLuint inputDepthPitch = 0;
3234 ANGLE_CHECK_GL_MATH(
3235 contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0,
3236 &inputDepthPitch));
3237
3238 for (int i = 0; i < size.depth; i++)
3239 {
3240 const ptrdiff_t layerOffset = (inputDepthPitch * i);
3241
3242 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3243 ANGLE_TRY(setCompressedImageImpl(context, layerIndex, unpack, pixels, layerOffset));
3244 }
3245
3246 return angle::Result::Continue;
3247 }
3248
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3249 angle::Result TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context,
3250 const gl::ImageIndex &index,
3251 const gl::Box &area,
3252 GLenum format,
3253 const gl::PixelUnpackState &unpack,
3254 size_t imageSize,
3255 const uint8_t *pixels)
3256 {
3257 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3258
3259 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3260
3261 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format);
3262 GLuint inputDepthPitch = 0;
3263 ANGLE_CHECK_GL_MATH(
3264 contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0,
3265 &inputDepthPitch));
3266
3267 for (int i = 0; i < area.depth; i++)
3268 {
3269 int layer = area.z + i;
3270 const ptrdiff_t layerOffset = (inputDepthPitch * i);
3271
3272 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3273
3274 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3275 ANGLE_TRY(TextureD3D::subImageCompressed(context, layerIndex, layerArea, format, unpack,
3276 pixels, layerOffset));
3277 ANGLE_TRY(commitRegion(context, layerIndex, layerArea));
3278 }
3279
3280 return angle::Result::Continue;
3281 }
3282
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3283 angle::Result TextureD3D_2DArray::copyImage(const gl::Context *context,
3284 const gl::ImageIndex &index,
3285 const gl::Rectangle &sourceArea,
3286 GLenum internalFormat,
3287 gl::Framebuffer *source)
3288 {
3289 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3290 return angle::Result::Continue;
3291 }
3292
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3293 angle::Result TextureD3D_2DArray::copySubImage(const gl::Context *context,
3294 const gl::ImageIndex &index,
3295 const gl::Offset &destOffset,
3296 const gl::Rectangle &sourceArea,
3297 gl::Framebuffer *source)
3298 {
3299 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3300
3301 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
3302 gl::Rectangle clippedSourceArea;
3303 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
3304 &clippedSourceArea))
3305 {
3306 return angle::Result::Continue;
3307 }
3308 const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
3309 destOffset.y + clippedSourceArea.y - sourceArea.y,
3310 destOffset.z);
3311
3312 if (!canCreateRenderTargetForImage(index))
3313 {
3314 gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0);
3315 ANGLE_TRY(mImageArray[index.getLevelIndex()][clippedDestOffset.z]->copyFromFramebuffer(
3316 context, destLayerOffset, clippedSourceArea, source));
3317 mDirtyImages = true;
3318 }
3319 else
3320 {
3321 ANGLE_TRY(ensureRenderTarget(context));
3322
3323 if (isValidLevel(index.getLevelIndex()))
3324 {
3325 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3326 ANGLE_TRY(
3327 mRenderer->copyImage2DArray(context, source, clippedSourceArea,
3328 gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())),
3329 clippedDestOffset, mTexStorage, index.getLevelIndex()));
3330 }
3331 }
3332 return angle::Result::Continue;
3333 }
3334
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)3335 angle::Result TextureD3D_2DArray::copyTexture(const gl::Context *context,
3336 const gl::ImageIndex &index,
3337 GLenum internalFormat,
3338 GLenum type,
3339 GLint sourceLevel,
3340 bool unpackFlipY,
3341 bool unpackPremultiplyAlpha,
3342 bool unpackUnmultiplyAlpha,
3343 const gl::Texture *source)
3344 {
3345 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3346
3347 gl::TextureType sourceType = source->getType();
3348
3349 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3350 gl::Extents size(
3351 static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3352 static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3353 static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
3354
3355 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
3356 size, false));
3357
3358 gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
3359 gl::Offset destOffset(0, 0, 0);
3360
3361 gl::ImageIndex destIndex =
3362 gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth);
3363
3364 if (!isSRGB(index.getLevelIndex()) &&
3365 canCreateRenderTargetForImage(
3366 gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth)))
3367 {
3368 ANGLE_TRY(ensureRenderTarget(context));
3369 ASSERT(isValidLevel(index.getLevelIndex()));
3370 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3371 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
3372 sourceBox, internalFormatInfo.format,
3373 internalFormatInfo.type, destOffset, mTexStorage,
3374 index.getTarget(), index.getLevelIndex(), unpackFlipY,
3375 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
3376 }
3377 else
3378 {
3379 for (int i = 0; i < size.depth; i++)
3380 {
3381 gl::ImageIndex currentSourceDepthIndex = gl::ImageIndex::Make2DArray(sourceLevel, i);
3382 gl::ImageIndex currentDestDepthIndex =
3383 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3384 ImageD3D *sourceImage = nullptr;
3385 ImageD3D *destImage = nullptr;
3386 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3387
3388 ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestDepthIndex, &destImage));
3389 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, currentSourceDepthIndex,
3390 &sourceImage));
3391 gl::Box imageBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 1);
3392 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, imageBox, destOffset,
3393 unpackFlipY, unpackPremultiplyAlpha,
3394 unpackUnmultiplyAlpha));
3395 }
3396
3397 mDirtyImages = true;
3398
3399 gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3400 sourceBox.height, sourceBox.depth);
3401 ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3402 }
3403
3404 return angle::Result::Continue;
3405 }
3406
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)3407 angle::Result TextureD3D_2DArray::copySubTexture(const gl::Context *context,
3408 const gl::ImageIndex &index,
3409 const gl::Offset &destOffset,
3410 GLint sourceLevel,
3411 const gl::Box &sourceBox,
3412 bool unpackFlipY,
3413 bool unpackPremultiplyAlpha,
3414 bool unpackUnmultiplyAlpha,
3415 const gl::Texture *source)
3416 {
3417 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3418
3419 gl::ImageIndex destIndex = gl::ImageIndex::Make2DArrayRange(
3420 static_cast<GLint>(index.getLevelIndex()), destOffset.z, sourceBox.depth - destOffset.z);
3421
3422 if (!isSRGB(destIndex.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
3423 {
3424 ANGLE_TRY(ensureRenderTarget(context));
3425 ASSERT(isValidLevel(destIndex.getLevelIndex()));
3426 ANGLE_TRY(updateStorageLevel(context, destIndex.getLevelIndex()));
3427
3428 const gl::InternalFormat &internalFormatInfo =
3429 gl::GetSizedInternalFormatInfo(getInternalFormat(destIndex.getLevelIndex()));
3430 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
3431 sourceBox, internalFormatInfo.format,
3432 internalFormatInfo.type, destOffset, mTexStorage,
3433 index.getTarget(), index.getLevelIndex(), unpackFlipY,
3434 unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
3435 }
3436 else
3437 {
3438 for (int i = 0; i < sourceBox.depth; i++)
3439 {
3440 gl::ImageIndex currentSourceIndex =
3441 gl::ImageIndex::Make2DArray(sourceLevel, i + sourceBox.z);
3442 gl::ImageIndex currentDestIndex =
3443 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i + destOffset.z);
3444
3445 gl::Box currentLayerBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height,
3446 1);
3447
3448 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3449 ImageD3D *sourceImage = nullptr;
3450 ANGLE_TRY(
3451 sourceD3D->getImageAndSyncFromStorage(context, currentSourceIndex, &sourceImage));
3452
3453 ImageD3D *destImage = nullptr;
3454 ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestIndex, &destImage));
3455
3456 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, currentLayerBox,
3457 destOffset, unpackFlipY, unpackPremultiplyAlpha,
3458 unpackUnmultiplyAlpha));
3459 }
3460
3461 mDirtyImages = true;
3462
3463 gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3464 sourceBox.height, sourceBox.depth);
3465 ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3466 }
3467
3468 return angle::Result::Continue;
3469 }
3470
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)3471 angle::Result TextureD3D_2DArray::setStorage(const gl::Context *context,
3472 gl::TextureType type,
3473 size_t levels,
3474 GLenum internalFormat,
3475 const gl::Extents &size)
3476 {
3477 ASSERT(type == gl::TextureType::_2DArray);
3478
3479 deleteImages();
3480
3481 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
3482 {
3483 gl::Extents levelLayerSize(std::max(1, size.width >> level),
3484 std::max(1, size.height >> level), 1);
3485
3486 mLayerCounts[level] = (level < levels ? size.depth : 0);
3487
3488 if (mLayerCounts[level] > 0)
3489 {
3490 // Create new images for this level
3491 mImageArray[level] = new ImageD3D *[mLayerCounts[level]];
3492
3493 for (int layer = 0; layer < mLayerCounts[level]; layer++)
3494 {
3495 mImageArray[level][layer] = mRenderer->createImage();
3496 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalFormat,
3497 levelLayerSize, true);
3498 }
3499 }
3500 }
3501
3502 // TODO(geofflang): Verify storage creation had no errors
3503 bool renderTarget = IsRenderTargetUsage(mState.getUsage());
3504 TexStoragePointer storage(context);
3505 storage.reset(mRenderer->createTextureStorage2DArray(
3506 internalFormat, renderTarget, size.width, size.height, size.depth, static_cast<int>(levels),
3507 mState.getLabel()));
3508
3509 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3510 storage.release();
3511
3512 ANGLE_TRY(updateStorage(context));
3513
3514 mImmutable = true;
3515
3516 return angle::Result::Continue;
3517 }
3518
bindTexImage(const gl::Context * context,egl::Surface * surface)3519 angle::Result TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface)
3520 {
3521 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3522 return angle::Result::Continue;
3523 }
3524
releaseTexImage(const gl::Context * context)3525 angle::Result TextureD3D_2DArray::releaseTexImage(const gl::Context *context)
3526 {
3527 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3528 return angle::Result::Continue;
3529 }
3530
initMipmapImages(const gl::Context * context)3531 angle::Result TextureD3D_2DArray::initMipmapImages(const gl::Context *context)
3532 {
3533 const GLuint baseLevel = mState.getEffectiveBaseLevel();
3534 const GLuint maxLevel = mState.getMipmapMaxLevel();
3535 int baseWidth = getLevelZeroWidth();
3536 int baseHeight = getLevelZeroHeight();
3537 int baseDepth = getLayerCount(getBaseLevel());
3538 GLenum baseFormat = getBaseLevelInternalFormat();
3539
3540 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
3541 // levels.
3542 for (GLuint level = baseLevel + 1u; level <= maxLevel; level++)
3543 {
3544 ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0);
3545 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
3546 std::max(baseHeight >> level, 1), baseDepth);
3547 ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false));
3548 }
3549
3550 return angle::Result::Continue;
3551 }
3552
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)3553 angle::Result TextureD3D_2DArray::getRenderTarget(const gl::Context *context,
3554 const gl::ImageIndex &index,
3555 GLsizei samples,
3556 RenderTargetD3D **outRT)
3557 {
3558 // ensure the underlying texture is created
3559 ANGLE_TRY(ensureRenderTarget(context));
3560 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3561 return mTexStorage->getRenderTarget(context, index, samples, outRT);
3562 }
3563
initializeStorage(const gl::Context * context,bool renderTarget)3564 angle::Result TextureD3D_2DArray::initializeStorage(const gl::Context *context, bool renderTarget)
3565 {
3566 // Only initialize the first time this texture is used as a render target or shader resource
3567 if (mTexStorage)
3568 {
3569 return angle::Result::Continue;
3570 }
3571
3572 // do not attempt to create storage for nonexistant data
3573 if (!isLevelComplete(getBaseLevel()))
3574 {
3575 return angle::Result::Continue;
3576 }
3577
3578 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
3579
3580 TexStoragePointer storage(context);
3581 ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
3582
3583 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3584 storage.release();
3585
3586 ASSERT(mTexStorage);
3587
3588 // flush image data to the storage
3589 ANGLE_TRY(updateStorage(context));
3590
3591 return angle::Result::Continue;
3592 }
3593
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const3594 angle::Result TextureD3D_2DArray::createCompleteStorage(bool renderTarget,
3595 TexStoragePointer *outStorage) const
3596 {
3597 GLsizei width = getLevelZeroWidth();
3598 GLsizei height = getLevelZeroHeight();
3599 GLsizei depth = getLayerCount(getBaseLevel());
3600 GLenum internalFormat = getBaseLevelInternalFormat();
3601
3602 ASSERT(width > 0 && height > 0 && depth > 0);
3603
3604 // use existing storage level count, when previously specified by TexStorage*D
3605 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
3606
3607 // TODO(geofflang): Verify storage creation succeeds
3608 outStorage->reset(mRenderer->createTextureStorage2DArray(
3609 internalFormat, renderTarget, width, height, depth, levels, mState.getLabel()));
3610
3611 return angle::Result::Continue;
3612 }
3613
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)3614 angle::Result TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context,
3615 TextureStorage *newCompleteTexStorage)
3616 {
3617 ANGLE_TRY(releaseTexStorage(context));
3618 mTexStorage = newCompleteTexStorage;
3619 mTexStorageObserverBinding.bind(mTexStorage);
3620 mDirtyImages = true;
3621
3622 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
3623 ASSERT(!mTexStorage->isManaged());
3624
3625 return angle::Result::Continue;
3626 }
3627
updateStorage(const gl::Context * context)3628 angle::Result TextureD3D_2DArray::updateStorage(const gl::Context *context)
3629 {
3630 if (!mDirtyImages)
3631 {
3632 return angle::Result::Continue;
3633 }
3634
3635 ASSERT(mTexStorage != nullptr);
3636 GLint storageLevels = mTexStorage->getLevelCount();
3637 for (int level = 0; level < storageLevels; level++)
3638 {
3639 if (isLevelComplete(level))
3640 {
3641 ANGLE_TRY(updateStorageLevel(context, level));
3642 }
3643 }
3644
3645 mDirtyImages = false;
3646 return angle::Result::Continue;
3647 }
3648
isValidLevel(int level) const3649 bool TextureD3D_2DArray::isValidLevel(int level) const
3650 {
3651 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
3652 }
3653
isLevelComplete(int level) const3654 bool TextureD3D_2DArray::isLevelComplete(int level) const
3655 {
3656 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
3657
3658 if (isImmutable())
3659 {
3660 return true;
3661 }
3662
3663 GLsizei width = getLevelZeroWidth();
3664 GLsizei height = getLevelZeroHeight();
3665
3666 if (width <= 0 || height <= 0)
3667 {
3668 return false;
3669 }
3670
3671 // Layers check needs to happen after the above checks, otherwise out-of-range base level may be
3672 // queried.
3673 GLsizei layers = getLayerCount(getBaseLevel());
3674
3675 if (layers <= 0)
3676 {
3677 return false;
3678 }
3679
3680 if (level == static_cast<int>(getBaseLevel()))
3681 {
3682 return true;
3683 }
3684
3685 if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
3686 {
3687 return false;
3688 }
3689
3690 if (getWidth(level) != std::max(1, width >> level))
3691 {
3692 return false;
3693 }
3694
3695 if (getHeight(level) != std::max(1, height >> level))
3696 {
3697 return false;
3698 }
3699
3700 if (getLayerCount(level) != layers)
3701 {
3702 return false;
3703 }
3704
3705 return true;
3706 }
3707
isImageComplete(const gl::ImageIndex & index) const3708 bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
3709 {
3710 return isLevelComplete(index.getLevelIndex());
3711 }
3712
updateStorageLevel(const gl::Context * context,int level)3713 angle::Result TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level)
3714 {
3715 ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts)));
3716 ASSERT(isLevelComplete(level));
3717
3718 for (int layer = 0; layer < mLayerCounts[level]; layer++)
3719 {
3720 ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr);
3721 if (mImageArray[level][layer]->isDirty())
3722 {
3723 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
3724 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
3725 ANGLE_TRY(commitRegion(context, index, region));
3726 }
3727 }
3728
3729 return angle::Result::Continue;
3730 }
3731
deleteImages()3732 void TextureD3D_2DArray::deleteImages()
3733 {
3734 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3735 {
3736 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
3737 {
3738 delete mImageArray[level][layer];
3739 }
3740 delete[] mImageArray[level];
3741 mImageArray[level] = nullptr;
3742 mLayerCounts[level] = 0;
3743 }
3744 }
3745
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)3746 angle::Result TextureD3D_2DArray::redefineImage(const gl::Context *context,
3747 GLint level,
3748 GLenum internalformat,
3749 const gl::Extents &size,
3750 bool forceRelease)
3751 {
3752 // If there currently is a corresponding storage texture image, it has these parameters
3753 const int storageWidth = std::max(1, getLevelZeroWidth() >> level);
3754 const int storageHeight = std::max(1, getLevelZeroHeight() >> level);
3755 const GLuint baseLevel = getBaseLevel();
3756 const GLenum storageFormat = getBaseLevelInternalFormat();
3757
3758 int storageDepth = 0;
3759 if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3760 {
3761 storageDepth = getLayerCount(baseLevel);
3762 }
3763
3764 // Only reallocate the layers if the size doesn't match
3765 if (size.depth != mLayerCounts[level])
3766 {
3767 for (int layer = 0; layer < mLayerCounts[level]; layer++)
3768 {
3769 SafeDelete(mImageArray[level][layer]);
3770 }
3771 SafeDeleteArray(mImageArray[level]);
3772 mLayerCounts[level] = size.depth;
3773
3774 if (size.depth > 0)
3775 {
3776 mImageArray[level] = new ImageD3D *[size.depth];
3777 for (int layer = 0; layer < mLayerCounts[level]; layer++)
3778 {
3779 mImageArray[level][layer] = mRenderer->createImage();
3780 }
3781 }
3782 }
3783
3784 if (size.depth > 0)
3785 {
3786 for (int layer = 0; layer < mLayerCounts[level]; layer++)
3787 {
3788 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalformat,
3789 gl::Extents(size.width, size.height, 1),
3790 forceRelease);
3791 mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty();
3792 }
3793 }
3794
3795 if (mTexStorage)
3796 {
3797 const int storageLevels = mTexStorage->getLevelCount();
3798
3799 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3800 size.height != storageHeight || size.depth != storageDepth ||
3801 internalformat != storageFormat) // Discard mismatched storage
3802 {
3803 markAllImagesDirty();
3804 ANGLE_TRY(releaseTexStorage(context));
3805 }
3806 }
3807
3808 return angle::Result::Continue;
3809 }
3810
imageIterator() const3811 gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
3812 {
3813 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
3814 }
3815
getImageIndex(GLint mip,GLint layer) const3816 gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
3817 {
3818 return gl::ImageIndex::Make2DArray(mip, layer);
3819 }
3820
isValidIndex(const gl::ImageIndex & index) const3821 bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
3822 {
3823 // Check for having a storage and the right type of index
3824 if (!mTexStorage || index.getType() != gl::TextureType::_2DArray)
3825 {
3826 return false;
3827 }
3828
3829 // Check the mip index
3830 if (index.getLevelIndex() < 0 || index.getLevelIndex() >= mTexStorage->getLevelCount())
3831 {
3832 return false;
3833 }
3834
3835 // Check the layer index
3836 return (!index.hasLayer() || (index.getLayerIndex() >= 0 &&
3837 index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]));
3838 }
3839
markAllImagesDirty()3840 void TextureD3D_2DArray::markAllImagesDirty()
3841 {
3842 for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
3843 {
3844 for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
3845 {
3846 mImageArray[dirtyLevel][dirtyLayer]->markDirty();
3847 }
3848 }
3849 mDirtyImages = true;
3850 }
3851
TextureD3DImmutableBase(const gl::TextureState & state,RendererD3D * renderer)3852 TextureD3DImmutableBase::TextureD3DImmutableBase(const gl::TextureState &state,
3853 RendererD3D *renderer)
3854 : TextureD3D(state, renderer)
3855 {}
3856
~TextureD3DImmutableBase()3857 TextureD3DImmutableBase::~TextureD3DImmutableBase() {}
3858
getImage(const gl::ImageIndex & index) const3859 ImageD3D *TextureD3DImmutableBase::getImage(const gl::ImageIndex &index) const
3860 {
3861 return nullptr;
3862 }
3863
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3864 angle::Result TextureD3DImmutableBase::setImage(const gl::Context *context,
3865 const gl::ImageIndex &index,
3866 GLenum internalFormat,
3867 const gl::Extents &size,
3868 GLenum format,
3869 GLenum type,
3870 const gl::PixelUnpackState &unpack,
3871 gl::Buffer *unpackBuffer,
3872 const uint8_t *pixels)
3873 {
3874 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3875 return angle::Result::Continue;
3876 }
3877
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3878 angle::Result TextureD3DImmutableBase::setSubImage(const gl::Context *context,
3879 const gl::ImageIndex &index,
3880 const gl::Box &area,
3881 GLenum format,
3882 GLenum type,
3883 const gl::PixelUnpackState &unpack,
3884 gl::Buffer *unpackBuffer,
3885 const uint8_t *pixels)
3886 {
3887 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3888 return angle::Result::Continue;
3889 }
3890
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3891 angle::Result TextureD3DImmutableBase::setCompressedImage(const gl::Context *context,
3892 const gl::ImageIndex &index,
3893 GLenum internalFormat,
3894 const gl::Extents &size,
3895 const gl::PixelUnpackState &unpack,
3896 size_t imageSize,
3897 const uint8_t *pixels)
3898 {
3899 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3900 return angle::Result::Continue;
3901 }
3902
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3903 angle::Result TextureD3DImmutableBase::setCompressedSubImage(const gl::Context *context,
3904 const gl::ImageIndex &index,
3905 const gl::Box &area,
3906 GLenum format,
3907 const gl::PixelUnpackState &unpack,
3908 size_t imageSize,
3909 const uint8_t *pixels)
3910 {
3911 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3912 return angle::Result::Continue;
3913 }
3914
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3915 angle::Result TextureD3DImmutableBase::copyImage(const gl::Context *context,
3916 const gl::ImageIndex &index,
3917 const gl::Rectangle &sourceArea,
3918 GLenum internalFormat,
3919 gl::Framebuffer *source)
3920 {
3921 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3922 return angle::Result::Continue;
3923 }
3924
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3925 angle::Result TextureD3DImmutableBase::copySubImage(const gl::Context *context,
3926 const gl::ImageIndex &index,
3927 const gl::Offset &destOffset,
3928 const gl::Rectangle &sourceArea,
3929 gl::Framebuffer *source)
3930 {
3931 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3932 return angle::Result::Continue;
3933 }
3934
bindTexImage(const gl::Context * context,egl::Surface * surface)3935 angle::Result TextureD3DImmutableBase::bindTexImage(const gl::Context *context,
3936 egl::Surface *surface)
3937 {
3938 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3939 return angle::Result::Continue;
3940 }
3941
releaseTexImage(const gl::Context * context)3942 angle::Result TextureD3DImmutableBase::releaseTexImage(const gl::Context *context)
3943 {
3944 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3945 return angle::Result::Continue;
3946 }
3947
TextureD3D_External(const gl::TextureState & state,RendererD3D * renderer)3948 TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer)
3949 : TextureD3DImmutableBase(state, renderer)
3950 {}
3951
~TextureD3D_External()3952 TextureD3D_External::~TextureD3D_External() {}
3953
getLayerCount(int level) const3954 GLsizei TextureD3D_External::getLayerCount(int level) const
3955 {
3956 return 1;
3957 }
3958
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)3959 angle::Result TextureD3D_External::setImageExternal(const gl::Context *context,
3960 gl::TextureType type,
3961 egl::Stream *stream,
3962 const egl::Stream::GLTextureDescription &desc)
3963 {
3964 ASSERT(type == gl::TextureType::External);
3965
3966 ANGLE_TRY(releaseTexStorage(context));
3967
3968 // If the stream is null, the external image is unbound and we release the storage
3969 if (stream != nullptr)
3970 {
3971 mTexStorage = mRenderer->createTextureStorageExternal(stream, desc, mState.getLabel());
3972 }
3973
3974 return angle::Result::Continue;
3975 }
3976
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3977 angle::Result TextureD3D_External::setEGLImageTarget(const gl::Context *context,
3978 gl::TextureType type,
3979 egl::Image *image)
3980 {
3981 EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
3982
3983 // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
3984 RenderTargetD3D *renderTargetD3D = nullptr;
3985 ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
3986
3987 ANGLE_TRY(releaseTexStorage(context));
3988 mTexStorage =
3989 mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
3990
3991 return angle::Result::Continue;
3992 }
3993
initMipmapImages(const gl::Context * context)3994 angle::Result TextureD3D_External::initMipmapImages(const gl::Context *context)
3995 {
3996 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3997 return angle::Result::Stop;
3998 }
3999
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4000 angle::Result TextureD3D_External::getRenderTarget(const gl::Context *context,
4001 const gl::ImageIndex &index,
4002 GLsizei samples,
4003 RenderTargetD3D **outRT)
4004 {
4005 UNREACHABLE();
4006 return angle::Result::Stop;
4007 }
4008
isImageComplete(const gl::ImageIndex & index) const4009 bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const
4010 {
4011 return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
4012 }
4013
initializeStorage(const gl::Context * context,bool renderTarget)4014 angle::Result TextureD3D_External::initializeStorage(const gl::Context *context, bool renderTarget)
4015 {
4016 // Texture storage is created when an external image is bound
4017 ASSERT(mTexStorage);
4018 return angle::Result::Continue;
4019 }
4020
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4021 angle::Result TextureD3D_External::createCompleteStorage(bool renderTarget,
4022 TexStoragePointer *outStorage) const
4023 {
4024 UNREACHABLE();
4025 return angle::Result::Continue;
4026 }
4027
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4028 angle::Result TextureD3D_External::setCompleteTexStorage(const gl::Context *context,
4029 TextureStorage *newCompleteTexStorage)
4030 {
4031 UNREACHABLE();
4032 return angle::Result::Continue;
4033 }
4034
updateStorage(const gl::Context * context)4035 angle::Result TextureD3D_External::updateStorage(const gl::Context *context)
4036 {
4037 // Texture storage does not need to be updated since it is already loaded with the latest
4038 // external image
4039 ASSERT(mTexStorage);
4040 return angle::Result::Continue;
4041 }
4042
imageIterator() const4043 gl::ImageIndexIterator TextureD3D_External::imageIterator() const
4044 {
4045 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
4046 }
4047
getImageIndex(GLint mip,GLint) const4048 gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const
4049 {
4050 // "layer" does not apply to 2D Textures.
4051 return gl::ImageIndex::Make2D(mip);
4052 }
4053
isValidIndex(const gl::ImageIndex & index) const4054 bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
4055 {
4056 return (mTexStorage && index.getType() == gl::TextureType::External &&
4057 index.getLevelIndex() == 0);
4058 }
4059
markAllImagesDirty()4060 void TextureD3D_External::markAllImagesDirty()
4061 {
4062 UNREACHABLE();
4063 }
4064
TextureD3D_2DMultisample(const gl::TextureState & state,RendererD3D * renderer)4065 TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state,
4066 RendererD3D *renderer)
4067 : TextureD3DImmutableBase(state, renderer)
4068 {}
4069
~TextureD3D_2DMultisample()4070 TextureD3D_2DMultisample::~TextureD3D_2DMultisample() {}
4071
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4072 angle::Result TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context,
4073 gl::TextureType type,
4074 GLsizei samples,
4075 GLint internalformat,
4076 const gl::Extents &size,
4077 bool fixedSampleLocations)
4078 {
4079 ASSERT(type == gl::TextureType::_2DMultisample && size.depth == 1);
4080
4081 // We allocate storage immediately instead of doing it lazily like other TextureD3D classes do.
4082 // This requires less state in this class.
4083 TexStoragePointer storage(context);
4084 storage.reset(mRenderer->createTextureStorage2DMultisample(
4085 internalformat, size.width, size.height, static_cast<int>(0), samples, fixedSampleLocations,
4086 mState.getLabel()));
4087
4088 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4089 storage.release();
4090
4091 mImmutable = true;
4092
4093 return angle::Result::Continue;
4094 }
4095
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4096 angle::Result TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context,
4097 gl::TextureType type,
4098 egl::Image *image)
4099 {
4100 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4101 return angle::Result::Continue;
4102 }
4103
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4104 angle::Result TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context,
4105 const gl::ImageIndex &index,
4106 GLsizei samples,
4107 RenderTargetD3D **outRT)
4108 {
4109 ASSERT(!index.hasLayer());
4110
4111 // ensure the underlying texture is created
4112 ANGLE_TRY(ensureRenderTarget(context));
4113
4114 return mTexStorage->getRenderTarget(context, index, samples, outRT);
4115 }
4116
imageIterator() const4117 gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const
4118 {
4119 return gl::ImageIndexIterator::Make2DMultisample();
4120 }
4121
getImageIndex(GLint mip,GLint layer) const4122 gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const
4123 {
4124 return gl::ImageIndex::Make2DMultisample();
4125 }
4126
isValidIndex(const gl::ImageIndex & index) const4127 bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const
4128 {
4129 return (mTexStorage && index.getType() == gl::TextureType::_2DMultisample &&
4130 index.getLevelIndex() == 0);
4131 }
4132
getLayerCount(int level) const4133 GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const
4134 {
4135 return 1;
4136 }
4137
markAllImagesDirty()4138 void TextureD3D_2DMultisample::markAllImagesDirty() {}
4139
initializeStorage(const gl::Context * context,bool renderTarget)4140 angle::Result TextureD3D_2DMultisample::initializeStorage(const gl::Context *context,
4141 bool renderTarget)
4142 {
4143 // initializeStorage should only be called in a situation where the texture already has storage
4144 // associated with it (storage is created in setStorageMultisample).
4145 ASSERT(mTexStorage);
4146 return angle::Result::Continue;
4147 }
4148
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4149 angle::Result TextureD3D_2DMultisample::createCompleteStorage(bool renderTarget,
4150 TexStoragePointer *outStorage) const
4151 {
4152 UNREACHABLE();
4153 outStorage->reset(mTexStorage);
4154 return angle::Result::Continue;
4155 }
4156
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4157 angle::Result TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context,
4158 TextureStorage *newCompleteTexStorage)
4159 {
4160 // These textures are immutable, so this should only be ever called once.
4161 ASSERT(!mTexStorage);
4162 mTexStorage = newCompleteTexStorage;
4163 mTexStorageObserverBinding.bind(mTexStorage);
4164 return angle::Result::Continue;
4165 }
4166
updateStorage(const gl::Context * context)4167 angle::Result TextureD3D_2DMultisample::updateStorage(const gl::Context *context)
4168 {
4169 return angle::Result::Continue;
4170 }
4171
initMipmapImages(const gl::Context * context)4172 angle::Result TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context)
4173 {
4174 UNREACHABLE();
4175 return angle::Result::Continue;
4176 }
4177
isImageComplete(const gl::ImageIndex & index) const4178 bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const
4179 {
4180 return true;
4181 }
4182
TextureD3D_2DMultisampleArray(const gl::TextureState & state,RendererD3D * renderer)4183 TextureD3D_2DMultisampleArray::TextureD3D_2DMultisampleArray(const gl::TextureState &state,
4184 RendererD3D *renderer)
4185 : TextureD3DImmutableBase(state, renderer)
4186 {}
4187
~TextureD3D_2DMultisampleArray()4188 TextureD3D_2DMultisampleArray::~TextureD3D_2DMultisampleArray() {}
4189
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4190 angle::Result TextureD3D_2DMultisampleArray::setStorageMultisample(const gl::Context *context,
4191 gl::TextureType type,
4192 GLsizei samples,
4193 GLint internalformat,
4194 const gl::Extents &size,
4195 bool fixedSampleLocations)
4196 {
4197 ASSERT(type == gl::TextureType::_2DMultisampleArray);
4198
4199 mLayerCount = size.depth;
4200
4201 TexStoragePointer storage(context);
4202 storage.reset(mRenderer->createTextureStorage2DMultisampleArray(
4203 internalformat, size.width, size.height, size.depth, static_cast<int>(0), samples,
4204 fixedSampleLocations, mState.getLabel()));
4205
4206 ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4207 storage.release();
4208
4209 mImmutable = true;
4210
4211 return angle::Result::Continue;
4212 }
4213
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4214 angle::Result TextureD3D_2DMultisampleArray::setEGLImageTarget(const gl::Context *context,
4215 gl::TextureType type,
4216 egl::Image *image)
4217 {
4218 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4219 return angle::Result::Continue;
4220 }
4221
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4222 angle::Result TextureD3D_2DMultisampleArray::getRenderTarget(const gl::Context *context,
4223 const gl::ImageIndex &index,
4224 GLsizei samples,
4225 RenderTargetD3D **outRT)
4226 {
4227 // ensure the underlying texture is created
4228 ANGLE_TRY(ensureRenderTarget(context));
4229
4230 return mTexStorage->getRenderTarget(context, index, samples, outRT);
4231 }
4232
imageIterator() const4233 gl::ImageIndexIterator TextureD3D_2DMultisampleArray::imageIterator() const
4234 {
4235 return gl::ImageIndexIterator::Make2DMultisampleArray(&mLayerCount);
4236 }
4237
getImageIndex(GLint mip,GLint layer) const4238 gl::ImageIndex TextureD3D_2DMultisampleArray::getImageIndex(GLint mip, GLint layer) const
4239 {
4240 return gl::ImageIndex::Make2DMultisampleArray(layer);
4241 }
4242
isValidIndex(const gl::ImageIndex & index) const4243 bool TextureD3D_2DMultisampleArray::isValidIndex(const gl::ImageIndex &index) const
4244 {
4245 return (mTexStorage && index.getType() == gl::TextureType::_2DMultisampleArray &&
4246 index.getLevelIndex() == 0);
4247 }
4248
getLayerCount(int level) const4249 GLsizei TextureD3D_2DMultisampleArray::getLayerCount(int level) const
4250 {
4251 return mLayerCount;
4252 }
4253
markAllImagesDirty()4254 void TextureD3D_2DMultisampleArray::markAllImagesDirty() {}
4255
initializeStorage(const gl::Context * context,bool renderTarget)4256 angle::Result TextureD3D_2DMultisampleArray::initializeStorage(const gl::Context *context,
4257 bool renderTarget)
4258 {
4259 // initializeStorage should only be called in a situation where the texture already has storage
4260 // associated with it (storage is created in setStorageMultisample).
4261 ASSERT(mTexStorage);
4262 return angle::Result::Continue;
4263 }
4264
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4265 angle::Result TextureD3D_2DMultisampleArray::createCompleteStorage(
4266 bool renderTarget,
4267 TexStoragePointer *outStorage) const
4268 {
4269 UNREACHABLE();
4270 outStorage->reset(mTexStorage);
4271 return angle::Result::Continue;
4272 }
4273
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4274 angle::Result TextureD3D_2DMultisampleArray::setCompleteTexStorage(
4275 const gl::Context *context,
4276 TextureStorage *newCompleteTexStorage)
4277 {
4278 // These textures are immutable, so this should only be ever called once.
4279 ASSERT(!mTexStorage);
4280 mTexStorage = newCompleteTexStorage;
4281 mTexStorageObserverBinding.bind(mTexStorage);
4282 return angle::Result::Continue;
4283 }
4284
updateStorage(const gl::Context * context)4285 angle::Result TextureD3D_2DMultisampleArray::updateStorage(const gl::Context *context)
4286 {
4287 return angle::Result::Continue;
4288 }
4289
initMipmapImages(const gl::Context * context)4290 angle::Result TextureD3D_2DMultisampleArray::initMipmapImages(const gl::Context *context)
4291 {
4292 UNIMPLEMENTED();
4293 return angle::Result::Continue;
4294 }
4295
isImageComplete(const gl::ImageIndex & index) const4296 bool TextureD3D_2DMultisampleArray::isImageComplete(const gl::ImageIndex &index) const
4297 {
4298 return true;
4299 }
4300
4301 } // namespace rx
4302