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