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