• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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))
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(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, internalFormat,
1172                                              destOffset, mTexStorage, index.getLevelIndex()));
1173         }
1174     }
1175 
1176     return angle::Result::Continue;
1177 }
1178 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1179 angle::Result TextureD3D_2D::copySubImage(const gl::Context *context,
1180                                           const gl::ImageIndex &index,
1181                                           const gl::Offset &destOffset,
1182                                           const gl::Rectangle &sourceArea,
1183                                           gl::Framebuffer *source)
1184 {
1185     ASSERT(index.getTarget() == gl::TextureTarget::_2D && destOffset.z == 0);
1186 
1187     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1188     gl::Rectangle clippedArea;
1189     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1190     {
1191         return angle::Result::Continue;
1192     }
1193     const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1194                                    destOffset.y + clippedArea.y - sourceArea.y, 0);
1195 
1196     // can only make our texture storage to a render target if level 0 is defined (with a width &
1197     // height) and the current level we're copying to is defined (with appropriate format, width &
1198     // height)
1199 
1200     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1201     // framebuffer in shaders, so we should use the non-rendering copy path.
1202     if (!canCreateRenderTargetForImage(index) ||
1203         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1204     {
1205         ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedOffset,
1206                                                                           clippedArea, source));
1207         mDirtyImages = true;
1208         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1209     }
1210     else
1211     {
1212         ANGLE_TRY(ensureRenderTarget(context));
1213 
1214         if (isValidLevel(index.getLevelIndex()))
1215         {
1216             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1217             ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea,
1218                                              gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1219                                              clippedOffset, mTexStorage, index.getLevelIndex()));
1220         }
1221     }
1222 
1223     return angle::Result::Continue;
1224 }
1225 
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)1226 angle::Result TextureD3D_2D::copyTexture(const gl::Context *context,
1227                                          const gl::ImageIndex &index,
1228                                          GLenum internalFormat,
1229                                          GLenum type,
1230                                          GLint sourceLevel,
1231                                          bool unpackFlipY,
1232                                          bool unpackPremultiplyAlpha,
1233                                          bool unpackUnmultiplyAlpha,
1234                                          const gl::Texture *source)
1235 {
1236     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1237 
1238     gl::TextureType sourceType = source->getType();
1239 
1240     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1241     gl::Extents size(
1242         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1243         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1244         1);
1245     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
1246                             size, false));
1247 
1248     gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1249     gl::Offset destOffset(0, 0, 0);
1250 
1251     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1252     {
1253         ANGLE_TRY(ensureRenderTarget(context));
1254         ASSERT(isValidLevel(index.getLevelIndex()));
1255         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1256 
1257         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1258                                          sourceBox, internalFormatInfo.format,
1259                                          internalFormatInfo.type, destOffset, mTexStorage,
1260                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
1261                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1262     }
1263     else
1264     {
1265         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1266         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1267         ImageD3D *sourceImage           = nullptr;
1268         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1269 
1270         ImageD3D *destImage = nullptr;
1271         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1272 
1273         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1274                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1275 
1276         mDirtyImages = true;
1277 
1278         gl::Box destRegion(destOffset, size);
1279         ANGLE_TRY(commitRegion(context, index, destRegion));
1280     }
1281 
1282     return angle::Result::Continue;
1283 }
1284 
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)1285 angle::Result TextureD3D_2D::copySubTexture(const gl::Context *context,
1286                                             const gl::ImageIndex &index,
1287                                             const gl::Offset &destOffset,
1288                                             GLint sourceLevel,
1289                                             const gl::Box &sourceBox,
1290                                             bool unpackFlipY,
1291                                             bool unpackPremultiplyAlpha,
1292                                             bool unpackUnmultiplyAlpha,
1293                                             const gl::Texture *source)
1294 {
1295     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1296 
1297     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1298     {
1299         ANGLE_TRY(ensureRenderTarget(context));
1300         ASSERT(isValidLevel(index.getLevelIndex()));
1301         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1302 
1303         const gl::InternalFormat &internalFormatInfo =
1304             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
1305         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1306                                          sourceBox, internalFormatInfo.format,
1307                                          internalFormatInfo.type, destOffset, mTexStorage,
1308                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
1309                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1310     }
1311     else
1312     {
1313         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1314         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1315         ImageD3D *sourceImage           = nullptr;
1316         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1317 
1318         ImageD3D *destImage = nullptr;
1319         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1320 
1321         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1322                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1323 
1324         mDirtyImages = true;
1325 
1326         gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
1327         ANGLE_TRY(commitRegion(context, index, destRegion));
1328     }
1329 
1330     return angle::Result::Continue;
1331 }
1332 
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)1333 angle::Result TextureD3D_2D::copyCompressedTexture(const gl::Context *context,
1334                                                    const gl::Texture *source)
1335 {
1336     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1337     GLint sourceLevel              = 0;
1338 
1339     GLint destLevel = 0;
1340 
1341     GLenum sizedInternalFormat =
1342         source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat;
1343     gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1344                      static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1345     ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false));
1346 
1347     ANGLE_TRY(initializeStorage(context, BindFlags()));
1348     ASSERT(mTexStorage);
1349 
1350     ANGLE_TRY(
1351         mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel));
1352 
1353     return angle::Result::Continue;
1354 }
1355 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1356 angle::Result TextureD3D_2D::setStorage(const gl::Context *context,
1357                                         gl::TextureType type,
1358                                         size_t levels,
1359                                         GLenum internalFormat,
1360                                         const gl::Extents &size)
1361 {
1362     ASSERT(type == gl::TextureType::_2D && size.depth == 1);
1363 
1364     for (size_t level = 0; level < levels; level++)
1365     {
1366         gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
1367                               1);
1368         ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true));
1369     }
1370 
1371     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1372     {
1373         ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1374     }
1375 
1376     // TODO(geofflang): Verify storage creation had no errors
1377     BindFlags flags;
1378     flags.renderTarget        = IsRenderTargetUsage(mState.getUsage());
1379     TexStoragePointer storage = {
1380         mRenderer->createTextureStorage2D(internalFormat, flags, size.width, size.height,
1381                                           static_cast<int>(levels), mState.getLabel(), false),
1382         context};
1383 
1384     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1385     storage.release();
1386 
1387     ANGLE_TRY(updateStorage(context));
1388 
1389     mImmutable = true;
1390 
1391     return angle::Result::Continue;
1392 }
1393 
bindTexImage(const gl::Context * context,egl::Surface * surface)1394 angle::Result TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface)
1395 {
1396     GLenum internalformat = surface->getConfig()->renderTargetFormat;
1397 
1398     gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
1399     ANGLE_TRY(redefineImage(context, 0, internalformat, size, true));
1400 
1401     ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
1402 
1403     SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
1404     ASSERT(surfaceD3D);
1405 
1406     mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain(), mState.getLabel());
1407     mEGLImageTarget = false;
1408 
1409     mDirtyImages = false;
1410     mImageArray[0]->markClean();
1411 
1412     return angle::Result::Continue;
1413 }
1414 
releaseTexImage(const gl::Context * context)1415 angle::Result TextureD3D_2D::releaseTexImage(const gl::Context *context)
1416 {
1417     if (mTexStorage)
1418     {
1419         ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
1420     }
1421 
1422     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1423     {
1424         ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true));
1425     }
1426 
1427     return angle::Result::Continue;
1428 }
1429 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1430 angle::Result TextureD3D_2D::setEGLImageTarget(const gl::Context *context,
1431                                                gl::TextureType type,
1432                                                egl::Image *image)
1433 {
1434     EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
1435 
1436     // Set the properties of the base mip level from the EGL image
1437     const auto &format = image->getFormat();
1438     gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1);
1439     ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true));
1440 
1441     // Clear all other images.
1442     for (size_t level = 1; level < mImageArray.size(); level++)
1443     {
1444         ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1445     }
1446 
1447     ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
1448     mImageArray[0]->markClean();
1449 
1450     // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
1451     RenderTargetD3D *renderTargetD3D = nullptr;
1452     ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
1453 
1454     mTexStorage =
1455         mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
1456     mEGLImageTarget = true;
1457 
1458     return angle::Result::Continue;
1459 }
1460 
initMipmapImages(const gl::Context * context)1461 angle::Result TextureD3D_2D::initMipmapImages(const gl::Context *context)
1462 {
1463     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1464     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1465     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
1466     // levels.
1467     for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
1468     {
1469         gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
1470                               std::max(getLevelZeroHeight() >> level, 1), 1);
1471 
1472         ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
1473     }
1474 
1475     // We should be mip-complete now so generate the storage.
1476     ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
1477 
1478     return angle::Result::Continue;
1479 }
1480 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)1481 angle::Result TextureD3D_2D::getRenderTarget(const gl::Context *context,
1482                                              const gl::ImageIndex &index,
1483                                              GLsizei samples,
1484                                              RenderTargetD3D **outRT)
1485 {
1486     ASSERT(!index.hasLayer());
1487 
1488     // ensure the underlying texture is created
1489     ANGLE_TRY(ensureRenderTarget(context));
1490     ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1491 
1492     return mTexStorage->getRenderTarget(context, index, samples, outRT);
1493 }
1494 
isValidLevel(int level) const1495 bool TextureD3D_2D::isValidLevel(int level) const
1496 {
1497     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1498 }
1499 
isLevelComplete(int level) const1500 bool TextureD3D_2D::isLevelComplete(int level) const
1501 {
1502     if (isImmutable())
1503     {
1504         return true;
1505     }
1506 
1507     GLsizei width  = getLevelZeroWidth();
1508     GLsizei height = getLevelZeroHeight();
1509 
1510     if (width <= 0 || height <= 0)
1511     {
1512         return false;
1513     }
1514 
1515     // The base image level is complete if the width and height are positive
1516     if (level == static_cast<int>(getBaseLevel()))
1517     {
1518         return true;
1519     }
1520 
1521     ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) &&
1522            mImageArray[level] != nullptr);
1523     ImageD3D *image = mImageArray[level].get();
1524 
1525     if (image->getInternalFormat() != getBaseLevelInternalFormat())
1526     {
1527         return false;
1528     }
1529 
1530     if (image->getWidth() != std::max(1, width >> level))
1531     {
1532         return false;
1533     }
1534 
1535     if (image->getHeight() != std::max(1, height >> level))
1536     {
1537         return false;
1538     }
1539 
1540     return true;
1541 }
1542 
isImageComplete(const gl::ImageIndex & index) const1543 bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
1544 {
1545     return isLevelComplete(index.getLevelIndex());
1546 }
1547 
1548 // Constructs a native texture resource from the texture images
initializeStorage(const gl::Context * context,BindFlags bindFlags)1549 angle::Result TextureD3D_2D::initializeStorage(const gl::Context *context, BindFlags bindFlags)
1550 {
1551     // Only initialize the first time this texture is used as a render target or shader resource
1552     if (mTexStorage)
1553     {
1554         return angle::Result::Continue;
1555     }
1556 
1557     // do not attempt to create storage for nonexistant data
1558     if (!isLevelComplete(getBaseLevel()))
1559     {
1560         return angle::Result::Continue;
1561     }
1562 
1563     bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage());
1564 
1565     TexStoragePointer storage;
1566     ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
1567 
1568     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1569     storage.release();
1570 
1571     ASSERT(mTexStorage);
1572 
1573     // flush image data to the storage
1574     ANGLE_TRY(updateStorage(context));
1575 
1576     return angle::Result::Continue;
1577 }
1578 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const1579 angle::Result TextureD3D_2D::createCompleteStorage(const gl::Context *context,
1580                                                    BindFlags bindFlags,
1581                                                    TexStoragePointer *outStorage) const
1582 {
1583     GLsizei width         = getLevelZeroWidth();
1584     GLsizei height        = getLevelZeroHeight();
1585     GLenum internalFormat = getBaseLevelInternalFormat();
1586 
1587     ASSERT(width > 0 && height > 0);
1588 
1589     // use existing storage level count, when previously specified by TexStorage*D
1590     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1591 
1592     bool hintLevelZeroOnly = false;
1593     if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1594     {
1595         // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use
1596         // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
1597         hintLevelZeroOnly = true;
1598         for (int level = 1; level < levels && hintLevelZeroOnly; level++)
1599         {
1600             hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
1601         }
1602     }
1603 
1604     // TODO(geofflang): Determine if the texture creation succeeded
1605     *outStorage = {mRenderer->createTextureStorage2D(internalFormat, bindFlags, width, height,
1606                                                      levels, mState.getLabel(), hintLevelZeroOnly),
1607                    context};
1608 
1609     return angle::Result::Continue;
1610 }
1611 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)1612 angle::Result TextureD3D_2D::setCompleteTexStorage(const gl::Context *context,
1613                                                    TextureStorage *newCompleteTexStorage)
1614 {
1615     if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
1616     {
1617         for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
1618         {
1619             ANGLE_TRY(
1620                 mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level));
1621         }
1622     }
1623 
1624     gl::TexLevelMask copyImageMask;
1625     copyImageMask.set();
1626 
1627     ANGLE_TRY(releaseTexStorage(context, copyImageMask));
1628     mTexStorage = newCompleteTexStorage;
1629     mTexStorageObserverBinding.bind(mTexStorage);
1630 
1631     mDirtyImages = true;
1632 
1633     return angle::Result::Continue;
1634 }
1635 
updateStorage(const gl::Context * context)1636 angle::Result TextureD3D_2D::updateStorage(const gl::Context *context)
1637 {
1638     if (!mDirtyImages)
1639     {
1640         return angle::Result::Continue;
1641     }
1642 
1643     ASSERT(mTexStorage != nullptr);
1644     GLint storageLevels = mTexStorage->getLevelCount();
1645     for (int level = 0; level < storageLevels; level++)
1646     {
1647         if (mImageArray[level]->isDirty() && isLevelComplete(level))
1648         {
1649             ANGLE_TRY(updateStorageLevel(context, level));
1650         }
1651     }
1652 
1653     mDirtyImages = false;
1654     return angle::Result::Continue;
1655 }
1656 
updateStorageLevel(const gl::Context * context,int level)1657 angle::Result TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level)
1658 {
1659     ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr);
1660     ASSERT(isLevelComplete(level));
1661 
1662     if (mImageArray[level]->isDirty())
1663     {
1664         gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1665         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
1666         ANGLE_TRY(commitRegion(context, index, region));
1667     }
1668 
1669     return angle::Result::Continue;
1670 }
1671 
redefineImage(const gl::Context * context,size_t level,GLenum internalformat,const gl::Extents & size,bool forceRelease)1672 angle::Result TextureD3D_2D::redefineImage(const gl::Context *context,
1673                                            size_t level,
1674                                            GLenum internalformat,
1675                                            const gl::Extents &size,
1676                                            bool forceRelease)
1677 {
1678     ASSERT(size.depth == 1);
1679 
1680     // If there currently is a corresponding storage texture image, it has these parameters
1681     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
1682     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
1683     const GLenum storageFormat = getBaseLevelInternalFormat();
1684 
1685     if (mTexStorage)
1686     {
1687         const size_t storageLevels = mTexStorage->getLevelCount();
1688 
1689         // If the storage was from an EGL image, copy it back into local images to preserve it
1690         // while orphaning
1691         if (level != 0 && mEGLImageTarget)
1692         {
1693             ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0),
1694                                                          mTexStorage));
1695         }
1696 
1697         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
1698             size.height != storageHeight || internalformat != storageFormat ||
1699             mEGLImageTarget)  // Discard mismatched storage
1700         {
1701             gl::TexLevelMask copyImageMask;
1702             copyImageMask.set();
1703             copyImageMask.set(level, false);
1704 
1705             ANGLE_TRY(releaseTexStorage(context, copyImageMask));
1706             markAllImagesDirty();
1707         }
1708     }
1709 
1710     mImageArray[level]->redefine(gl::TextureType::_2D, internalformat, size, forceRelease);
1711     mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
1712 
1713     // Can't be an EGL image target after being redefined
1714     mEGLImageTarget = false;
1715 
1716     return angle::Result::Continue;
1717 }
1718 
imageIterator() const1719 gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1720 {
1721     return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1722 }
1723 
getImageIndex(GLint mip,GLint) const1724 gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1725 {
1726     // "layer" does not apply to 2D Textures.
1727     return gl::ImageIndex::Make2D(mip);
1728 }
1729 
isValidIndex(const gl::ImageIndex & index) const1730 bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1731 {
1732     return (mTexStorage && index.getType() == gl::TextureType::_2D && index.getLevelIndex() >= 0 &&
1733             index.getLevelIndex() < mTexStorage->getLevelCount());
1734 }
1735 
markAllImagesDirty()1736 void TextureD3D_2D::markAllImagesDirty()
1737 {
1738     for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1739     {
1740         mImageArray[i]->markDirty();
1741     }
1742     mDirtyImages = true;
1743 }
1744 
TextureD3D_Cube(const gl::TextureState & state,RendererD3D * renderer)1745 TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer)
1746     : TextureD3D(state, renderer)
1747 {
1748     for (auto &face : mImageArray)
1749     {
1750         for (auto &image : face)
1751         {
1752             image.reset(renderer->createImage());
1753         }
1754     }
1755 }
1756 
onDestroy(const gl::Context * context)1757 void TextureD3D_Cube::onDestroy(const gl::Context *context)
1758 {
1759     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
1760     // for some of their data. If TextureStorage is deleted before the Images, then their data will
1761     // be wastefully copied back from the GPU before we delete the Images.
1762     for (auto &face : mImageArray)
1763     {
1764         for (auto &image : face)
1765         {
1766             image.reset();
1767         }
1768     }
1769     return TextureD3D::onDestroy(context);
1770 }
1771 
~TextureD3D_Cube()1772 TextureD3D_Cube::~TextureD3D_Cube() {}
1773 
getImage(int level,int layer) const1774 ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
1775 {
1776     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1777     ASSERT(layer >= 0 && static_cast<size_t>(layer) < gl::kCubeFaceCount);
1778     return mImageArray[layer][level].get();
1779 }
1780 
getImage(const gl::ImageIndex & index) const1781 ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1782 {
1783     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1784     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1785     return mImageArray[index.cubeMapFaceIndex()][index.getLevelIndex()].get();
1786 }
1787 
getLayerCount(int level) const1788 GLsizei TextureD3D_Cube::getLayerCount(int level) const
1789 {
1790     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1791     return gl::kCubeFaceCount;
1792 }
1793 
getInternalFormat(GLint level,GLint layer) const1794 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
1795 {
1796     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1797         return mImageArray[layer][level]->getInternalFormat();
1798     else
1799         return GL_NONE;
1800 }
1801 
isDepth(GLint level,GLint layer) const1802 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
1803 {
1804     return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
1805 }
1806 
isSRGB(GLint level,GLint layer) const1807 bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const
1808 {
1809     return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB;
1810 }
1811 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1812 angle::Result TextureD3D_Cube::setEGLImageTarget(const gl::Context *context,
1813                                                  gl::TextureType type,
1814                                                  egl::Image *image)
1815 {
1816     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
1817     return angle::Result::Continue;
1818 }
1819 
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)1820 angle::Result TextureD3D_Cube::setImage(const gl::Context *context,
1821                                         const gl::ImageIndex &index,
1822                                         GLenum internalFormat,
1823                                         const gl::Extents &size,
1824                                         GLenum format,
1825                                         GLenum type,
1826                                         const gl::PixelUnpackState &unpack,
1827                                         gl::Buffer *unpackBuffer,
1828                                         const uint8_t *pixels)
1829 {
1830     ASSERT(size.depth == 1);
1831 
1832     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1833     ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1834                             internalFormatInfo.sizedInternalFormat, size, false));
1835 
1836     return setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0);
1837 }
1838 
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)1839 angle::Result TextureD3D_Cube::setSubImage(const gl::Context *context,
1840                                            const gl::ImageIndex &index,
1841                                            const gl::Box &area,
1842                                            GLenum format,
1843                                            GLenum type,
1844                                            const gl::PixelUnpackState &unpack,
1845                                            gl::Buffer *unpackBuffer,
1846                                            const uint8_t *pixels)
1847 {
1848     ASSERT(area.depth == 1 && area.z == 0);
1849     return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, pixels,
1850                                 0);
1851 }
1852 
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)1853 angle::Result TextureD3D_Cube::setCompressedImage(const gl::Context *context,
1854                                                   const gl::ImageIndex &index,
1855                                                   GLenum internalFormat,
1856                                                   const gl::Extents &size,
1857                                                   const gl::PixelUnpackState &unpack,
1858                                                   size_t imageSize,
1859                                                   const uint8_t *pixels)
1860 {
1861     ASSERT(size.depth == 1);
1862 
1863     // compressed formats don't have separate sized internal formats-- we can just use the
1864     // compressed format directly
1865     ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1866                             internalFormat, size, false));
1867 
1868     return setCompressedImageImpl(context, index, unpack, pixels, 0);
1869 }
1870 
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)1871 angle::Result TextureD3D_Cube::setCompressedSubImage(const gl::Context *context,
1872                                                      const gl::ImageIndex &index,
1873                                                      const gl::Box &area,
1874                                                      GLenum format,
1875                                                      const gl::PixelUnpackState &unpack,
1876                                                      size_t imageSize,
1877                                                      const uint8_t *pixels)
1878 {
1879     ASSERT(area.depth == 1 && area.z == 0);
1880 
1881     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
1882     return commitRegion(context, index, area);
1883 }
1884 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)1885 angle::Result TextureD3D_Cube::copyImage(const gl::Context *context,
1886                                          const gl::ImageIndex &index,
1887                                          const gl::Rectangle &sourceArea,
1888                                          GLenum internalFormat,
1889                                          gl::Framebuffer *source)
1890 {
1891     GLint faceIndex = index.cubeMapFaceIndex();
1892     const gl::InternalFormat &internalFormatInfo =
1893         gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1894 
1895     gl::Extents size(sourceArea.width, sourceArea.height, 1);
1896     ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1897                             internalFormatInfo.sizedInternalFormat, size, false));
1898 
1899     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1900 
1901     // Does the read area extend beyond the framebuffer?
1902     bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
1903                    sourceArea.x + sourceArea.width > fbSize.width ||
1904                    sourceArea.y + sourceArea.height > fbSize.height;
1905 
1906     // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
1907     // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
1908     // Same thing for robust resource init.
1909     if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled()))
1910     {
1911         ANGLE_TRY(initializeContents(context, GL_NONE, index));
1912     }
1913 
1914     gl::Rectangle clippedArea;
1915     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1916     {
1917         // Empty source area, nothing to do.
1918         return angle::Result::Continue;
1919     }
1920 
1921     gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
1922 
1923     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1924     // framebuffer in shaders, so we should use the non-rendering copy path.
1925     if (!canCreateRenderTargetForImage(index) ||
1926         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1927     {
1928         ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1929             context, destOffset, clippedArea, source));
1930         mDirtyImages = true;
1931         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1932     }
1933     else
1934     {
1935         ANGLE_TRY(ensureRenderTarget(context));
1936 
1937         ASSERT(size.width == size.height);
1938 
1939         if (size.width > 0 && isValidFaceLevel(faceIndex, index.getLevelIndex()))
1940         {
1941             ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1942             ANGLE_TRY(mRenderer->copyImageCube(context, source, clippedArea, internalFormat,
1943                                                destOffset, mTexStorage, index.getTarget(),
1944                                                index.getLevelIndex()));
1945         }
1946     }
1947 
1948     return angle::Result::Continue;
1949 }
1950 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1951 angle::Result TextureD3D_Cube::copySubImage(const gl::Context *context,
1952                                             const gl::ImageIndex &index,
1953                                             const gl::Offset &destOffset,
1954                                             const gl::Rectangle &sourceArea,
1955                                             gl::Framebuffer *source)
1956 {
1957     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1958     gl::Rectangle clippedArea;
1959     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1960     {
1961         return angle::Result::Continue;
1962     }
1963     const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1964                                    destOffset.y + clippedArea.y - sourceArea.y, 0);
1965 
1966     GLint faceIndex = index.cubeMapFaceIndex();
1967 
1968     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1969     // framebuffer in shaders, so we should use the non-rendering copy path.
1970     if (!canCreateRenderTargetForImage(index) ||
1971         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1972     {
1973         ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1974             context, clippedOffset, clippedArea, source));
1975         mDirtyImages = true;
1976         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1977     }
1978     else
1979     {
1980         ANGLE_TRY(ensureRenderTarget(context));
1981         if (isValidFaceLevel(faceIndex, index.getLevelIndex()))
1982         {
1983             ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1984             ANGLE_TRY(mRenderer->copyImageCube(
1985                 context, source, clippedArea, gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1986                 clippedOffset, mTexStorage, index.getTarget(), index.getLevelIndex()));
1987         }
1988     }
1989 
1990     return angle::Result::Continue;
1991 }
1992 
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)1993 angle::Result TextureD3D_Cube::copyTexture(const gl::Context *context,
1994                                            const gl::ImageIndex &index,
1995                                            GLenum internalFormat,
1996                                            GLenum type,
1997                                            GLint sourceLevel,
1998                                            bool unpackFlipY,
1999                                            bool unpackPremultiplyAlpha,
2000                                            bool unpackUnmultiplyAlpha,
2001                                            const gl::Texture *source)
2002 {
2003     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
2004 
2005     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
2006 
2007     GLint faceIndex = index.cubeMapFaceIndex();
2008 
2009     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2010     gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
2011                      static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
2012     ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
2013                             internalFormatInfo.sizedInternalFormat, size, false));
2014 
2015     gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
2016     gl::Offset destOffset(0, 0, 0);
2017 
2018     if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
2019     {
2020 
2021         ANGLE_TRY(ensureRenderTarget(context));
2022         ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
2023         ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
2024 
2025         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
2026                                          sourceBox, internalFormatInfo.format,
2027                                          internalFormatInfo.type, destOffset, mTexStorage,
2028                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2029                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2030     }
2031     else
2032     {
2033         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
2034         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
2035         ImageD3D *sourceImage           = nullptr;
2036         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2037 
2038         ImageD3D *destImage = nullptr;
2039         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
2040 
2041         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2042                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2043 
2044         mDirtyImages = true;
2045 
2046         gl::Box destRegion(destOffset, size);
2047         ANGLE_TRY(commitRegion(context, index, destRegion));
2048     }
2049 
2050     return angle::Result::Continue;
2051 }
2052 
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)2053 angle::Result TextureD3D_Cube::copySubTexture(const gl::Context *context,
2054                                               const gl::ImageIndex &index,
2055                                               const gl::Offset &destOffset,
2056                                               GLint sourceLevel,
2057                                               const gl::Box &sourceBox,
2058                                               bool unpackFlipY,
2059                                               bool unpackPremultiplyAlpha,
2060                                               bool unpackUnmultiplyAlpha,
2061                                               const gl::Texture *source)
2062 {
2063     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
2064 
2065     GLint faceIndex = index.cubeMapFaceIndex();
2066 
2067     if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
2068     {
2069         ANGLE_TRY(ensureRenderTarget(context));
2070         ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
2071         ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
2072 
2073         const gl::InternalFormat &internalFormatInfo =
2074             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex(), faceIndex));
2075         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
2076                                          sourceBox, internalFormatInfo.format,
2077                                          internalFormatInfo.type, destOffset, mTexStorage,
2078                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2079                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2080     }
2081     else
2082     {
2083         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
2084         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
2085         ImageD3D *sourceImage           = nullptr;
2086         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2087 
2088         ImageD3D *destImage = nullptr;
2089         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
2090 
2091         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2092                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2093 
2094         mDirtyImages = true;
2095 
2096         gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
2097         ANGLE_TRY(commitRegion(context, index, destRegion));
2098     }
2099 
2100     return angle::Result::Continue;
2101 }
2102 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2103 angle::Result TextureD3D_Cube::setStorage(const gl::Context *context,
2104                                           gl::TextureType type,
2105                                           size_t levels,
2106                                           GLenum internalFormat,
2107                                           const gl::Extents &size)
2108 {
2109     ASSERT(size.width == size.height);
2110     ASSERT(size.depth == 1);
2111 
2112     for (size_t level = 0; level < levels; level++)
2113     {
2114         GLsizei mipSize = std::max(1, size.width >> level);
2115         for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2116         {
2117             mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalFormat,
2118                                                     gl::Extents(mipSize, mipSize, 1), true);
2119         }
2120     }
2121 
2122     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2123     {
2124         for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2125         {
2126             mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, GL_NONE,
2127                                                     gl::Extents(0, 0, 0), true);
2128         }
2129     }
2130 
2131     // TODO(geofflang): Verify storage creation had no errors
2132     BindFlags bindFlags;
2133     bindFlags.renderTarget = IsRenderTargetUsage(mState.getUsage());
2134 
2135     TexStoragePointer storage = {
2136         mRenderer->createTextureStorageCube(internalFormat, bindFlags, size.width,
2137                                             static_cast<int>(levels), false, mState.getLabel()),
2138         context};
2139 
2140     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2141     storage.release();
2142 
2143     ANGLE_TRY(updateStorage(context));
2144 
2145     mImmutable = true;
2146 
2147     return angle::Result::Continue;
2148 }
2149 
2150 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isCubeComplete() const2151 bool TextureD3D_Cube::isCubeComplete() const
2152 {
2153     int baseWidth     = getBaseLevelWidth();
2154     int baseHeight    = getBaseLevelHeight();
2155     GLenum baseFormat = getBaseLevelInternalFormat();
2156 
2157     if (baseWidth <= 0 || baseWidth != baseHeight)
2158     {
2159         return false;
2160     }
2161 
2162     for (size_t faceIndex = 1; faceIndex < gl::kCubeFaceCount; faceIndex++)
2163     {
2164         const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
2165 
2166         if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight ||
2167             faceBaseImage.getInternalFormat() != baseFormat)
2168         {
2169             return false;
2170         }
2171     }
2172 
2173     return true;
2174 }
2175 
bindTexImage(const gl::Context * context,egl::Surface * surface)2176 angle::Result TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface)
2177 {
2178     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2179     return angle::Result::Continue;
2180 }
2181 
releaseTexImage(const gl::Context * context)2182 angle::Result TextureD3D_Cube::releaseTexImage(const gl::Context *context)
2183 {
2184     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2185     return angle::Result::Continue;
2186 }
2187 
initMipmapImages(const gl::Context * context)2188 angle::Result TextureD3D_Cube::initMipmapImages(const gl::Context *context)
2189 {
2190     const GLuint baseLevel = mState.getEffectiveBaseLevel();
2191     const GLuint maxLevel  = mState.getMipmapMaxLevel();
2192     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2193     // levels.
2194     for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2195     {
2196         for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2197         {
2198             int faceLevelSize =
2199                 (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1));
2200             ANGLE_TRY(redefineImage(context, faceIndex, level,
2201                                     mImageArray[faceIndex][baseLevel]->getInternalFormat(),
2202                                     gl::Extents(faceLevelSize, faceLevelSize, 1), false));
2203         }
2204     }
2205 
2206     // We should be mip-complete now so generate the storage.
2207     ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
2208 
2209     return angle::Result::Continue;
2210 }
2211 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2212 angle::Result TextureD3D_Cube::getRenderTarget(const gl::Context *context,
2213                                                const gl::ImageIndex &index,
2214                                                GLsizei samples,
2215                                                RenderTargetD3D **outRT)
2216 {
2217     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
2218 
2219     // ensure the underlying texture is created
2220     ANGLE_TRY(ensureRenderTarget(context));
2221     ANGLE_TRY(updateStorageFaceLevel(context, index.cubeMapFaceIndex(), index.getLevelIndex()));
2222 
2223     return mTexStorage->getRenderTarget(context, index, samples, outRT);
2224 }
2225 
initializeStorage(const gl::Context * context,BindFlags bindFlags)2226 angle::Result TextureD3D_Cube::initializeStorage(const gl::Context *context, BindFlags bindFlags)
2227 {
2228     // Only initialize the first time this texture is used as a render target or shader resource
2229     if (mTexStorage)
2230     {
2231         return angle::Result::Continue;
2232     }
2233 
2234     // do not attempt to create storage for nonexistant data
2235     if (!isFaceLevelComplete(0, getBaseLevel()))
2236     {
2237         return angle::Result::Continue;
2238     }
2239 
2240     bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage());
2241 
2242     TexStoragePointer storage;
2243     ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
2244 
2245     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2246     storage.release();
2247 
2248     ASSERT(mTexStorage);
2249 
2250     // flush image data to the storage
2251     ANGLE_TRY(updateStorage(context));
2252 
2253     return angle::Result::Continue;
2254 }
2255 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const2256 angle::Result TextureD3D_Cube::createCompleteStorage(const gl::Context *context,
2257                                                      BindFlags bindFlags,
2258                                                      TexStoragePointer *outStorage) const
2259 {
2260     GLsizei size = getLevelZeroWidth();
2261 
2262     ASSERT(size > 0);
2263 
2264     // use existing storage level count, when previously specified by TexStorage*D
2265     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
2266 
2267     bool hintLevelZeroOnly = false;
2268     if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
2269     {
2270         // If any of the CPU images (levels >= 1) are dirty, then the textureStorageEXT should use
2271         // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
2272         hintLevelZeroOnly = true;
2273         for (int faceIndex = 0;
2274              faceIndex < static_cast<int>(gl::kCubeFaceCount) && hintLevelZeroOnly; faceIndex++)
2275         {
2276             for (int level = 1; level < levels && hintLevelZeroOnly; level++)
2277             {
2278                 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() &&
2279                                       isFaceLevelComplete(faceIndex, level));
2280             }
2281         }
2282     }
2283 
2284     // TODO (geofflang): detect if storage creation succeeded
2285     *outStorage = {
2286         mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), bindFlags, size, levels,
2287                                             hintLevelZeroOnly, mState.getLabel()),
2288         context};
2289 
2290     return angle::Result::Continue;
2291 }
2292 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2293 angle::Result TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context,
2294                                                      TextureStorage *newCompleteTexStorage)
2295 {
2296     if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
2297     {
2298         for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2299         {
2300             for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
2301             {
2302                 ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube(
2303                     context, newCompleteTexStorage, faceIndex, level));
2304             }
2305         }
2306     }
2307 
2308     gl::TexLevelMask copyImageMask;
2309     copyImageMask.set();
2310 
2311     ANGLE_TRY(releaseTexStorage(context, copyImageMask));
2312     mTexStorage = newCompleteTexStorage;
2313     mTexStorageObserverBinding.bind(mTexStorage);
2314 
2315     mDirtyImages = true;
2316     return angle::Result::Continue;
2317 }
2318 
updateStorage(const gl::Context * context)2319 angle::Result TextureD3D_Cube::updateStorage(const gl::Context *context)
2320 {
2321     if (!mDirtyImages)
2322     {
2323         return angle::Result::Continue;
2324     }
2325 
2326     ASSERT(mTexStorage != nullptr);
2327     GLint storageLevels = mTexStorage->getLevelCount();
2328     for (int face = 0; face < static_cast<int>(gl::kCubeFaceCount); face++)
2329     {
2330         for (int level = 0; level < storageLevels; level++)
2331         {
2332             if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
2333             {
2334                 ANGLE_TRY(updateStorageFaceLevel(context, face, level));
2335             }
2336         }
2337     }
2338 
2339     mDirtyImages = false;
2340     return angle::Result::Continue;
2341 }
2342 
isValidFaceLevel(int faceIndex,int level) const2343 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
2344 {
2345     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2346 }
2347 
isFaceLevelComplete(int faceIndex,int level) const2348 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
2349 {
2350     if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2351     {
2352         return false;
2353     }
2354     ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2355            level < static_cast<int>(mImageArray[faceIndex].size()) &&
2356            mImageArray[faceIndex][level] != nullptr);
2357 
2358     if (isImmutable())
2359     {
2360         return true;
2361     }
2362 
2363     int levelZeroSize = getLevelZeroWidth();
2364 
2365     if (levelZeroSize <= 0)
2366     {
2367         return false;
2368     }
2369 
2370     // Check that non-zero levels are consistent with the base level.
2371     const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get();
2372 
2373     if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
2374     {
2375         return false;
2376     }
2377 
2378     if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
2379     {
2380         return false;
2381     }
2382 
2383     return true;
2384 }
2385 
isImageComplete(const gl::ImageIndex & index) const2386 bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
2387 {
2388     return isFaceLevelComplete(index.cubeMapFaceIndex(), index.getLevelIndex());
2389 }
2390 
updateStorageFaceLevel(const gl::Context * context,int faceIndex,int level)2391 angle::Result TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
2392                                                       int faceIndex,
2393                                                       int level)
2394 {
2395     ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2396            level < static_cast<int>(mImageArray[faceIndex].size()) &&
2397            mImageArray[faceIndex][level] != nullptr);
2398     ImageD3D *image = mImageArray[faceIndex][level].get();
2399 
2400     if (image->isDirty())
2401     {
2402         gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex);
2403         gl::ImageIndex index         = gl::ImageIndex::MakeCubeMapFace(faceTarget, level);
2404         gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
2405         ANGLE_TRY(commitRegion(context, index, region));
2406     }
2407 
2408     return angle::Result::Continue;
2409 }
2410 
redefineImage(const gl::Context * context,int faceIndex,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2411 angle::Result TextureD3D_Cube::redefineImage(const gl::Context *context,
2412                                              int faceIndex,
2413                                              GLint level,
2414                                              GLenum internalformat,
2415                                              const gl::Extents &size,
2416                                              bool forceRelease)
2417 {
2418     // If there currently is a corresponding storage texture image, it has these parameters
2419     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
2420     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
2421     const GLenum storageFormat = getBaseLevelInternalFormat();
2422 
2423     if (mTexStorage)
2424     {
2425         const int storageLevels = mTexStorage->getLevelCount();
2426 
2427         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
2428             size.height != storageHeight ||
2429             internalformat != storageFormat)  // Discard mismatched storage
2430         {
2431             markAllImagesDirty();
2432 
2433             gl::TexLevelMask copyImageMask;
2434             copyImageMask.set();
2435             copyImageMask.set(level, false);
2436 
2437             ANGLE_TRY(releaseTexStorage(context, copyImageMask));
2438         }
2439     }
2440 
2441     mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalformat, size,
2442                                             forceRelease);
2443     mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty();
2444 
2445     return angle::Result::Continue;
2446 }
2447 
imageIterator() const2448 gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
2449 {
2450     return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
2451 }
2452 
getImageIndex(GLint mip,GLint layer) const2453 gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
2454 {
2455     // The "layer" of the image index corresponds to the cube face
2456     return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip);
2457 }
2458 
isValidIndex(const gl::ImageIndex & index) const2459 bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
2460 {
2461     return (mTexStorage && index.getType() == gl::TextureType::CubeMap &&
2462             gl::IsCubeMapFaceTarget(index.getTarget()) && index.getLevelIndex() >= 0 &&
2463             index.getLevelIndex() < mTexStorage->getLevelCount());
2464 }
2465 
markAllImagesDirty()2466 void TextureD3D_Cube::markAllImagesDirty()
2467 {
2468     for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
2469     {
2470         for (size_t dirtyFace = 0; dirtyFace < gl::kCubeFaceCount; dirtyFace++)
2471         {
2472             mImageArray[dirtyFace][dirtyLevel]->markDirty();
2473         }
2474     }
2475     mDirtyImages = true;
2476 }
2477 
TextureD3D_3D(const gl::TextureState & state,RendererD3D * renderer)2478 TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer)
2479     : TextureD3D(state, renderer)
2480 {
2481     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
2482     {
2483         mImageArray[i].reset(renderer->createImage());
2484     }
2485 }
2486 
onDestroy(const gl::Context * context)2487 void TextureD3D_3D::onDestroy(const gl::Context *context)
2488 {
2489     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
2490     // for some of their data. If TextureStorage is deleted before the Images, then their data will
2491     // be wastefully copied back from the GPU before we delete the Images.
2492     for (auto &image : mImageArray)
2493     {
2494         image.reset();
2495     }
2496     return TextureD3D::onDestroy(context);
2497 }
2498 
~TextureD3D_3D()2499 TextureD3D_3D::~TextureD3D_3D() {}
2500 
getImage(int level,int layer) const2501 ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
2502 {
2503     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2504     ASSERT(layer == 0);
2505     return mImageArray[level].get();
2506 }
2507 
getImage(const gl::ImageIndex & index) const2508 ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
2509 {
2510     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2511     ASSERT(!index.hasLayer());
2512     ASSERT(index.getType() == gl::TextureType::_3D);
2513     return mImageArray[index.getLevelIndex()].get();
2514 }
2515 
getLayerCount(int level) const2516 GLsizei TextureD3D_3D::getLayerCount(int level) const
2517 {
2518     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2519     return 1;
2520 }
2521 
getWidth(GLint level) const2522 GLsizei TextureD3D_3D::getWidth(GLint level) const
2523 {
2524     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2525         return mImageArray[level]->getWidth();
2526     else
2527         return 0;
2528 }
2529 
getHeight(GLint level) const2530 GLsizei TextureD3D_3D::getHeight(GLint level) const
2531 {
2532     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2533         return mImageArray[level]->getHeight();
2534     else
2535         return 0;
2536 }
2537 
getDepth(GLint level) const2538 GLsizei TextureD3D_3D::getDepth(GLint level) const
2539 {
2540     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2541         return mImageArray[level]->getDepth();
2542     else
2543         return 0;
2544 }
2545 
getInternalFormat(GLint level) const2546 GLenum TextureD3D_3D::getInternalFormat(GLint level) const
2547 {
2548     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2549         return mImageArray[level]->getInternalFormat();
2550     else
2551         return GL_NONE;
2552 }
2553 
isDepth(GLint level) const2554 bool TextureD3D_3D::isDepth(GLint level) const
2555 {
2556     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
2557 }
2558 
isSRGB(GLint level) const2559 bool TextureD3D_3D::isSRGB(GLint level) const
2560 {
2561     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
2562 }
2563 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)2564 angle::Result TextureD3D_3D::setEGLImageTarget(const gl::Context *context,
2565                                                gl::TextureType type,
2566                                                egl::Image *image)
2567 {
2568     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2569     return angle::Result::Continue;
2570 }
2571 
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)2572 angle::Result TextureD3D_3D::setImage(const gl::Context *context,
2573                                       const gl::ImageIndex &index,
2574                                       GLenum internalFormat,
2575                                       const gl::Extents &size,
2576                                       GLenum format,
2577                                       GLenum type,
2578                                       const gl::PixelUnpackState &unpack,
2579                                       gl::Buffer *unpackBuffer,
2580                                       const uint8_t *pixels)
2581 {
2582     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2583     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2584 
2585     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2586                             size, false));
2587 
2588     bool fastUnpacked = false;
2589 
2590     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2591     if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) &&
2592         !size.empty() && isLevelComplete(index.getLevelIndex()))
2593     {
2594         // Will try to create RT storage if it does not exist
2595         RenderTargetD3D *destRenderTarget = nullptr;
2596         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2597 
2598         gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
2599                          getDepth(index.getLevelIndex()));
2600 
2601         ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
2602                                    internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
2603 
2604         // Ensure we don't overwrite our newly initialized data
2605         mImageArray[index.getLevelIndex()]->markClean();
2606 
2607         fastUnpacked = true;
2608     }
2609 
2610     if (!fastUnpacked)
2611     {
2612         ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
2613     }
2614 
2615     return angle::Result::Continue;
2616 }
2617 
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)2618 angle::Result TextureD3D_3D::setSubImage(const gl::Context *context,
2619                                          const gl::ImageIndex &index,
2620                                          const gl::Box &area,
2621                                          GLenum format,
2622                                          GLenum type,
2623                                          const gl::PixelUnpackState &unpack,
2624                                          gl::Buffer *unpackBuffer,
2625                                          const uint8_t *pixels)
2626 {
2627     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2628 
2629     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2630     GLenum mipFormat = getInternalFormat(index.getLevelIndex());
2631     if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex()))
2632     {
2633         RenderTargetD3D *destRenderTarget = nullptr;
2634         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2635         ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
2636 
2637         return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
2638                                 destRenderTarget);
2639     }
2640     else
2641     {
2642         return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
2643                                     pixels, 0);
2644     }
2645 }
2646 
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)2647 angle::Result TextureD3D_3D::setCompressedImage(const gl::Context *context,
2648                                                 const gl::ImageIndex &index,
2649                                                 GLenum internalFormat,
2650                                                 const gl::Extents &size,
2651                                                 const gl::PixelUnpackState &unpack,
2652                                                 size_t imageSize,
2653                                                 const uint8_t *pixels)
2654 {
2655     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2656 
2657     // compressed formats don't have separate sized internal formats-- we can just use the
2658     // compressed format directly
2659     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
2660 
2661     return setCompressedImageImpl(context, index, unpack, pixels, 0);
2662 }
2663 
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)2664 angle::Result TextureD3D_3D::setCompressedSubImage(const gl::Context *context,
2665                                                    const gl::ImageIndex &index,
2666                                                    const gl::Box &area,
2667                                                    GLenum format,
2668                                                    const gl::PixelUnpackState &unpack,
2669                                                    size_t imageSize,
2670                                                    const uint8_t *pixels)
2671 {
2672     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2673 
2674     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
2675     return commitRegion(context, index, area);
2676 }
2677 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)2678 angle::Result TextureD3D_3D::copyImage(const gl::Context *context,
2679                                        const gl::ImageIndex &index,
2680                                        const gl::Rectangle &sourceArea,
2681                                        GLenum internalFormat,
2682                                        gl::Framebuffer *source)
2683 {
2684     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2685     return angle::Result::Continue;
2686 }
2687 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)2688 angle::Result TextureD3D_3D::copySubImage(const gl::Context *context,
2689                                           const gl::ImageIndex &index,
2690                                           const gl::Offset &destOffset,
2691                                           const gl::Rectangle &sourceArea,
2692                                           gl::Framebuffer *source)
2693 {
2694     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2695 
2696     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
2697     gl::Rectangle clippedSourceArea;
2698     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
2699                        &clippedSourceArea))
2700     {
2701         return angle::Result::Continue;
2702     }
2703     const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
2704                                        destOffset.y + clippedSourceArea.y - sourceArea.y,
2705                                        destOffset.z);
2706 
2707     // Currently, copying directly to the storage is not possible because it's not possible to
2708     // create an SRV from a single layer of a 3D texture.  Instead, make sure the image is up to
2709     // date before the copy and then copy back to the storage afterwards if needed.
2710     // TODO: Investigate 3D blits in D3D11.
2711 
2712     bool syncTexStorage = mTexStorage && isLevelComplete(index.getLevelIndex());
2713     if (syncTexStorage)
2714     {
2715         ANGLE_TRY(
2716             mImageArray[index.getLevelIndex()]->copyFromTexStorage(context, index, mTexStorage));
2717     }
2718     ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedDestOffset,
2719                                                                       clippedSourceArea, source));
2720     mDirtyImages = true;
2721     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
2722 
2723     if (syncTexStorage)
2724     {
2725         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2726     }
2727 
2728     return angle::Result::Continue;
2729 }
2730 
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)2731 angle::Result TextureD3D_3D::copyTexture(const gl::Context *context,
2732                                          const gl::ImageIndex &index,
2733                                          GLenum internalFormat,
2734                                          GLenum type,
2735                                          GLint sourceLevel,
2736                                          bool unpackFlipY,
2737                                          bool unpackPremultiplyAlpha,
2738                                          bool unpackUnmultiplyAlpha,
2739                                          const gl::Texture *source)
2740 {
2741     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2742 
2743     gl::TextureType sourceType = source->getType();
2744 
2745     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2746     gl::Extents size(
2747         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2748         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2749         static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
2750 
2751     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2752                             size, false));
2753 
2754     gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
2755     gl::Offset destOffset(0, 0, 0);
2756     gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2757 
2758     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2759     {
2760         ANGLE_TRY(ensureRenderTarget(context));
2761         ASSERT(isValidLevel(index.getLevelIndex()));
2762         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2763 
2764         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
2765                                          sourceBox, internalFormatInfo.format,
2766                                          internalFormatInfo.type, destOffset, mTexStorage,
2767                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2768                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2769     }
2770     else
2771     {
2772         gl::ImageIndex sourceIndex = gl::ImageIndex::Make3D(sourceLevel);
2773         ImageD3D *sourceImage      = nullptr;
2774         ImageD3D *destImage        = nullptr;
2775         TextureD3D *sourceD3D      = GetImplAs<TextureD3D>(source);
2776 
2777         ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2778         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceIndex, &sourceImage));
2779 
2780         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2781                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2782 
2783         mDirtyImages = true;
2784 
2785         gl::Box destRegion(0, 0, 0, sourceBox.width, sourceBox.height, sourceBox.depth);
2786         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2787     }
2788 
2789     return angle::Result::Continue;
2790 }
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)2791 angle::Result TextureD3D_3D::copySubTexture(const gl::Context *context,
2792                                             const gl::ImageIndex &index,
2793                                             const gl::Offset &destOffset,
2794                                             GLint sourceLevel,
2795                                             const gl::Box &sourceBox,
2796                                             bool unpackFlipY,
2797                                             bool unpackPremultiplyAlpha,
2798                                             bool unpackUnmultiplyAlpha,
2799                                             const gl::Texture *source)
2800 {
2801     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2802 
2803     gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2804 
2805     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2806     {
2807         ANGLE_TRY(ensureRenderTarget(context));
2808         ASSERT(isValidLevel(index.getLevelIndex()));
2809         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2810 
2811         const gl::InternalFormat &internalFormatInfo =
2812             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
2813         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
2814                                          sourceBox, internalFormatInfo.format,
2815                                          internalFormatInfo.type, destOffset, mTexStorage,
2816                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2817                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2818     }
2819     else
2820     {
2821         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make3D(sourceLevel);
2822         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
2823         ImageD3D *sourceImage           = nullptr;
2824         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2825 
2826         ImageD3D *destImage = nullptr;
2827         ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2828 
2829         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2830                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2831 
2832         mDirtyImages = true;
2833 
2834         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
2835                            sourceBox.height, sourceBox.depth);
2836         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2837     }
2838 
2839     return angle::Result::Continue;
2840 }
2841 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2842 angle::Result TextureD3D_3D::setStorage(const gl::Context *context,
2843                                         gl::TextureType type,
2844                                         size_t levels,
2845                                         GLenum internalFormat,
2846                                         const gl::Extents &size)
2847 {
2848     ASSERT(type == gl::TextureType::_3D);
2849 
2850     for (size_t level = 0; level < levels; level++)
2851     {
2852         gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
2853                               std::max(1, size.depth >> level));
2854         mImageArray[level]->redefine(gl::TextureType::_3D, internalFormat, levelSize, true);
2855     }
2856 
2857     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2858     {
2859         mImageArray[level]->redefine(gl::TextureType::_3D, GL_NONE, gl::Extents(0, 0, 0), true);
2860     }
2861 
2862     // TODO(geofflang): Verify storage creation had no errors
2863     BindFlags bindFlags;
2864     bindFlags.renderTarget    = IsRenderTargetUsage(mState.getUsage());
2865     TexStoragePointer storage = {
2866         mRenderer->createTextureStorage3D(internalFormat, bindFlags, size.width, size.height,
2867                                           size.depth, static_cast<int>(levels), mState.getLabel()),
2868         context};
2869 
2870     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2871     storage.release();
2872 
2873     ANGLE_TRY(updateStorage(context));
2874 
2875     mImmutable = true;
2876 
2877     return angle::Result::Continue;
2878 }
2879 
bindTexImage(const gl::Context * context,egl::Surface * surface)2880 angle::Result TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface)
2881 {
2882     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2883     return angle::Result::Continue;
2884 }
2885 
releaseTexImage(const gl::Context * context)2886 angle::Result TextureD3D_3D::releaseTexImage(const gl::Context *context)
2887 {
2888     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2889     return angle::Result::Continue;
2890 }
2891 
initMipmapImages(const gl::Context * context)2892 angle::Result TextureD3D_3D::initMipmapImages(const gl::Context *context)
2893 {
2894     const GLuint baseLevel = mState.getEffectiveBaseLevel();
2895     const GLuint maxLevel  = mState.getMipmapMaxLevel();
2896     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2897     // levels.
2898     for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2899     {
2900         gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
2901                               std::max(getLevelZeroHeight() >> level, 1),
2902                               std::max(getLevelZeroDepth() >> level, 1));
2903         ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
2904     }
2905 
2906     // We should be mip-complete now so generate the storage.
2907     ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
2908 
2909     return angle::Result::Continue;
2910 }
2911 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2912 angle::Result TextureD3D_3D::getRenderTarget(const gl::Context *context,
2913                                              const gl::ImageIndex &index,
2914                                              GLsizei samples,
2915                                              RenderTargetD3D **outRT)
2916 {
2917     // ensure the underlying texture is created
2918     ANGLE_TRY(ensureRenderTarget(context));
2919 
2920     if (index.hasLayer())
2921     {
2922         ANGLE_TRY(updateStorage(context));
2923     }
2924     else
2925     {
2926         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2927     }
2928 
2929     return mTexStorage->getRenderTarget(context, index, samples, outRT);
2930 }
2931 
initializeStorage(const gl::Context * context,BindFlags bindFlags)2932 angle::Result TextureD3D_3D::initializeStorage(const gl::Context *context, BindFlags bindFlags)
2933 {
2934     // Only initialize the first time this texture is used as a render target or shader resource
2935     if (mTexStorage)
2936     {
2937         return angle::Result::Continue;
2938     }
2939 
2940     // do not attempt to create storage for nonexistant data
2941     if (!isLevelComplete(getBaseLevel()))
2942     {
2943         return angle::Result::Continue;
2944     }
2945 
2946     TexStoragePointer storage;
2947     ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
2948 
2949     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2950     storage.release();
2951 
2952     ASSERT(mTexStorage);
2953 
2954     // flush image data to the storage
2955     ANGLE_TRY(updateStorage(context));
2956 
2957     return angle::Result::Continue;
2958 }
2959 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const2960 angle::Result TextureD3D_3D::createCompleteStorage(const gl::Context *context,
2961                                                    BindFlags bindFlags,
2962                                                    TexStoragePointer *outStorage) const
2963 {
2964     GLsizei width         = getLevelZeroWidth();
2965     GLsizei height        = getLevelZeroHeight();
2966     GLsizei depth         = getLevelZeroDepth();
2967     GLenum internalFormat = getBaseLevelInternalFormat();
2968 
2969     ASSERT(width > 0 && height > 0 && depth > 0);
2970 
2971     // use existing storage level count, when previously specified by TexStorage*D
2972     GLint levels =
2973         (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2974 
2975     // TODO: Verify creation of the storage succeeded
2976     *outStorage = {mRenderer->createTextureStorage3D(internalFormat, bindFlags, width, height,
2977                                                      depth, levels, mState.getLabel()),
2978                    context};
2979 
2980     return angle::Result::Continue;
2981 }
2982 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2983 angle::Result TextureD3D_3D::setCompleteTexStorage(const gl::Context *context,
2984                                                    TextureStorage *newCompleteTexStorage)
2985 {
2986     gl::TexLevelMask copyImageMask;
2987     copyImageMask.set();
2988 
2989     ANGLE_TRY(releaseTexStorage(context, copyImageMask));
2990     mTexStorage = newCompleteTexStorage;
2991     mTexStorageObserverBinding.bind(mTexStorage);
2992     mDirtyImages = true;
2993 
2994     // We do not support managed 3D storage, as that is D3D9/ES2-only
2995     ASSERT(!mTexStorage->isManaged());
2996 
2997     return angle::Result::Continue;
2998 }
2999 
updateStorage(const gl::Context * context)3000 angle::Result TextureD3D_3D::updateStorage(const gl::Context *context)
3001 {
3002     if (!mDirtyImages)
3003     {
3004         return angle::Result::Continue;
3005     }
3006 
3007     ASSERT(mTexStorage != nullptr);
3008     GLint storageLevels = mTexStorage->getLevelCount();
3009     for (int level = 0; level < storageLevels; level++)
3010     {
3011         if (mImageArray[level]->isDirty() && isLevelComplete(level))
3012         {
3013             ANGLE_TRY(updateStorageLevel(context, level));
3014         }
3015     }
3016 
3017     mDirtyImages = false;
3018     return angle::Result::Continue;
3019 }
3020 
isValidLevel(int level) const3021 bool TextureD3D_3D::isValidLevel(int level) const
3022 {
3023     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
3024 }
3025 
isLevelComplete(int level) const3026 bool TextureD3D_3D::isLevelComplete(int level) const
3027 {
3028     ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
3029            mImageArray[level] != nullptr);
3030 
3031     if (isImmutable())
3032     {
3033         return true;
3034     }
3035 
3036     GLsizei width  = getLevelZeroWidth();
3037     GLsizei height = getLevelZeroHeight();
3038     GLsizei depth  = getLevelZeroDepth();
3039 
3040     if (width <= 0 || height <= 0 || depth <= 0)
3041     {
3042         return false;
3043     }
3044 
3045     if (level == static_cast<int>(getBaseLevel()))
3046     {
3047         return true;
3048     }
3049 
3050     ImageD3D *levelImage = mImageArray[level].get();
3051 
3052     if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
3053     {
3054         return false;
3055     }
3056 
3057     if (levelImage->getWidth() != std::max(1, width >> level))
3058     {
3059         return false;
3060     }
3061 
3062     if (levelImage->getHeight() != std::max(1, height >> level))
3063     {
3064         return false;
3065     }
3066 
3067     if (levelImage->getDepth() != std::max(1, depth >> level))
3068     {
3069         return false;
3070     }
3071 
3072     return true;
3073 }
3074 
isImageComplete(const gl::ImageIndex & index) const3075 bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
3076 {
3077     return isLevelComplete(index.getLevelIndex());
3078 }
3079 
updateStorageLevel(const gl::Context * context,int level)3080 angle::Result TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level)
3081 {
3082     ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
3083            mImageArray[level] != nullptr);
3084     ASSERT(isLevelComplete(level));
3085 
3086     if (mImageArray[level]->isDirty())
3087     {
3088         gl::ImageIndex index = gl::ImageIndex::Make3D(level);
3089         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
3090         ANGLE_TRY(commitRegion(context, index, region));
3091     }
3092 
3093     return angle::Result::Continue;
3094 }
3095 
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)3096 angle::Result TextureD3D_3D::redefineImage(const gl::Context *context,
3097                                            GLint level,
3098                                            GLenum internalformat,
3099                                            const gl::Extents &size,
3100                                            bool forceRelease)
3101 {
3102     // If there currently is a corresponding storage texture image, it has these parameters
3103     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
3104     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
3105     const int storageDepth     = std::max(1, getLevelZeroDepth() >> level);
3106     const GLenum storageFormat = getBaseLevelInternalFormat();
3107 
3108     if (mTexStorage)
3109     {
3110         const int storageLevels = mTexStorage->getLevelCount();
3111 
3112         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3113             size.height != storageHeight || size.depth != storageDepth ||
3114             internalformat != storageFormat)  // Discard mismatched storage
3115         {
3116             markAllImagesDirty();
3117 
3118             gl::TexLevelMask copyImageMask;
3119             copyImageMask.set();
3120             copyImageMask.set(level, false);
3121 
3122             ANGLE_TRY(releaseTexStorage(context, copyImageMask));
3123         }
3124     }
3125 
3126     mImageArray[level]->redefine(gl::TextureType::_3D, internalformat, size, forceRelease);
3127     mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
3128 
3129     return angle::Result::Continue;
3130 }
3131 
imageIterator() const3132 gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
3133 {
3134     return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
3135                                           gl::ImageIndex::kEntireLevel,
3136                                           gl::ImageIndex::kEntireLevel);
3137 }
3138 
getImageIndex(GLint mip,GLint) const3139 gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
3140 {
3141     // The "layer" here does not apply to 3D images. We use one Image per mip.
3142     return gl::ImageIndex::Make3D(mip);
3143 }
3144 
isValidIndex(const gl::ImageIndex & index) const3145 bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
3146 {
3147     return (mTexStorage && index.getType() == gl::TextureType::_3D && index.getLevelIndex() >= 0 &&
3148             index.getLevelIndex() < mTexStorage->getLevelCount());
3149 }
3150 
markAllImagesDirty()3151 void TextureD3D_3D::markAllImagesDirty()
3152 {
3153     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
3154     {
3155         mImageArray[i]->markDirty();
3156     }
3157     mDirtyImages = true;
3158 }
3159 
getLevelZeroDepth() const3160 GLint TextureD3D_3D::getLevelZeroDepth() const
3161 {
3162     ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel());
3163     return getBaseLevelDepth() << getBaseLevel();
3164 }
3165 
TextureD3D_2DArray(const gl::TextureState & state,RendererD3D * renderer)3166 TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer)
3167     : TextureD3D(state, renderer)
3168 {
3169     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3170     {
3171         mLayerCounts[level] = 0;
3172         mImageArray[level]  = nullptr;
3173     }
3174 }
3175 
onDestroy(const gl::Context * context)3176 void TextureD3D_2DArray::onDestroy(const gl::Context *context)
3177 {
3178     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
3179     // for some of their data. If TextureStorage is deleted before the Images, then their data will
3180     // be wastefully copied back from the GPU before we delete the Images.
3181     deleteImages();
3182     return TextureD3D::onDestroy(context);
3183 }
3184 
~TextureD3D_2DArray()3185 TextureD3D_2DArray::~TextureD3D_2DArray() {}
3186 
getImage(int level,int layer) const3187 ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
3188 {
3189     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3190     ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]);
3191     return (mImageArray[level] ? mImageArray[level][layer] : nullptr);
3192 }
3193 
getImage(const gl::ImageIndex & index) const3194 ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
3195 {
3196     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3197     ASSERT(index.hasLayer());
3198     ASSERT((index.getLayerIndex() == 0 && mLayerCounts[index.getLevelIndex()] == 0) ||
3199            index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]);
3200     ASSERT(index.getType() == gl::TextureType::_2DArray);
3201     return (mImageArray[index.getLevelIndex()]
3202                 ? mImageArray[index.getLevelIndex()][index.getLayerIndex()]
3203                 : nullptr);
3204 }
3205 
getLayerCount(int level) const3206 GLsizei TextureD3D_2DArray::getLayerCount(int level) const
3207 {
3208     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3209     return mLayerCounts[level];
3210 }
3211 
getWidth(GLint level) const3212 GLsizei TextureD3D_2DArray::getWidth(GLint level) const
3213 {
3214     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3215                ? mImageArray[level][0]->getWidth()
3216                : 0;
3217 }
3218 
getHeight(GLint level) const3219 GLsizei TextureD3D_2DArray::getHeight(GLint level) const
3220 {
3221     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3222                ? mImageArray[level][0]->getHeight()
3223                : 0;
3224 }
3225 
getInternalFormat(GLint level) const3226 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
3227 {
3228     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3229                ? mImageArray[level][0]->getInternalFormat()
3230                : GL_NONE;
3231 }
3232 
isDepth(GLint level) const3233 bool TextureD3D_2DArray::isDepth(GLint level) const
3234 {
3235     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
3236 }
3237 
isSRGB(GLint level) const3238 bool TextureD3D_2DArray::isSRGB(GLint level) const
3239 {
3240     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
3241 }
3242 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3243 angle::Result TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context,
3244                                                     gl::TextureType type,
3245                                                     egl::Image *image)
3246 {
3247     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3248     return angle::Result::Continue;
3249 }
3250 
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)3251 angle::Result TextureD3D_2DArray::setImage(const gl::Context *context,
3252                                            const gl::ImageIndex &index,
3253                                            GLenum internalFormat,
3254                                            const gl::Extents &size,
3255                                            GLenum format,
3256                                            GLenum type,
3257                                            const gl::PixelUnpackState &unpack,
3258                                            gl::Buffer *unpackBuffer,
3259                                            const uint8_t *pixels)
3260 {
3261     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3262 
3263     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3264 
3265     ANGLE_TRY(
3266         redefineImage(context, index.getLevelIndex(), formatInfo.sizedInternalFormat, size, false));
3267 
3268     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3269 
3270     GLuint inputDepthPitch = 0;
3271     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3272                                         type, size.width, size.height, unpack.alignment,
3273                                         unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3274 
3275     for (int i = 0; i < size.depth; i++)
3276     {
3277         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3278         gl::ImageIndex layerIndex   = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3279         ANGLE_TRY(
3280             setImageImpl(context, layerIndex, type, unpack, unpackBuffer, pixels, layerOffset));
3281     }
3282 
3283     return angle::Result::Continue;
3284 }
3285 
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)3286 angle::Result TextureD3D_2DArray::setSubImage(const gl::Context *context,
3287                                               const gl::ImageIndex &index,
3288                                               const gl::Box &area,
3289                                               GLenum format,
3290                                               GLenum type,
3291                                               const gl::PixelUnpackState &unpack,
3292                                               gl::Buffer *unpackBuffer,
3293                                               const uint8_t *pixels)
3294 {
3295     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3296 
3297     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3298     const gl::InternalFormat &formatInfo =
3299         gl::GetInternalFormatInfo(getInternalFormat(index.getLevelIndex()), type);
3300     GLuint inputDepthPitch = 0;
3301     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3302                                         type, area.width, area.height, unpack.alignment,
3303                                         unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3304 
3305     for (int i = 0; i < area.depth; i++)
3306     {
3307         int layer                   = area.z + i;
3308         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3309 
3310         gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3311 
3312         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3313         ANGLE_TRY(TextureD3D::subImage(context, layerIndex, layerArea, format, type, unpack,
3314                                        unpackBuffer, pixels, layerOffset));
3315     }
3316 
3317     return angle::Result::Continue;
3318 }
3319 
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)3320 angle::Result TextureD3D_2DArray::setCompressedImage(const gl::Context *context,
3321                                                      const gl::ImageIndex &index,
3322                                                      GLenum internalFormat,
3323                                                      const gl::Extents &size,
3324                                                      const gl::PixelUnpackState &unpack,
3325                                                      size_t imageSize,
3326                                                      const uint8_t *pixels)
3327 {
3328     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3329 
3330     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3331 
3332     // compressed formats don't have separate sized internal formats-- we can just use the
3333     // compressed format directly
3334     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
3335 
3336     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
3337     GLuint inputDepthPitch               = 0;
3338     ANGLE_CHECK_GL_MATH(
3339         contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0,
3340                                                  &inputDepthPitch));
3341 
3342     for (int i = 0; i < size.depth; i++)
3343     {
3344         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3345 
3346         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3347         ANGLE_TRY(setCompressedImageImpl(context, layerIndex, unpack, pixels, layerOffset));
3348     }
3349 
3350     return angle::Result::Continue;
3351 }
3352 
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)3353 angle::Result TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context,
3354                                                         const gl::ImageIndex &index,
3355                                                         const gl::Box &area,
3356                                                         GLenum format,
3357                                                         const gl::PixelUnpackState &unpack,
3358                                                         size_t imageSize,
3359                                                         const uint8_t *pixels)
3360 {
3361     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3362 
3363     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3364 
3365     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format);
3366     GLuint inputDepthPitch               = 0;
3367     ANGLE_CHECK_GL_MATH(
3368         contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0,
3369                                                  &inputDepthPitch));
3370 
3371     for (int i = 0; i < area.depth; i++)
3372     {
3373         int layer                   = area.z + i;
3374         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3375 
3376         gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3377 
3378         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3379         ANGLE_TRY(TextureD3D::subImageCompressed(context, layerIndex, layerArea, format, unpack,
3380                                                  pixels, layerOffset));
3381         ANGLE_TRY(commitRegion(context, layerIndex, layerArea));
3382     }
3383 
3384     return angle::Result::Continue;
3385 }
3386 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3387 angle::Result TextureD3D_2DArray::copyImage(const gl::Context *context,
3388                                             const gl::ImageIndex &index,
3389                                             const gl::Rectangle &sourceArea,
3390                                             GLenum internalFormat,
3391                                             gl::Framebuffer *source)
3392 {
3393     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3394     return angle::Result::Continue;
3395 }
3396 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3397 angle::Result TextureD3D_2DArray::copySubImage(const gl::Context *context,
3398                                                const gl::ImageIndex &index,
3399                                                const gl::Offset &destOffset,
3400                                                const gl::Rectangle &sourceArea,
3401                                                gl::Framebuffer *source)
3402 {
3403     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3404 
3405     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
3406     gl::Rectangle clippedSourceArea;
3407     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
3408                        &clippedSourceArea))
3409     {
3410         return angle::Result::Continue;
3411     }
3412     const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
3413                                        destOffset.y + clippedSourceArea.y - sourceArea.y,
3414                                        destOffset.z);
3415 
3416     if (!canCreateRenderTargetForImage(index))
3417     {
3418         gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0);
3419         ANGLE_TRY(mImageArray[index.getLevelIndex()][clippedDestOffset.z]->copyFromFramebuffer(
3420             context, destLayerOffset, clippedSourceArea, source));
3421         mDirtyImages = true;
3422         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
3423     }
3424     else
3425     {
3426         ANGLE_TRY(ensureRenderTarget(context));
3427 
3428         if (isValidLevel(index.getLevelIndex()))
3429         {
3430             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3431             ANGLE_TRY(
3432                 mRenderer->copyImage2DArray(context, source, clippedSourceArea,
3433                                             gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())),
3434                                             clippedDestOffset, mTexStorage, index.getLevelIndex()));
3435         }
3436     }
3437     return angle::Result::Continue;
3438 }
3439 
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)3440 angle::Result TextureD3D_2DArray::copyTexture(const gl::Context *context,
3441                                               const gl::ImageIndex &index,
3442                                               GLenum internalFormat,
3443                                               GLenum type,
3444                                               GLint sourceLevel,
3445                                               bool unpackFlipY,
3446                                               bool unpackPremultiplyAlpha,
3447                                               bool unpackUnmultiplyAlpha,
3448                                               const gl::Texture *source)
3449 {
3450     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3451 
3452     gl::TextureType sourceType = source->getType();
3453 
3454     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3455     gl::Extents size(
3456         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3457         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3458         static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
3459 
3460     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
3461                             size, false));
3462 
3463     gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
3464     gl::Offset destOffset(0, 0, 0);
3465 
3466     gl::ImageIndex destIndex =
3467         gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth);
3468 
3469     if (!isSRGB(index.getLevelIndex()) &&
3470         canCreateRenderTargetForImage(
3471             gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth)))
3472     {
3473         ANGLE_TRY(ensureRenderTarget(context));
3474         ASSERT(isValidLevel(index.getLevelIndex()));
3475         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3476         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
3477                                          sourceBox, internalFormatInfo.format,
3478                                          internalFormatInfo.type, destOffset, mTexStorage,
3479                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
3480                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
3481     }
3482     else
3483     {
3484         for (int i = 0; i < size.depth; i++)
3485         {
3486             gl::ImageIndex currentSourceDepthIndex = gl::ImageIndex::Make2DArray(sourceLevel, i);
3487             gl::ImageIndex currentDestDepthIndex =
3488                 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3489             ImageD3D *sourceImage = nullptr;
3490             ImageD3D *destImage   = nullptr;
3491             TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3492 
3493             ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestDepthIndex, &destImage));
3494             ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, currentSourceDepthIndex,
3495                                                             &sourceImage));
3496             gl::Box imageBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 1);
3497             ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, imageBox, destOffset,
3498                                            unpackFlipY, unpackPremultiplyAlpha,
3499                                            unpackUnmultiplyAlpha));
3500         }
3501 
3502         mDirtyImages = true;
3503 
3504         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3505                            sourceBox.height, sourceBox.depth);
3506         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3507     }
3508 
3509     return angle::Result::Continue;
3510 }
3511 
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)3512 angle::Result TextureD3D_2DArray::copySubTexture(const gl::Context *context,
3513                                                  const gl::ImageIndex &index,
3514                                                  const gl::Offset &destOffset,
3515                                                  GLint sourceLevel,
3516                                                  const gl::Box &sourceBox,
3517                                                  bool unpackFlipY,
3518                                                  bool unpackPremultiplyAlpha,
3519                                                  bool unpackUnmultiplyAlpha,
3520                                                  const gl::Texture *source)
3521 {
3522     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3523 
3524     gl::ImageIndex destIndex = gl::ImageIndex::Make2DArrayRange(
3525         static_cast<GLint>(index.getLevelIndex()), destOffset.z, sourceBox.depth - destOffset.z);
3526 
3527     if (!isSRGB(destIndex.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
3528     {
3529         ANGLE_TRY(ensureRenderTarget(context));
3530         ASSERT(isValidLevel(destIndex.getLevelIndex()));
3531         ANGLE_TRY(updateStorageLevel(context, destIndex.getLevelIndex()));
3532 
3533         const gl::InternalFormat &internalFormatInfo =
3534             gl::GetSizedInternalFormatInfo(getInternalFormat(destIndex.getLevelIndex()));
3535         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
3536                                          sourceBox, internalFormatInfo.format,
3537                                          internalFormatInfo.type, destOffset, mTexStorage,
3538                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
3539                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
3540     }
3541     else
3542     {
3543         for (int i = 0; i < sourceBox.depth; i++)
3544         {
3545             gl::ImageIndex currentSourceIndex =
3546                 gl::ImageIndex::Make2DArray(sourceLevel, i + sourceBox.z);
3547             gl::ImageIndex currentDestIndex =
3548                 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i + destOffset.z);
3549 
3550             gl::Box currentLayerBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height,
3551                                     1);
3552 
3553             TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3554             ImageD3D *sourceImage = nullptr;
3555             ANGLE_TRY(
3556                 sourceD3D->getImageAndSyncFromStorage(context, currentSourceIndex, &sourceImage));
3557 
3558             ImageD3D *destImage = nullptr;
3559             ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestIndex, &destImage));
3560 
3561             ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, currentLayerBox,
3562                                            destOffset, unpackFlipY, unpackPremultiplyAlpha,
3563                                            unpackUnmultiplyAlpha));
3564         }
3565 
3566         mDirtyImages = true;
3567 
3568         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3569                            sourceBox.height, sourceBox.depth);
3570         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3571     }
3572 
3573     return angle::Result::Continue;
3574 }
3575 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)3576 angle::Result TextureD3D_2DArray::setStorage(const gl::Context *context,
3577                                              gl::TextureType type,
3578                                              size_t levels,
3579                                              GLenum internalFormat,
3580                                              const gl::Extents &size)
3581 {
3582     ASSERT(type == gl::TextureType::_2DArray);
3583 
3584     deleteImages();
3585 
3586     for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
3587     {
3588         gl::Extents levelLayerSize(std::max(1, size.width >> level),
3589                                    std::max(1, size.height >> level), 1);
3590 
3591         mLayerCounts[level] = (level < levels ? size.depth : 0);
3592 
3593         if (mLayerCounts[level] > 0)
3594         {
3595             // Create new images for this level
3596             mImageArray[level] = new ImageD3D *[mLayerCounts[level]];
3597 
3598             for (int layer = 0; layer < mLayerCounts[level]; layer++)
3599             {
3600                 mImageArray[level][layer] = mRenderer->createImage();
3601                 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalFormat,
3602                                                     levelLayerSize, true);
3603             }
3604         }
3605     }
3606 
3607     // TODO(geofflang): Verify storage creation had no errors
3608     BindFlags bindFlags;
3609     bindFlags.renderTarget    = IsRenderTargetUsage(mState.getUsage());
3610     TexStoragePointer storage = {mRenderer->createTextureStorage2DArray(
3611                                      internalFormat, bindFlags, size.width, size.height, size.depth,
3612                                      static_cast<int>(levels), mState.getLabel()),
3613                                  context};
3614 
3615     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3616     storage.release();
3617 
3618     ANGLE_TRY(updateStorage(context));
3619 
3620     mImmutable = true;
3621 
3622     return angle::Result::Continue;
3623 }
3624 
bindTexImage(const gl::Context * context,egl::Surface * surface)3625 angle::Result TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface)
3626 {
3627     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3628     return angle::Result::Continue;
3629 }
3630 
releaseTexImage(const gl::Context * context)3631 angle::Result TextureD3D_2DArray::releaseTexImage(const gl::Context *context)
3632 {
3633     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3634     return angle::Result::Continue;
3635 }
3636 
initMipmapImages(const gl::Context * context)3637 angle::Result TextureD3D_2DArray::initMipmapImages(const gl::Context *context)
3638 {
3639     const GLuint baseLevel = mState.getEffectiveBaseLevel();
3640     const GLuint maxLevel  = mState.getMipmapMaxLevel();
3641     int baseWidth          = getLevelZeroWidth();
3642     int baseHeight         = getLevelZeroHeight();
3643     int baseDepth          = getLayerCount(getBaseLevel());
3644     GLenum baseFormat      = getBaseLevelInternalFormat();
3645 
3646     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
3647     // levels.
3648     for (GLuint level = baseLevel + 1u; level <= maxLevel; level++)
3649     {
3650         ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0);
3651         gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
3652                                    std::max(baseHeight >> level, 1), baseDepth);
3653         ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false));
3654     }
3655 
3656     // We should be mip-complete now so generate the storage.
3657     ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget()));
3658 
3659     return angle::Result::Continue;
3660 }
3661 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)3662 angle::Result TextureD3D_2DArray::getRenderTarget(const gl::Context *context,
3663                                                   const gl::ImageIndex &index,
3664                                                   GLsizei samples,
3665                                                   RenderTargetD3D **outRT)
3666 {
3667     // ensure the underlying texture is created
3668     ANGLE_TRY(ensureRenderTarget(context));
3669     ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3670     return mTexStorage->getRenderTarget(context, index, samples, outRT);
3671 }
3672 
initializeStorage(const gl::Context * context,BindFlags bindFlags)3673 angle::Result TextureD3D_2DArray::initializeStorage(const gl::Context *context, BindFlags bindFlags)
3674 {
3675     // Only initialize the first time this texture is used as a render target or shader resource
3676     if (mTexStorage)
3677     {
3678         return angle::Result::Continue;
3679     }
3680 
3681     // do not attempt to create storage for nonexistant data
3682     if (!isLevelComplete(getBaseLevel()))
3683     {
3684         return angle::Result::Continue;
3685     }
3686 
3687     bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage());
3688 
3689     TexStoragePointer storage;
3690     ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage));
3691 
3692     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3693     storage.release();
3694 
3695     ASSERT(mTexStorage);
3696 
3697     // flush image data to the storage
3698     ANGLE_TRY(updateStorage(context));
3699 
3700     return angle::Result::Continue;
3701 }
3702 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const3703 angle::Result TextureD3D_2DArray::createCompleteStorage(const gl::Context *context,
3704                                                         BindFlags bindFlags,
3705                                                         TexStoragePointer *outStorage) const
3706 {
3707     GLsizei width         = getLevelZeroWidth();
3708     GLsizei height        = getLevelZeroHeight();
3709     GLsizei depth         = getLayerCount(getBaseLevel());
3710     GLenum internalFormat = getBaseLevelInternalFormat();
3711 
3712     ASSERT(width > 0 && height > 0 && depth > 0);
3713 
3714     // use existing storage level count, when previously specified by TexStorage*D
3715     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
3716 
3717     // TODO(geofflang): Verify storage creation succeeds
3718     *outStorage = {mRenderer->createTextureStorage2DArray(internalFormat, bindFlags, width, height,
3719                                                           depth, levels, mState.getLabel()),
3720                    context};
3721 
3722     return angle::Result::Continue;
3723 }
3724 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)3725 angle::Result TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context,
3726                                                         TextureStorage *newCompleteTexStorage)
3727 {
3728     gl::TexLevelMask copyImageMask;
3729     copyImageMask.set();
3730 
3731     ANGLE_TRY(releaseTexStorage(context, copyImageMask));
3732     mTexStorage = newCompleteTexStorage;
3733     mTexStorageObserverBinding.bind(mTexStorage);
3734     mDirtyImages = true;
3735 
3736     // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
3737     ASSERT(!mTexStorage->isManaged());
3738 
3739     return angle::Result::Continue;
3740 }
3741 
updateStorage(const gl::Context * context)3742 angle::Result TextureD3D_2DArray::updateStorage(const gl::Context *context)
3743 {
3744     if (!mDirtyImages)
3745     {
3746         return angle::Result::Continue;
3747     }
3748 
3749     ASSERT(mTexStorage != nullptr);
3750     GLint storageLevels = mTexStorage->getLevelCount();
3751     for (int level = 0; level < storageLevels; level++)
3752     {
3753         if (isLevelComplete(level))
3754         {
3755             ANGLE_TRY(updateStorageLevel(context, level));
3756         }
3757     }
3758 
3759     mDirtyImages = false;
3760     return angle::Result::Continue;
3761 }
3762 
isValidLevel(int level) const3763 bool TextureD3D_2DArray::isValidLevel(int level) const
3764 {
3765     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
3766 }
3767 
isLevelComplete(int level) const3768 bool TextureD3D_2DArray::isLevelComplete(int level) const
3769 {
3770     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
3771 
3772     if (isImmutable())
3773     {
3774         return true;
3775     }
3776 
3777     GLsizei width  = getLevelZeroWidth();
3778     GLsizei height = getLevelZeroHeight();
3779 
3780     if (width <= 0 || height <= 0)
3781     {
3782         return false;
3783     }
3784 
3785     // Layers check needs to happen after the above checks, otherwise out-of-range base level may be
3786     // queried.
3787     GLsizei layers = getLayerCount(getBaseLevel());
3788 
3789     if (layers <= 0)
3790     {
3791         return false;
3792     }
3793 
3794     if (level == static_cast<int>(getBaseLevel()))
3795     {
3796         return true;
3797     }
3798 
3799     if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
3800     {
3801         return false;
3802     }
3803 
3804     if (getWidth(level) != std::max(1, width >> level))
3805     {
3806         return false;
3807     }
3808 
3809     if (getHeight(level) != std::max(1, height >> level))
3810     {
3811         return false;
3812     }
3813 
3814     if (getLayerCount(level) != layers)
3815     {
3816         return false;
3817     }
3818 
3819     return true;
3820 }
3821 
isImageComplete(const gl::ImageIndex & index) const3822 bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
3823 {
3824     return isLevelComplete(index.getLevelIndex());
3825 }
3826 
updateStorageLevel(const gl::Context * context,int level)3827 angle::Result TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level)
3828 {
3829     ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts)));
3830     ASSERT(isLevelComplete(level));
3831 
3832     for (int layer = 0; layer < mLayerCounts[level]; layer++)
3833     {
3834         ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr);
3835         if (mImageArray[level][layer]->isDirty())
3836         {
3837             gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
3838             gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
3839             ANGLE_TRY(commitRegion(context, index, region));
3840         }
3841     }
3842 
3843     return angle::Result::Continue;
3844 }
3845 
deleteImages()3846 void TextureD3D_2DArray::deleteImages()
3847 {
3848     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3849     {
3850         for (int layer = 0; layer < mLayerCounts[level]; ++layer)
3851         {
3852             delete mImageArray[level][layer];
3853         }
3854         delete[] mImageArray[level];
3855         mImageArray[level]  = nullptr;
3856         mLayerCounts[level] = 0;
3857     }
3858 }
3859 
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)3860 angle::Result TextureD3D_2DArray::redefineImage(const gl::Context *context,
3861                                                 GLint level,
3862                                                 GLenum internalformat,
3863                                                 const gl::Extents &size,
3864                                                 bool forceRelease)
3865 {
3866     // If there currently is a corresponding storage texture image, it has these parameters
3867     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
3868     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
3869     const GLuint baseLevel     = getBaseLevel();
3870     const GLenum storageFormat = getBaseLevelInternalFormat();
3871 
3872     int storageDepth = 0;
3873     if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3874     {
3875         storageDepth = getLayerCount(baseLevel);
3876     }
3877 
3878     // Only reallocate the layers if the size doesn't match
3879     if (size.depth != mLayerCounts[level])
3880     {
3881         for (int layer = 0; layer < mLayerCounts[level]; layer++)
3882         {
3883             SafeDelete(mImageArray[level][layer]);
3884         }
3885         SafeDeleteArray(mImageArray[level]);
3886         mLayerCounts[level] = size.depth;
3887 
3888         if (size.depth > 0)
3889         {
3890             mImageArray[level] = new ImageD3D *[size.depth];
3891             for (int layer = 0; layer < mLayerCounts[level]; layer++)
3892             {
3893                 mImageArray[level][layer] = mRenderer->createImage();
3894             }
3895         }
3896     }
3897 
3898     if (mTexStorage)
3899     {
3900         const int storageLevels = mTexStorage->getLevelCount();
3901 
3902         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3903             size.height != storageHeight || size.depth != storageDepth ||
3904             internalformat != storageFormat)  // Discard mismatched storage
3905         {
3906             markAllImagesDirty();
3907 
3908             gl::TexLevelMask copyImageMask;
3909             copyImageMask.set();
3910             copyImageMask.set(level, false);
3911 
3912             ANGLE_TRY(releaseTexStorage(context, copyImageMask));
3913         }
3914     }
3915 
3916     if (size.depth > 0)
3917     {
3918         for (int layer = 0; layer < mLayerCounts[level]; layer++)
3919         {
3920             mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalformat,
3921                                                 gl::Extents(size.width, size.height, 1),
3922                                                 forceRelease);
3923             mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty();
3924         }
3925     }
3926 
3927     return angle::Result::Continue;
3928 }
3929 
imageIterator() const3930 gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
3931 {
3932     return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
3933 }
3934 
getImageIndex(GLint mip,GLint layer) const3935 gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
3936 {
3937     return gl::ImageIndex::Make2DArray(mip, layer);
3938 }
3939 
isValidIndex(const gl::ImageIndex & index) const3940 bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
3941 {
3942     // Check for having a storage and the right type of index
3943     if (!mTexStorage || index.getType() != gl::TextureType::_2DArray)
3944     {
3945         return false;
3946     }
3947 
3948     // Check the mip index
3949     if (index.getLevelIndex() < 0 || index.getLevelIndex() >= mTexStorage->getLevelCount())
3950     {
3951         return false;
3952     }
3953 
3954     // Check the layer index
3955     return (!index.hasLayer() || (index.getLayerIndex() >= 0 &&
3956                                   index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]));
3957 }
3958 
markAllImagesDirty()3959 void TextureD3D_2DArray::markAllImagesDirty()
3960 {
3961     for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
3962     {
3963         for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
3964         {
3965             mImageArray[dirtyLevel][dirtyLayer]->markDirty();
3966         }
3967     }
3968     mDirtyImages = true;
3969 }
3970 
TextureD3DImmutableBase(const gl::TextureState & state,RendererD3D * renderer)3971 TextureD3DImmutableBase::TextureD3DImmutableBase(const gl::TextureState &state,
3972                                                  RendererD3D *renderer)
3973     : TextureD3D(state, renderer)
3974 {}
3975 
~TextureD3DImmutableBase()3976 TextureD3DImmutableBase::~TextureD3DImmutableBase() {}
3977 
getImage(const gl::ImageIndex & index) const3978 ImageD3D *TextureD3DImmutableBase::getImage(const gl::ImageIndex &index) const
3979 {
3980     return nullptr;
3981 }
3982 
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)3983 angle::Result TextureD3DImmutableBase::setImage(const gl::Context *context,
3984                                                 const gl::ImageIndex &index,
3985                                                 GLenum internalFormat,
3986                                                 const gl::Extents &size,
3987                                                 GLenum format,
3988                                                 GLenum type,
3989                                                 const gl::PixelUnpackState &unpack,
3990                                                 gl::Buffer *unpackBuffer,
3991                                                 const uint8_t *pixels)
3992 {
3993     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3994     return angle::Result::Continue;
3995 }
3996 
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)3997 angle::Result TextureD3DImmutableBase::setSubImage(const gl::Context *context,
3998                                                    const gl::ImageIndex &index,
3999                                                    const gl::Box &area,
4000                                                    GLenum format,
4001                                                    GLenum type,
4002                                                    const gl::PixelUnpackState &unpack,
4003                                                    gl::Buffer *unpackBuffer,
4004                                                    const uint8_t *pixels)
4005 {
4006     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4007     return angle::Result::Continue;
4008 }
4009 
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)4010 angle::Result TextureD3DImmutableBase::setCompressedImage(const gl::Context *context,
4011                                                           const gl::ImageIndex &index,
4012                                                           GLenum internalFormat,
4013                                                           const gl::Extents &size,
4014                                                           const gl::PixelUnpackState &unpack,
4015                                                           size_t imageSize,
4016                                                           const uint8_t *pixels)
4017 {
4018     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4019     return angle::Result::Continue;
4020 }
4021 
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)4022 angle::Result TextureD3DImmutableBase::setCompressedSubImage(const gl::Context *context,
4023                                                              const gl::ImageIndex &index,
4024                                                              const gl::Box &area,
4025                                                              GLenum format,
4026                                                              const gl::PixelUnpackState &unpack,
4027                                                              size_t imageSize,
4028                                                              const uint8_t *pixels)
4029 {
4030     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4031     return angle::Result::Continue;
4032 }
4033 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)4034 angle::Result TextureD3DImmutableBase::copyImage(const gl::Context *context,
4035                                                  const gl::ImageIndex &index,
4036                                                  const gl::Rectangle &sourceArea,
4037                                                  GLenum internalFormat,
4038                                                  gl::Framebuffer *source)
4039 {
4040     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4041     return angle::Result::Continue;
4042 }
4043 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)4044 angle::Result TextureD3DImmutableBase::copySubImage(const gl::Context *context,
4045                                                     const gl::ImageIndex &index,
4046                                                     const gl::Offset &destOffset,
4047                                                     const gl::Rectangle &sourceArea,
4048                                                     gl::Framebuffer *source)
4049 {
4050     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4051     return angle::Result::Continue;
4052 }
4053 
bindTexImage(const gl::Context * context,egl::Surface * surface)4054 angle::Result TextureD3DImmutableBase::bindTexImage(const gl::Context *context,
4055                                                     egl::Surface *surface)
4056 {
4057     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4058     return angle::Result::Continue;
4059 }
4060 
releaseTexImage(const gl::Context * context)4061 angle::Result TextureD3DImmutableBase::releaseTexImage(const gl::Context *context)
4062 {
4063     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4064     return angle::Result::Continue;
4065 }
4066 
TextureD3D_External(const gl::TextureState & state,RendererD3D * renderer)4067 TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer)
4068     : TextureD3DImmutableBase(state, renderer)
4069 {}
4070 
~TextureD3D_External()4071 TextureD3D_External::~TextureD3D_External() {}
4072 
getLayerCount(int level) const4073 GLsizei TextureD3D_External::getLayerCount(int level) const
4074 {
4075     return 1;
4076 }
4077 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)4078 angle::Result TextureD3D_External::setImageExternal(const gl::Context *context,
4079                                                     gl::TextureType type,
4080                                                     egl::Stream *stream,
4081                                                     const egl::Stream::GLTextureDescription &desc)
4082 {
4083     ASSERT(type == gl::TextureType::External);
4084 
4085     ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
4086 
4087     // If the stream is null, the external image is unbound and we release the storage
4088     if (stream != nullptr)
4089     {
4090         mTexStorage = mRenderer->createTextureStorageExternal(stream, desc, mState.getLabel());
4091     }
4092 
4093     return angle::Result::Continue;
4094 }
4095 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4096 angle::Result TextureD3D_External::setEGLImageTarget(const gl::Context *context,
4097                                                      gl::TextureType type,
4098                                                      egl::Image *image)
4099 {
4100     EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
4101 
4102     // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
4103     RenderTargetD3D *renderTargetD3D = nullptr;
4104     ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
4105 
4106     ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
4107     mTexStorage =
4108         mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
4109 
4110     return angle::Result::Continue;
4111 }
4112 
initMipmapImages(const gl::Context * context)4113 angle::Result TextureD3D_External::initMipmapImages(const gl::Context *context)
4114 {
4115     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4116     return angle::Result::Stop;
4117 }
4118 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4119 angle::Result TextureD3D_External::getRenderTarget(const gl::Context *context,
4120                                                    const gl::ImageIndex &index,
4121                                                    GLsizei samples,
4122                                                    RenderTargetD3D **outRT)
4123 {
4124     UNREACHABLE();
4125     return angle::Result::Stop;
4126 }
4127 
isImageComplete(const gl::ImageIndex & index) const4128 bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const
4129 {
4130     return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
4131 }
4132 
initializeStorage(const gl::Context * context,BindFlags bindFlags)4133 angle::Result TextureD3D_External::initializeStorage(const gl::Context *context,
4134                                                      BindFlags bindFlags)
4135 {
4136     // Texture storage is created when an external image is bound
4137     ASSERT(mTexStorage);
4138     return angle::Result::Continue;
4139 }
4140 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const4141 angle::Result TextureD3D_External::createCompleteStorage(const gl::Context *context,
4142                                                          BindFlags bindFlags,
4143                                                          TexStoragePointer *outStorage) const
4144 {
4145     UNREACHABLE();
4146     return angle::Result::Continue;
4147 }
4148 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4149 angle::Result TextureD3D_External::setCompleteTexStorage(const gl::Context *context,
4150                                                          TextureStorage *newCompleteTexStorage)
4151 {
4152     UNREACHABLE();
4153     return angle::Result::Continue;
4154 }
4155 
updateStorage(const gl::Context * context)4156 angle::Result TextureD3D_External::updateStorage(const gl::Context *context)
4157 {
4158     // Texture storage does not need to be updated since it is already loaded with the latest
4159     // external image
4160     ASSERT(mTexStorage);
4161     return angle::Result::Continue;
4162 }
4163 
imageIterator() const4164 gl::ImageIndexIterator TextureD3D_External::imageIterator() const
4165 {
4166     return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
4167 }
4168 
getImageIndex(GLint mip,GLint) const4169 gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const
4170 {
4171     // "layer" does not apply to 2D Textures.
4172     return gl::ImageIndex::Make2D(mip);
4173 }
4174 
isValidIndex(const gl::ImageIndex & index) const4175 bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
4176 {
4177     return (mTexStorage && index.getType() == gl::TextureType::External &&
4178             index.getLevelIndex() == 0);
4179 }
4180 
markAllImagesDirty()4181 void TextureD3D_External::markAllImagesDirty()
4182 {
4183     UNREACHABLE();
4184 }
4185 
TextureD3D_2DMultisample(const gl::TextureState & state,RendererD3D * renderer)4186 TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state,
4187                                                    RendererD3D *renderer)
4188     : TextureD3DImmutableBase(state, renderer)
4189 {}
4190 
~TextureD3D_2DMultisample()4191 TextureD3D_2DMultisample::~TextureD3D_2DMultisample() {}
4192 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4193 angle::Result TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context,
4194                                                               gl::TextureType type,
4195                                                               GLsizei samples,
4196                                                               GLint internalformat,
4197                                                               const gl::Extents &size,
4198                                                               bool fixedSampleLocations)
4199 {
4200     ASSERT(type == gl::TextureType::_2DMultisample && size.depth == 1);
4201 
4202     // We allocate storage immediately instead of doing it lazily like other TextureD3D classes do.
4203     // This requires less state in this class.
4204     TexStoragePointer storage = {mRenderer->createTextureStorage2DMultisample(
4205                                      internalformat, size.width, size.height, static_cast<int>(0),
4206                                      samples, fixedSampleLocations, mState.getLabel()),
4207                                  context};
4208 
4209     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4210     storage.release();
4211 
4212     mImmutable = true;
4213 
4214     return angle::Result::Continue;
4215 }
4216 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4217 angle::Result TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context,
4218                                                           gl::TextureType type,
4219                                                           egl::Image *image)
4220 {
4221     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4222     return angle::Result::Continue;
4223 }
4224 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4225 angle::Result TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context,
4226                                                         const gl::ImageIndex &index,
4227                                                         GLsizei samples,
4228                                                         RenderTargetD3D **outRT)
4229 {
4230     ASSERT(!index.hasLayer());
4231 
4232     // ensure the underlying texture is created
4233     ANGLE_TRY(ensureRenderTarget(context));
4234 
4235     return mTexStorage->getRenderTarget(context, index, samples, outRT);
4236 }
4237 
imageIterator() const4238 gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const
4239 {
4240     return gl::ImageIndexIterator::Make2DMultisample();
4241 }
4242 
getImageIndex(GLint mip,GLint layer) const4243 gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const
4244 {
4245     return gl::ImageIndex::Make2DMultisample();
4246 }
4247 
isValidIndex(const gl::ImageIndex & index) const4248 bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const
4249 {
4250     return (mTexStorage && index.getType() == gl::TextureType::_2DMultisample &&
4251             index.getLevelIndex() == 0);
4252 }
4253 
getLayerCount(int level) const4254 GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const
4255 {
4256     return 1;
4257 }
4258 
markAllImagesDirty()4259 void TextureD3D_2DMultisample::markAllImagesDirty() {}
4260 
initializeStorage(const gl::Context * context,BindFlags bindFlags)4261 angle::Result TextureD3D_2DMultisample::initializeStorage(const gl::Context *context,
4262                                                           BindFlags bindFlags)
4263 {
4264     // initializeStorage should only be called in a situation where the texture already has storage
4265     // associated with it (storage is created in setStorageMultisample).
4266     ASSERT(mTexStorage);
4267     return angle::Result::Continue;
4268 }
4269 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const4270 angle::Result TextureD3D_2DMultisample::createCompleteStorage(const gl::Context *context,
4271                                                               BindFlags bindFlags,
4272                                                               TexStoragePointer *outStorage) const
4273 {
4274     UNREACHABLE();
4275     *outStorage = {mTexStorage, context};
4276     return angle::Result::Continue;
4277 }
4278 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4279 angle::Result TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context,
4280                                                               TextureStorage *newCompleteTexStorage)
4281 {
4282     // These textures are immutable, so this should only be ever called once.
4283     ASSERT(!mTexStorage);
4284     mTexStorage = newCompleteTexStorage;
4285     mTexStorageObserverBinding.bind(mTexStorage);
4286     return angle::Result::Continue;
4287 }
4288 
updateStorage(const gl::Context * context)4289 angle::Result TextureD3D_2DMultisample::updateStorage(const gl::Context *context)
4290 {
4291     return angle::Result::Continue;
4292 }
4293 
initMipmapImages(const gl::Context * context)4294 angle::Result TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context)
4295 {
4296     UNREACHABLE();
4297     return angle::Result::Continue;
4298 }
4299 
isImageComplete(const gl::ImageIndex & index) const4300 bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const
4301 {
4302     return true;
4303 }
4304 
TextureD3D_2DMultisampleArray(const gl::TextureState & state,RendererD3D * renderer)4305 TextureD3D_2DMultisampleArray::TextureD3D_2DMultisampleArray(const gl::TextureState &state,
4306                                                              RendererD3D *renderer)
4307     : TextureD3DImmutableBase(state, renderer)
4308 {}
4309 
~TextureD3D_2DMultisampleArray()4310 TextureD3D_2DMultisampleArray::~TextureD3D_2DMultisampleArray() {}
4311 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4312 angle::Result TextureD3D_2DMultisampleArray::setStorageMultisample(const gl::Context *context,
4313                                                                    gl::TextureType type,
4314                                                                    GLsizei samples,
4315                                                                    GLint internalformat,
4316                                                                    const gl::Extents &size,
4317                                                                    bool fixedSampleLocations)
4318 {
4319     ASSERT(type == gl::TextureType::_2DMultisampleArray);
4320 
4321     mLayerCount = size.depth;
4322 
4323     TexStoragePointer storage = {
4324         mRenderer->createTextureStorage2DMultisampleArray(internalformat, size.width, size.height,
4325                                                           size.depth, static_cast<int>(0), samples,
4326                                                           fixedSampleLocations, mState.getLabel()),
4327         context};
4328 
4329     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4330     storage.release();
4331 
4332     mImmutable = true;
4333 
4334     return angle::Result::Continue;
4335 }
4336 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4337 angle::Result TextureD3D_2DMultisampleArray::setEGLImageTarget(const gl::Context *context,
4338                                                                gl::TextureType type,
4339                                                                egl::Image *image)
4340 {
4341     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4342     return angle::Result::Continue;
4343 }
4344 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4345 angle::Result TextureD3D_2DMultisampleArray::getRenderTarget(const gl::Context *context,
4346                                                              const gl::ImageIndex &index,
4347                                                              GLsizei samples,
4348                                                              RenderTargetD3D **outRT)
4349 {
4350     // ensure the underlying texture is created
4351     ANGLE_TRY(ensureRenderTarget(context));
4352 
4353     return mTexStorage->getRenderTarget(context, index, samples, outRT);
4354 }
4355 
imageIterator() const4356 gl::ImageIndexIterator TextureD3D_2DMultisampleArray::imageIterator() const
4357 {
4358     return gl::ImageIndexIterator::Make2DMultisampleArray(&mLayerCount);
4359 }
4360 
getImageIndex(GLint mip,GLint layer) const4361 gl::ImageIndex TextureD3D_2DMultisampleArray::getImageIndex(GLint mip, GLint layer) const
4362 {
4363     return gl::ImageIndex::Make2DMultisampleArray(layer);
4364 }
4365 
isValidIndex(const gl::ImageIndex & index) const4366 bool TextureD3D_2DMultisampleArray::isValidIndex(const gl::ImageIndex &index) const
4367 {
4368     return (mTexStorage && index.getType() == gl::TextureType::_2DMultisampleArray &&
4369             index.getLevelIndex() == 0);
4370 }
4371 
getLayerCount(int level) const4372 GLsizei TextureD3D_2DMultisampleArray::getLayerCount(int level) const
4373 {
4374     return mLayerCount;
4375 }
4376 
markAllImagesDirty()4377 void TextureD3D_2DMultisampleArray::markAllImagesDirty() {}
4378 
initializeStorage(const gl::Context * context,BindFlags bindFlags)4379 angle::Result TextureD3D_2DMultisampleArray::initializeStorage(const gl::Context *context,
4380                                                                BindFlags bindFlags)
4381 {
4382     // initializeStorage should only be called in a situation where the texture already has storage
4383     // associated with it (storage is created in setStorageMultisample).
4384     ASSERT(mTexStorage);
4385     return angle::Result::Continue;
4386 }
4387 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const4388 angle::Result TextureD3D_2DMultisampleArray::createCompleteStorage(
4389     const gl::Context *context,
4390     BindFlags bindFlags,
4391     TexStoragePointer *outStorage) const
4392 {
4393     UNREACHABLE();
4394     *outStorage = {mTexStorage, context};
4395     return angle::Result::Continue;
4396 }
4397 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4398 angle::Result TextureD3D_2DMultisampleArray::setCompleteTexStorage(
4399     const gl::Context *context,
4400     TextureStorage *newCompleteTexStorage)
4401 {
4402     // These textures are immutable, so this should only be ever called once.
4403     ASSERT(!mTexStorage);
4404     mTexStorage = newCompleteTexStorage;
4405     mTexStorageObserverBinding.bind(mTexStorage);
4406     return angle::Result::Continue;
4407 }
4408 
updateStorage(const gl::Context * context)4409 angle::Result TextureD3D_2DMultisampleArray::updateStorage(const gl::Context *context)
4410 {
4411     return angle::Result::Continue;
4412 }
4413 
initMipmapImages(const gl::Context * context)4414 angle::Result TextureD3D_2DMultisampleArray::initMipmapImages(const gl::Context *context)
4415 {
4416     UNIMPLEMENTED();
4417     return angle::Result::Continue;
4418 }
4419 
isImageComplete(const gl::ImageIndex & index) const4420 bool TextureD3D_2DMultisampleArray::isImageComplete(const gl::ImageIndex &index) const
4421 {
4422     return true;
4423 }
4424 
TextureD3D_Buffer(const gl::TextureState & state,RendererD3D * renderer)4425 TextureD3D_Buffer::TextureD3D_Buffer(const gl::TextureState &state, RendererD3D *renderer)
4426     : TextureD3D(state, renderer), mInternalFormat(GL_INVALID_ENUM)
4427 {}
4428 
~TextureD3D_Buffer()4429 TextureD3D_Buffer::~TextureD3D_Buffer() {}
4430 
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)4431 angle::Result TextureD3D_Buffer::setImage(const gl::Context *context,
4432                                           const gl::ImageIndex &index,
4433                                           GLenum internalFormat,
4434                                           const gl::Extents &size,
4435                                           GLenum format,
4436                                           GLenum type,
4437                                           const gl::PixelUnpackState &unpack,
4438                                           gl::Buffer *unpackBuffer,
4439                                           const uint8_t *pixels)
4440 {
4441     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4442     return angle::Result::Continue;
4443 }
4444 
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)4445 angle::Result TextureD3D_Buffer::setSubImage(const gl::Context *context,
4446                                              const gl::ImageIndex &index,
4447                                              const gl::Box &area,
4448                                              GLenum format,
4449                                              GLenum type,
4450                                              const gl::PixelUnpackState &unpack,
4451                                              gl::Buffer *unpackBuffer,
4452                                              const uint8_t *pixels)
4453 {
4454     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4455     return angle::Result::Continue;
4456 }
4457 
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)4458 angle::Result TextureD3D_Buffer::setCompressedImage(const gl::Context *context,
4459                                                     const gl::ImageIndex &index,
4460                                                     GLenum internalFormat,
4461                                                     const gl::Extents &size,
4462                                                     const gl::PixelUnpackState &unpack,
4463                                                     size_t imageSize,
4464                                                     const uint8_t *pixels)
4465 {
4466     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4467     return angle::Result::Continue;
4468 }
4469 
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)4470 angle::Result TextureD3D_Buffer::setCompressedSubImage(const gl::Context *context,
4471                                                        const gl::ImageIndex &index,
4472                                                        const gl::Box &area,
4473                                                        GLenum format,
4474                                                        const gl::PixelUnpackState &unpack,
4475                                                        size_t imageSize,
4476                                                        const uint8_t *pixels)
4477 {
4478     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4479     return angle::Result::Continue;
4480 }
4481 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)4482 angle::Result TextureD3D_Buffer::copyImage(const gl::Context *context,
4483                                            const gl::ImageIndex &index,
4484                                            const gl::Rectangle &sourceArea,
4485                                            GLenum internalFormat,
4486                                            gl::Framebuffer *source)
4487 {
4488     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4489     return angle::Result::Continue;
4490 }
4491 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)4492 angle::Result TextureD3D_Buffer::copySubImage(const gl::Context *context,
4493                                               const gl::ImageIndex &index,
4494                                               const gl::Offset &destOffset,
4495                                               const gl::Rectangle &sourceArea,
4496                                               gl::Framebuffer *source)
4497 {
4498     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4499     return angle::Result::Continue;
4500 }
4501 
bindTexImage(const gl::Context * context,egl::Surface * surface)4502 angle::Result TextureD3D_Buffer::bindTexImage(const gl::Context *context, egl::Surface *surface)
4503 {
4504     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4505     return angle::Result::Continue;
4506 }
4507 
releaseTexImage(const gl::Context * context)4508 angle::Result TextureD3D_Buffer::releaseTexImage(const gl::Context *context)
4509 {
4510     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4511     return angle::Result::Continue;
4512 }
4513 
getLayerCount(int level) const4514 GLsizei TextureD3D_Buffer::getLayerCount(int level) const
4515 {
4516     return 1;
4517 }
4518 
initMipmapImages(const gl::Context * context)4519 angle::Result TextureD3D_Buffer::initMipmapImages(const gl::Context *context)
4520 {
4521     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4522     return angle::Result::Stop;
4523 }
4524 
isImageComplete(const gl::ImageIndex & index) const4525 bool TextureD3D_Buffer::isImageComplete(const gl::ImageIndex &index) const
4526 {
4527     return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
4528 }
4529 
initializeStorage(const gl::Context * context,BindFlags bindFlags)4530 angle::Result TextureD3D_Buffer::initializeStorage(const gl::Context *context, BindFlags bindFlags)
4531 {
4532     ASSERT(mTexStorage);
4533     return angle::Result::Continue;
4534 }
4535 
createCompleteStorage(const gl::Context * context,BindFlags bindFlags,TexStoragePointer * outStorage) const4536 angle::Result TextureD3D_Buffer::createCompleteStorage(const gl::Context *context,
4537                                                        BindFlags bindFlags,
4538                                                        TexStoragePointer *outStorage) const
4539 {
4540     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4541     return angle::Result::Continue;
4542 }
4543 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4544 angle::Result TextureD3D_Buffer::setCompleteTexStorage(const gl::Context *context,
4545                                                        TextureStorage *newCompleteTexStorage)
4546 {
4547     ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask()));
4548     mTexStorage = newCompleteTexStorage;
4549     mTexStorageObserverBinding.bind(mTexStorage);
4550 
4551     mDirtyImages = true;
4552 
4553     return angle::Result::Continue;
4554 }
4555 
updateStorage(const gl::Context * context)4556 angle::Result TextureD3D_Buffer::updateStorage(const gl::Context *context)
4557 {
4558     ASSERT(mTexStorage);
4559     return angle::Result::Continue;
4560 }
4561 
imageIterator() const4562 gl::ImageIndexIterator TextureD3D_Buffer::imageIterator() const
4563 {
4564     return gl::ImageIndexIterator::MakeBuffer();
4565 }
4566 
getImageIndex(GLint mip,GLint layer) const4567 gl::ImageIndex TextureD3D_Buffer::getImageIndex(GLint mip, GLint layer) const
4568 {
4569     return gl::ImageIndex::MakeBuffer();
4570 }
4571 
isValidIndex(const gl::ImageIndex & index) const4572 bool TextureD3D_Buffer::isValidIndex(const gl::ImageIndex &index) const
4573 {
4574     return (mTexStorage && index.getType() == gl::TextureType::Buffer &&
4575             index.getLevelIndex() == 0);
4576 }
4577 
markAllImagesDirty()4578 void TextureD3D_Buffer::markAllImagesDirty()
4579 {
4580     UNREACHABLE();
4581 }
4582 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4583 angle::Result TextureD3D_Buffer::setEGLImageTarget(const gl::Context *context,
4584                                                    gl::TextureType type,
4585                                                    egl::Image *image)
4586 {
4587     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4588     return angle::Result::Continue;
4589 }
4590 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4591 angle::Result TextureD3D_Buffer::getRenderTarget(const gl::Context *context,
4592                                                  const gl::ImageIndex &index,
4593                                                  GLsizei samples,
4594                                                  RenderTargetD3D **outRT)
4595 {
4596     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4597     return angle::Result::Continue;
4598 }
4599 
getImage(const gl::ImageIndex & index) const4600 ImageD3D *TextureD3D_Buffer::getImage(const gl::ImageIndex &index) const
4601 {
4602     return nullptr;
4603 }
4604 
setBuffer(const gl::Context * context,GLenum internalFormat)4605 angle::Result TextureD3D_Buffer::setBuffer(const gl::Context *context, GLenum internalFormat)
4606 {
4607     ASSERT(mState.getType() == gl::TextureType::Buffer);
4608     TexStoragePointer storage;
4609     storage.reset(mRenderer->createTextureStorageBuffer(mState.getBuffer(), internalFormat,
4610                                                         mState.getLabel()));
4611     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4612     storage.release();
4613     mInternalFormat = internalFormat;
4614     mImmutable      = false;
4615     return angle::Result::Continue;
4616 }
4617 
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)4618 angle::Result TextureD3D_Buffer::syncState(const gl::Context *context,
4619                                            const gl::Texture::DirtyBits &dirtyBits,
4620                                            gl::Command source)
4621 {
4622     ASSERT(mState.getType() == gl::TextureType::Buffer);
4623     if (dirtyBits.test(gl::Texture::DirtyBitType::DIRTY_BIT_IMPLEMENTATION) &&
4624         mState.getBuffer().get() != nullptr)
4625     {
4626         // buffer data have been changed. Buffer data may out of sync
4627         // give up the old TexStorage, create a new one.
4628         // this may not efficient, since staging buffer may be patially updated.
4629         ANGLE_TRY(setBuffer(context, mInternalFormat));
4630     }
4631     return angle::Result::Continue;
4632 }
4633 
4634 }  // namespace rx
4635