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