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