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