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