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