diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp | 3088 |
1 files changed, 1988 insertions, 1100 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp index 430576b318..bf44cbb5d2 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -12,6 +12,7 @@ #include "common/utilities.h" #include "libANGLE/Buffer.h" #include "libANGLE/Config.h" +#include "libANGLE/Context.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/Image.h" #include "libANGLE/Surface.h" @@ -21,8 +22,8 @@ #include "libANGLE/renderer/d3d/BufferD3D.h" #include "libANGLE/renderer/d3d/EGLImageD3D.h" #include "libANGLE/renderer/d3d/ImageD3D.h" -#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/SurfaceD3D.h" #include "libANGLE/renderer/d3d/TextureStorage.h" @@ -32,26 +33,24 @@ namespace rx namespace { -gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, - ptrdiff_t layerOffset, const uint8_t **pointerOut) +gl::Error GetUnpackPointer(const gl::Context *context, + const gl::PixelUnpackState &unpack, + gl::Buffer *unpackBuffer, + const uint8_t *pixels, + ptrdiff_t layerOffset, + const uint8_t **pointerOut) { - if (unpack.pixelBuffer.id() != 0) + if (unpackBuffer) { // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported - gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels); // TODO: this is the only place outside of renderer that asks for a buffers raw data. // This functionality should be moved into renderer and the getData method of BufferImpl removed. - BufferD3D *bufferD3D = GetImplAs<BufferD3D>(pixelBuffer); + BufferD3D *bufferD3D = GetImplAs<BufferD3D>(unpackBuffer); ASSERT(bufferD3D); - const uint8_t *bufferData = NULL; - gl::Error error = bufferD3D->getData(&bufferData); - if (error.isError()) - { - return error; - } - + const uint8_t *bufferData = nullptr; + ANGLE_TRY(bufferD3D->getData(context, &bufferData)); *pointerOut = bufferData + offset; } else @@ -65,7 +64,7 @@ gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pi *pointerOut += layerOffset; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool IsRenderTargetUsage(GLenum usage) @@ -75,41 +74,66 @@ bool IsRenderTargetUsage(GLenum usage) } -TextureD3D::TextureD3D(RendererD3D *renderer) - : mRenderer(renderer), - mUsage(GL_NONE), +TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer) + : TextureImpl(state), + mRenderer(renderer), mDirtyImages(true), mImmutable(false), - mTexStorage(NULL) + mTexStorage(nullptr), + mBaseLevel(0) { } TextureD3D::~TextureD3D() { + ASSERT(!mTexStorage); } -gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage) +gl::Error TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage) { // ensure the underlying texture is created - gl::Error error = initializeStorage(false); - if (error.isError()) - { - return error; - } + ANGLE_TRY(initializeStorage(context, false)); if (mTexStorage) { - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } ASSERT(outStorage); *outStorage = mTexStorage; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error TextureD3D::getImageAndSyncFromStorage(const gl::Context *context, + const gl::ImageIndex &index, + ImageD3D **outImage) +{ + ImageD3D *image = getImage(index); + if (mTexStorage && mTexStorage->isRenderTarget()) + { + ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage)); + mDirtyImages = true; + } + *outImage = image; + return gl::NoError(); +} + +GLint TextureD3D::getLevelZeroWidth() const +{ + ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelWidth())) > getBaseLevel()); + return getBaseLevelWidth() << mBaseLevel; +} + +GLint TextureD3D::getLevelZeroHeight() const +{ + ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelHeight())) > getBaseLevel()); + return getBaseLevelHeight() << mBaseLevel; +} + +GLint TextureD3D::getLevelZeroDepth() const +{ + return getBaseLevelDepth(); } GLint TextureD3D::getBaseLevelWidth() const @@ -139,6 +163,27 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } +gl::Error TextureD3D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D::setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) +{ + UNREACHABLE(); + return gl::InternalError(); +} + bool TextureD3D::shouldUseSetData(const ImageD3D *image) const { if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) @@ -146,7 +191,12 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const return false; } - gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + if (image->isDirty()) + { + return false; + } + + gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); // We can only handle full updates for depth-stencil textures, so to avoid complications // disable them entirely. @@ -159,173 +209,166 @@ bool TextureD3D::shouldUseSetData(const ImageD3D *image) const return (mTexStorage && !internalFormat.compressed); } -gl::Error TextureD3D::setImageImpl(const gl::ImageIndex &index, +gl::Error TextureD3D::setImageImpl(const gl::Context *context, + const gl::ImageIndex &index, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) { ImageD3D *image = getImage(index); + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); ASSERT(image); // No-op if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); if (pixelData != nullptr) { if (shouldUseSetData(image)) { - error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); + ANGLE_TRY( + mTexStorage->setData(context, index, image, nullptr, type, unpack, pixelData)); } else { gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); - error = image->loadData(fullImageArea, unpack, type, pixelData); - } - - if (error.isError()) - { - return error; + ANGLE_TRY( + image->loadData(context, fullImageArea, unpack, type, pixelData, index.is3D())); } mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) +gl::Error TextureD3D::subImage(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, + ptrdiff_t layerOffset) { // CPU readback & copy where direct GPU copy is not supported - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); - if (pixelData != NULL) + if (pixelData != nullptr) { ImageD3D *image = getImage(index); ASSERT(image); if (shouldUseSetData(image)) { - return mTexStorage->setData(index, image, &area, type, unpack, pixelData); - } - - error = image->loadData(area, unpack, type, pixelData); - if (error.isError()) - { - return error; - } - - error = commitRegion(index, area); - if (error.isError()) - { - return error; + return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData); } + ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.is3D())); + ANGLE_TRY(commitRegion(context, index, area)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::setCompressedImageImpl(const gl::ImageIndex &index, +gl::Error TextureD3D::setCompressedImageImpl(const gl::Context *context, + const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) { - // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. - // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) + ImageD3D *image = getImage(index); + ASSERT(image); + + if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return error; + return gl::NoError(); } - if (pixelData != NULL) - { - ImageD3D *image = getImage(index); - ASSERT(image); + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); + if (pixelData != nullptr) + { gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); - error = image->loadCompressedData(fullImageArea, pixelData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, const uint8_t *pixels, +gl::Error TextureD3D::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) { - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); - if (error.isError()) - { - return error; - } + const uint8_t *pixelData = nullptr; + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); - if (pixelData != NULL) + if (pixelData != nullptr) { ImageD3D *image = getImage(index); ASSERT(image); - error = image->loadCompressedData(area, pixelData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->loadCompressedData(context, area, pixelData)); mDirtyImages = true; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) +bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer, GLenum sizedInternalFormat) { - return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); + return unpackBuffer != nullptr && + mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); } -gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget) +gl::Error TextureD3D::fastUnpackPixels(const gl::Context *context, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels, + const gl::Box &destArea, + GLenum sizedInternalFormat, + GLenum type, + RenderTargetD3D *destRenderTarget) { if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) { // TODO(jmadill): additional unpack parameters UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, - "Unimplemented pixel store parameters in fastUnpackPixels"); + return gl::InternalError() << "Unimplemented pixel store parameters in fastUnpackPixels"; } // No-op if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // In order to perform the fast copy through the shader, we must have the right format, and be able @@ -334,18 +377,17 @@ gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uintptr_t offset = reinterpret_cast<uintptr_t>(pixels); - gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, static_cast<unsigned int>(offset), destRenderTarget, sizedInternalFormat, type, destArea); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->fastCopyBufferToTexture(context, unpack, static_cast<unsigned int>(offset), + destRenderTarget, sizedInternalFormat, type, + destArea)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const { - if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) + if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || + mRenderer->getNativeExtensions().textureNPOT) { // Maximum number of levels return gl::log2(std::max(std::max(width, height), depth)) + 1; @@ -357,11 +399,6 @@ GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) c } } -int TextureD3D::mipLevels() const -{ - return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; -} - TextureStorage *TextureD3D::getStorage() { ASSERT(mTexStorage); @@ -370,72 +407,60 @@ TextureStorage *TextureD3D::getStorage() ImageD3D *TextureD3D::getBaseLevelImage() const { - return getImage(getImageIndex(0, 0)); + if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + return nullptr; + } + return getImage(getImageIndex(mBaseLevel, 0)); } -gl::Error TextureD3D::generateMipmaps(const gl::TextureState &textureState) +gl::Error TextureD3D::setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) { - GLint mipCount = mipLevels(); + // Only external images can accept external textures + UNREACHABLE(); + return gl::InternalError(); +} - if (mipCount == 1) - { - return gl::Error(GL_NO_ERROR); // no-op - } +gl::Error TextureD3D::generateMipmap(const gl::Context *context) +{ + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + ASSERT(maxLevel > baseLevel); // Should be checked before calling this. if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround) { // Switch to using the mipmapped texture. - TextureStorage *textureStorage = NULL; - gl::Error error = getNativeTexture(&textureStorage); - if (error.isError()) - { - return error; - } - - error = textureStorage->useLevelZeroWorkaroundTexture(false); - if (error.isError()) - { - return error; - } + TextureStorage *textureStorage = nullptr; + ANGLE_TRY(getNativeTexture(context, &textureStorage)); + ANGLE_TRY(textureStorage->useLevelZeroWorkaroundTexture(context, false)); } // Set up proper mipmap chain in our Image array. - initMipmapsImages(); + ANGLE_TRY(initMipmapImages(context)); if (mTexStorage && mTexStorage->supportsNativeMipmapFunction()) { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); // Generate the mipmap chain using the ad-hoc DirectX function. - error = mRenderer->generateMipmapsUsingD3D(mTexStorage, textureState); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState)); } else { // Generate the mipmap chain, one level at a time. - gl::Error error = generateMipmapsUsingImages(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(generateMipmapUsingImages(context, maxLevel)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::generateMipmapsUsingImages() +gl::Error TextureD3D::generateMipmapUsingImages(const gl::Context *context, const GLuint maxLevel) { - GLint mipCount = mipLevels(); - // We know that all layers have the same dimension, for the texture to be complete - GLint layerCount = static_cast<GLint>(getLayerCount(0)); + GLint layerCount = static_cast<GLint>(getLayerCount(mBaseLevel)); // When making mipmaps with the setData workaround enabled, the texture storage has // the image data already. For non-render-target storage, we have to pull it out into @@ -447,23 +472,15 @@ gl::Error TextureD3D::generateMipmapsUsingImages() // Copy from the storage mip 0 to Image mip 0 for (GLint layer = 0; layer < layerCount; ++layer) { - gl::ImageIndex srcIndex = getImageIndex(0, layer); + gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer); ImageD3D *image = getImage(srcIndex); - gl::Error error = image->copyFromTexStorage(srcIndex, mTexStorage); - if (error.isError()) - { - return error; - } + ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage)); } } else { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } } @@ -476,7 +493,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages() for (GLint layer = 0; layer < layerCount; ++layer) { - for (GLint mip = 1; mip < mipCount; ++mip) + for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip) { ASSERT(getLayerCount(mip) == layerCount); @@ -486,30 +503,25 @@ gl::Error TextureD3D::generateMipmapsUsingImages() if (renderableStorage) { // GPU-side mipmapping - gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex)); } else { // CPU-side mipmapping - gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex))); } } } + mDirtyImages = true; + if (mTexStorage) { - updateStorage(); + ANGLE_TRY(updateStorage(context)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool TextureD3D::isBaseImageZeroSize() const @@ -531,7 +543,7 @@ bool TextureD3D::isBaseImageZeroSize() const return true; } - if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) + if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(getBaseLevel()) <= 0) { return true; } @@ -539,12 +551,16 @@ bool TextureD3D::isBaseImageZeroSize() const return false; } -gl::Error TextureD3D::ensureRenderTarget() +gl::Error TextureD3D::ensureRenderTarget(const gl::Context *context) { - gl::Error error = initializeStorage(true); - if (error.isError()) + ANGLE_TRY(initializeStorage(context, true)); + + // initializeStorage can fail with NoError if the texture is not complete. This is not + // an error for incomplete sampling, but it is a big problem for rendering. + if (!mTexStorage) { - return error; + UNREACHABLE(); + return gl::InternalError() << "Cannot render to incomplete texture."; } if (!isBaseImageZeroSize()) @@ -552,94 +568,210 @@ gl::Error TextureD3D::ensureRenderTarget() ASSERT(mTexStorage); if (!mTexStorage->isRenderTarget()) { - TextureStorage *newRenderTargetStorage = NULL; - error = createCompleteStorage(true, &newRenderTargetStorage); - if (error.isError()) - { - return error; - } + TexStoragePointer newRenderTargetStorage(context); + ANGLE_TRY(createCompleteStorage(true, &newRenderTargetStorage)); - error = mTexStorage->copyToStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } - - error = setCompleteTexStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } + ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get())); + ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get())); + newRenderTargetStorage.release(); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const { + if (index.type == GL_TEXTURE_2D_MULTISAMPLE) + return true; + ImageD3D *image = getImage(index); + ASSERT(image); bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); return (image->isRenderableFormat() && levelsComplete); } -gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) +gl::Error TextureD3D::commitRegion(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box ®ion) { if (mTexStorage) { ASSERT(isValidIndex(index)); ImageD3D *image = getImage(index); - gl::Error error = image->copyToStorage(mTexStorage, index, region); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region)); image->markClean(); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D::getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, +gl::Error TextureD3D::getAttachmentRenderTarget(const gl::Context *context, + GLenum /*binding*/, + const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) { RenderTargetD3D *rtD3D = nullptr; - gl::Error error = getRenderTarget(target.textureIndex(), &rtD3D); + gl::Error error = getRenderTarget(context, imageIndex, &rtD3D); *rtOut = static_cast<FramebufferAttachmentRenderTarget *>(rtD3D); return error; } -TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) - : TextureD3D(renderer) +gl::Error TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel) +{ + const int oldStorageWidth = std::max(1, getLevelZeroWidth()); + const int oldStorageHeight = std::max(1, getLevelZeroHeight()); + const int oldStorageDepth = std::max(1, getLevelZeroDepth()); + const int oldStorageFormat = getBaseLevelInternalFormat(); + mBaseLevel = baseLevel; + + // When the base level changes, the texture storage might not be valid anymore, since it could + // have been created based on the dimensions of the previous specified level range. + const int newStorageWidth = std::max(1, getLevelZeroWidth()); + const int newStorageHeight = std::max(1, getLevelZeroHeight()); + const int newStorageDepth = std::max(1, getLevelZeroDepth()); + const int newStorageFormat = getBaseLevelInternalFormat(); + if (mTexStorage && + (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight || + newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat)) + { + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); + } + + return gl::NoError(); +} + +void TextureD3D::syncState(const gl::Texture::DirtyBits &dirtyBits) +{ + // TODO(geofflang): Use dirty bits +} + +gl::Error TextureD3D::releaseTexStorage(const gl::Context *context) +{ + if (!mTexStorage) + { + return gl::NoError(); + } + auto err = mTexStorage->onDestroy(context); + SafeDelete(mTexStorage); + return err; +} + +gl::Error TextureD3D::onDestroy(const gl::Context *context) +{ + return releaseTexStorage(context); +} + +gl::Error TextureD3D::initializeContents(const gl::Context *context, + const gl::ImageIndex &imageIndexIn) +{ + gl::ImageIndex imageIndex = imageIndexIn; + + // Special case for D3D11 3D textures. We can't create render targets for individual layers of a + // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we + // would lose existing data. + if (imageIndex.type == GL_TEXTURE_3D) + { + imageIndex.layerIndex = gl::ImageIndex::ENTIRE_LEVEL; + } + else if (imageIndex.type == GL_TEXTURE_2D_ARRAY && + imageIndex.layerIndex == gl::ImageIndex::ENTIRE_LEVEL) + { + GLsizei layerCount = getLayerCount(imageIndex.mipIndex); + for (imageIndex.layerIndex = 0; imageIndex.layerIndex < layerCount; ++imageIndex.layerIndex) + { + ANGLE_TRY(initializeContents(context, imageIndex)); + } + return gl::NoError(); + } + + // Force image clean. + ImageD3D *image = getImage(imageIndex); + if (image) + { + image->markClean(); + } + + // Fast path: can use a render target clear. + if (canCreateRenderTargetForImage(imageIndex)) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(mTexStorage); + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(mTexStorage->getRenderTarget(context, imageIndex, &renderTarget)); + ANGLE_TRY(mRenderer->initRenderTarget(renderTarget)); + return gl::NoError(); + } + + // Slow path: non-renderable texture or the texture levels aren't set up. + const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); + + size_t imageBytes = 0; + ANGLE_TRY_RESULT(formatInfo.computeRowPitch(formatInfo.type, image->getWidth(), 1, 0), + imageBytes); + imageBytes *= image->getHeight() * image->getDepth(); + + gl::PixelUnpackState defaultUnpackState; + + angle::MemoryBuffer *zeroBuffer = nullptr; + ANGLE_TRY(context->getZeroFilledBuffer(imageBytes, &zeroBuffer)); + if (shouldUseSetData(image)) + { + ANGLE_TRY(mTexStorage->setData(context, imageIndex, image, nullptr, formatInfo.type, + defaultUnpackState, zeroBuffer->data())); + } + else + { + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + ANGLE_TRY(image->loadData(context, fullImageArea, defaultUnpackState, formatInfo.type, + zeroBuffer->data(), false)); + + // Force an update to the tex storage so we avoid problems with subImage and dirty regions. + if (mTexStorage) + { + ANGLE_TRY(commitRegion(context, imageIndex, fullImageArea)); + image->markClean(); + } + else + { + mDirtyImages = true; + } + } + return gl::NoError(); +} + +TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { mEGLImageTarget = false; - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + for (auto &image : mImageArray) { - mImageArray[i] = renderer->createImage(); + image.reset(renderer->createImage()); } } -TextureD3D_2D::~TextureD3D_2D() +gl::Error TextureD3D_2D::onDestroy(const gl::Context *context) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. + for (auto &image : mImageArray) { - delete mImageArray[i]; + image.reset(); } + return TextureD3D::onDestroy(context); +} - SafeDelete(mTexStorage); +TextureD3D_2D::~TextureD3D_2D() +{ } ImageD3D *TextureD3D_2D::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer == 0); - return mImageArray[level]; + return mImageArray[level].get(); } ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const @@ -647,7 +779,7 @@ ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(!index.hasLayer()); ASSERT(index.type == GL_TEXTURE_2D); - return mImageArray[index.mipIndex]; + return mImageArray[index.mipIndex].get(); } GLsizei TextureD3D_2D::getLayerCount(int level) const @@ -682,10 +814,16 @@ GLenum TextureD3D_2D::getInternalFormat(GLint level) const bool TextureD3D_2D::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +bool TextureD3D_2D::isSRGB(GLint level) const +{ + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB; } -gl::Error TextureD3D_2D::setImage(GLenum target, +gl::Error TextureD3D_2D::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -696,33 +834,29 @@ gl::Error TextureD3D_2D::setImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D && size.depth == 1); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); bool fastUnpacked = false; GLint level = static_cast<GLint>(imageLevel); - redefineImage(level, sizedInternalFormat, size, false); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::Make2D(level); // Attempt a fast gpu copy of the pixel data to the surface - if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) && + isLevelComplete(level)) { // Will try to create RT storage if it does not exist - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(fastUnpackPixels(context, unpack, pixels, destArea, + internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); @@ -732,17 +866,14 @@ gl::Error TextureD3D_2D::setImage(GLenum target, if (!fastUnpacked) { - gl::Error error = setImageImpl(index, type, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, 0)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setSubImage(GLenum target, +gl::Error TextureD3D_2D::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -754,26 +885,26 @@ gl::Error TextureD3D_2D::setSubImage(GLenum target, GLint level = static_cast<GLint>(imageLevel); gl::ImageIndex index = gl::ImageIndex::Make2D(level); - if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) - { - RenderTargetD3D *renderTarget = NULL; - gl::Error error = getRenderTarget(index, &renderTarget); - if (error.isError()) - { - return error; - } + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, getInternalFormat(level)) && isLevelComplete(level)) + { + RenderTargetD3D *renderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &renderTarget)); ASSERT(!mImageArray[level]->isDirty()); - return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget); + return fastUnpackPixels(context, unpack, pixels, area, getInternalFormat(level), type, + renderTarget); } else { - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } } -gl::Error TextureD3D_2D::setCompressedImage(GLenum target, +gl::Error TextureD3D_2D::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -785,84 +916,120 @@ gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level = static_cast<GLint>(imageLevel); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, internalFormat, size, false); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); - return setCompressedImageImpl(gl::ImageIndex::Make2D(level), unpack, pixels, 0); + return setCompressedImageImpl(context, gl::ImageIndex::Make2D(level), unpack, pixels, 0); } -gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_2D::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0); gl::ImageIndex index = gl::ImageIndex::Make2D(static_cast<GLint>(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); - return commitRegion(index, area); + return commitRegion(context, index, area); } -gl::Error TextureD3D_2D::copyImage(GLenum target, +gl::Error TextureD3D_2D::copyImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Rectangle &sourceArea, + const gl::Rectangle &origSourceArea, GLenum internalFormat, const gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D); - GLint level = static_cast<GLint>(imageLevel); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); - redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1), - false); + GLint level = static_cast<GLint>(imageLevel); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); + gl::Extents sourceExtents(origSourceArea.width, origSourceArea.height, 1); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, sourceExtents, + false)); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + + // Does the read area extend beyond the framebuffer? + bool outside = origSourceArea.x < 0 || origSourceArea.y < 0 || + origSourceArea.x + origSourceArea.width > fbSize.width || + origSourceArea.y + origSourceArea.height > fbSize.height; + + // In WebGL mode we need to zero the texture outside the framebuffer. + // If we have robust resource init, it was already zeroed by redefineImage() above, otherwise + // zero it explicitly. + // TODO(fjhenigman): When robust resource is fully implemented look into making it a + // prerequisite for WebGL and deleting this code. + if (outside && + (context->getExtensions().webglCompatibility || context->isRobustResourceInitEnabled())) + { + angle::MemoryBuffer *zero; + ANGLE_TRY(context->getZeroFilledBuffer( + origSourceArea.width * origSourceArea.height * internalFormatInfo.pixelBytes, &zero)); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + ANGLE_TRY(setImage(context, target, imageLevel, internalFormat, sourceExtents, + internalFormatInfo.format, internalFormatInfo.type, unpack, + zero->data())); + } + + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + // Empty source area, nothing to do. + return gl::NoError(); + } gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Offset destOffset(0, 0, 0); + gl::Offset destOffset(sourceArea.x - origSourceArea.x, sourceArea.y - origSourceArea.y, 0); // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[level]->markClean(); + ANGLE_TRY(ensureRenderTarget(context)); if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level)) { - error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY(mRenderer->copyImage2D(context, source, sourceArea, internalFormat, + destOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::copySubImage(GLenum target, +gl::Error TextureD3D_2D::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Offset &destOffset, - const gl::Rectangle &sourceArea, + const gl::Offset &origDestOffset, + const gl::Rectangle &origSourceArea, const gl::Framebuffer *source) { - ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0); + ASSERT(target == GL_TEXTURE_2D && origDestOffset.z == 0); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + return gl::NoError(); + } + const gl::Offset destOffset(origDestOffset.x + sourceArea.x - origSourceArea.x, + origDestOffset.y + sourceArea.y - origSourceArea.y, 0); // can only make our texture storage to a render target if level 0 is defined (with a width & height) and // the current level we're copying to is defined (with appropriate format, width & height) @@ -874,44 +1041,162 @@ gl::Error TextureD3D_2D::copySubImage(GLenum target, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); + mDirtyImages = true; + } + else + { + ANGLE_TRY(ensureRenderTarget(context)); + + if (isValidLevel(level)) { - return error; + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY(mRenderer->copyImage2D(context, source, sourceArea, + gl::GetUnsizedFormat(getBaseLevelInternalFormat()), + destOffset, mTexStorage, level)); } + } + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(target == GL_TEXTURE_2D); + + GLenum sourceTarget = source->getTarget(); + + GLint destLevel = static_cast<GLint>(level); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)), + static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY( + redefineImage(context, destLevel, internalFormatInfo.sizedInternalFormat, size, false)); + + gl::Rectangle sourceRect(0, 0, size.width, size.height); + gl::Offset destOffset(0, 0, 0); + + if (!isSRGB(destLevel) && canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidLevel(destLevel)); + ANGLE_TRY(updateStorageLevel(context, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture(context, source, static_cast<GLint>(sourceLevel), + sourceRect, internalFormatInfo.format, destOffset, + mTexStorage, target, destLevel, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); + + gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); + + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceRect, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); mDirtyImages = true; + + gl::Box destRegion(destOffset, size); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_2D::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(target == GL_TEXTURE_2D); + + GLint destLevel = static_cast<GLint>(level); + + if (!isSRGB(destLevel) && canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidLevel(destLevel)); + ANGLE_TRY(updateStorageLevel(context, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture( + context, source, static_cast<GLint>(sourceLevel), sourceArea, + gl::GetUnsizedFormat(getInternalFormat(destLevel)), destOffset, mTexStorage, target, + destLevel, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); - if (isValidLevel(level)) - { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); - error = mRenderer->copyImage2D(source, sourceArea, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } - } + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceArea, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + + mDirtyImages = true; + + gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); +} + +gl::Error TextureD3D_2D::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source) +{ + GLenum sourceTarget = source->getTarget(); + GLint sourceLevel = 0; + + GLint destLevel = 0; + + GLenum sizedInternalFormat = + source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat; + gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)), + static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false)); + + ANGLE_TRY(initializeStorage(context, false)); + ASSERT(mTexStorage); + + ANGLE_TRY( + mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel)); + + return gl::NoError(); } -gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_2D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(GL_TEXTURE_2D && size.depth == 1); @@ -920,49 +1205,38 @@ gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum interna gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level), 1); - redefineImage(level, internalFormat, levelSize, true); + ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true)); } for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorage2D( - internalFormat, renderTarget, size.width, size.height, static_cast<int>(levels), false); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, + size.height, static_cast<int>(levels), false)); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - error = updateStorage(); + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface) { GLenum internalformat = surface->getConfig()->renderTargetFormat; gl::Extents size(surface->getWidth(), surface->getHeight(), 1); - redefineImage(0, internalformat, size, true); + ANGLE_TRY(redefineImage(context, 0, internalformat, size, true)); - if (mTexStorage) - { - SafeDelete(mTexStorage); - } + ANGLE_TRY(releaseTexStorage(context)); SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface); ASSERT(surfaceD3D); @@ -970,78 +1244,84 @@ void TextureD3D_2D::bindTexImage(egl::Surface *surface) mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain()); mEGLImageTarget = false; - mDirtyImages = true; + mDirtyImages = false; + mImageArray[0]->markClean(); + + return gl::NoError(); } -void TextureD3D_2D::releaseTexImage() +gl::Error TextureD3D_2D::releaseTexImage(const gl::Context *context) { if (mTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); } for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - redefineImage(i, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true)); } + + return gl::NoError(); } -gl::Error TextureD3D_2D::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_2D::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image); // Set the properties of the base mip level from the EGL image - GLenum internalformat = image->getInternalFormat(); + const auto &format = image->getFormat(); gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1); - redefineImage(0, internalformat, size, true); + ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true)); // Clear all other images. - for (size_t level = 1; level < ArraySize(mImageArray); level++) + for (size_t level = 1; level < mImageArray.size(); level++) { - redefineImage(level, GL_NONE, gl::Extents(0, 0, 1), true); + ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mImageArray[0]->markClean(); - mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d); + // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); + + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D); mEGLImageTarget = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::initMipmapsImages() +gl::Error TextureD3D_2D::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - 1); + gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), + std::max(getLevelZeroHeight() >> level, 1), 1); - redefineImage(level, getBaseLevelInternalFormat(), levelSize, false); + ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); } + return gl::NoError(); } -gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_2D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } bool TextureD3D_2D::isValidLevel(int level) const @@ -1056,10 +1336,8 @@ bool TextureD3D_2D::isLevelComplete(int level) const return true; } - const ImageD3D *baseImage = getBaseLevelImage(); - - GLsizei width = baseImage->getWidth(); - GLsizei height = baseImage->getHeight(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); if (width <= 0 || height <= 0) { @@ -1067,15 +1345,16 @@ bool TextureD3D_2D::isLevelComplete(int level) const } // The base image level is complete if the width and height are positive - if (level == 0) + if (level == static_cast<int>(getBaseLevel())) { return true; } - ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - ImageD3D *image = mImageArray[level]; + ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) && + mImageArray[level] != nullptr); + ImageD3D *image = mImageArray[level].get(); - if (image->getInternalFormat() != baseImage->getInternalFormat()) + if (image->getInternalFormat() != getBaseLevelInternalFormat()) { return false; } @@ -1099,52 +1378,41 @@ bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const } // Constructs a native texture resource from the texture images -gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2D::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0); @@ -1165,84 +1433,83 @@ gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage } // TODO(geofflang): Determine if the texture creation succeeded - *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly); + outStorage->reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, + levels, hintLevelZeroOnly)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2D::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY( + mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level)); } } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2D::updateStorage() +gl::Error TextureD3D_2D::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (mImageArray[level]->isDirty() && isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } -gl::Error TextureD3D_2D::updateStorageLevel(int level) +gl::Error TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { gl::ImageIndex index = gl::ImageIndex::Make2D(level); gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2D::redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease) +gl::Error TextureD3D_2D::redefineImage(const gl::Context *context, + size_t level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { ASSERT(size.depth == 1); // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); if (mTexStorage) { @@ -1252,27 +1519,23 @@ void TextureD3D_2D::redefineImage(size_t level, // while orphaning if (level != 0 && mEGLImageTarget) { - // TODO(jmadill): Don't discard error. - mImageArray[0]->copyFromTexStorage(gl::ImageIndex::Make2D(0), mTexStorage); + ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0), + mTexStorage)); } - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || size.height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage + internalformat != storageFormat) // Discard mismatched storage { - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; + ANGLE_TRY(releaseTexStorage(context)); + markAllImagesDirty(); } } // Can't be an EGL image target after being redefined mEGLImageTarget = false; + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_2D::imageIterator() const @@ -1292,46 +1555,58 @@ bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_2D::markAllImagesDirty() +{ + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + mDirtyImages = true; +} + +TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { - for (int i = 0; i < 6; i++) + for (auto &face : mImageArray) { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + for (auto &image : face) { - mImageArray[i][j] = renderer->createImage(); + image.reset(renderer->createImage()); } } } -TextureD3D_Cube::~TextureD3D_Cube() +gl::Error TextureD3D_Cube::onDestroy(const gl::Context *context) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < 6; i++) + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. + for (auto &face : mImageArray) { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + for (auto &image : face) { - SafeDelete(mImageArray[i][j]); + image.reset(); } } + return TextureD3D::onDestroy(context); +} - SafeDelete(mTexStorage); +TextureD3D_Cube::~TextureD3D_Cube() +{ } ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer >= 0 && layer < 6); - return mImageArray[layer][level]; + return mImageArray[layer][level].get(); } ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const { ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(index.layerIndex >= 0 && index.layerIndex < 6); - return mImageArray[index.layerIndex][index.mipIndex]; + return mImageArray[index.layerIndex][index.mipIndex].get(); } GLsizei TextureD3D_Cube::getLayerCount(int level) const @@ -1350,128 +1625,191 @@ GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const { - return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; } -gl::Error TextureD3D_Cube::setEGLImageTarget(GLenum target, egl::Image *image) +bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const +{ + return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB; +} + +gl::Error TextureD3D_Cube::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) { ASSERT(size.depth == 1); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level)); - redefineImage(index.layerIndex, static_cast<GLint>(level), sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, index.layerIndex, static_cast<GLint>(level), + internalFormatInfo.sizedInternalFormat, size, false)); - return setImageImpl(index, type, unpack, pixels, 0); + return setImageImpl(context, index, type, unpack, pixels, 0); } -gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) { ASSERT(area.depth == 1 && area.z == 0); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level)); - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } -gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(size.depth == 1); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); - redefineImage(static_cast<int>(faceIndex), static_cast<GLint>(level), internalFormat, size); + ANGLE_TRY(redefineImage(context, static_cast<int>(faceIndex), static_cast<GLint>(level), + internalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level)); - return setCompressedImageImpl(index, unpack, pixels, 0); + return setCompressedImageImpl(context, index, unpack, pixels, 0); } -gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_Cube::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(area.depth == 1 && area.z == 0); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, static_cast<GLint>(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } - - return commitRegion(index, area); + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); + return commitRegion(context, index, area); } -gl::Error TextureD3D_Cube::copyImage(GLenum target, +gl::Error TextureD3D_Cube::copyImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Rectangle &sourceArea, + const gl::Rectangle &origSourceArea, GLenum internalFormat, const gl::Framebuffer *source) { int faceIndex = static_cast<int>(gl::CubeMapTextureTargetToLayerIndex(target)); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + const gl::InternalFormat &internalFormatInfo = + gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); GLint level = static_cast<GLint>(imageLevel); - gl::Extents size(sourceArea.width, sourceArea.height, 1); - redefineImage(static_cast<int>(faceIndex), level, sizedInternalFormat, size); + gl::Extents size(origSourceArea.width, origSourceArea.height, 1); + ANGLE_TRY(redefineImage(context, static_cast<int>(faceIndex), level, + internalFormatInfo.sizedInternalFormat, size, false)); + + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + + // Does the read area extend beyond the framebuffer? + bool outside = origSourceArea.x < 0 || origSourceArea.y < 0 || + origSourceArea.x + origSourceArea.width > fbSize.width || + origSourceArea.y + origSourceArea.height > fbSize.height; + + // In WebGL mode we need to zero the texture outside the framebuffer. + // If we have robust resource init, it was already zeroed by redefineImage() above, otherwise + // zero it explicitly. + // TODO(fjhenigman): When robust resource is fully implemented look into making it a + // prerequisite for WebGL and deleting this code. + if (outside && context->getExtensions().webglCompatibility && + !context->isRobustResourceInitEnabled()) + { + angle::MemoryBuffer *zero; + ANGLE_TRY(context->getZeroFilledBuffer( + origSourceArea.width * origSourceArea.height * internalFormatInfo.pixelBytes, &zero)); + gl::PixelUnpackState unpack; + unpack.alignment = 1; + ANGLE_TRY(setImage(context, target, imageLevel, internalFormat, size, + internalFormatInfo.format, internalFormatInfo.type, unpack, + zero->data())); + } + + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + // Empty source area, nothing to do. + return gl::NoError(); + } gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - gl::Offset destOffset(0, 0, 0); + gl::Offset destOffset(sourceArea.x - origSourceArea.x, sourceArea.y - origSourceArea.y, 0); // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = - mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - + ANGLE_TRY(mImageArray[faceIndex][level]->copyFromFramebuffer(context, destOffset, + sourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[faceIndex][level]->markClean(); + ANGLE_TRY(ensureRenderTarget(context)); ASSERT(size.width == size.height); if (size.width > 0 && isValidFaceLevel(faceIndex, level)) { - error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, level)); + ANGLE_TRY(mRenderer->copyImageCube(context, source, sourceArea, internalFormat, + destOffset, mTexStorage, target, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::copySubImage(GLenum target, +gl::Error TextureD3D_Cube::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, - const gl::Offset &destOffset, - const gl::Rectangle &sourceArea, + const gl::Offset &origDestOffset, + const gl::Rectangle &origSourceArea, const gl::Framebuffer *source) { + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle sourceArea; + if (!ClipRectangle(origSourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &sourceArea)) + { + return gl::NoError(); + } + const gl::Offset destOffset(origDestOffset.x + sourceArea.x - origSourceArea.x, + origDestOffset.y + sourceArea.y - origSourceArea.y, 0); + int faceIndex = static_cast<int>(gl::CubeMapTextureTargetToLayerIndex(target)); GLint level = static_cast<GLint>(imageLevel); @@ -1481,44 +1819,145 @@ gl::Error TextureD3D_Cube::copySubImage(GLenum target, // so we should use the non-rendering copy path. if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) { - gl::Error error = - mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) + ANGLE_TRY(mImageArray[faceIndex][level]->copyFromFramebuffer(context, destOffset, + sourceArea, source)); + mDirtyImages = true; + } + else + { + ANGLE_TRY(ensureRenderTarget(context)); + if (isValidFaceLevel(faceIndex, level)) { - return error; + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, level)); + ANGLE_TRY(mRenderer->copyImageCube(context, source, sourceArea, + gl::GetUnsizedFormat(getBaseLevelInternalFormat()), + destOffset, mTexStorage, target, level)); } + } + + return gl::NoError(); +} + +gl::Error TextureD3D_Cube::copyTexture(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + GLenum type, + size_t sourceLevel, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + + GLenum sourceTarget = source->getTarget(); + + GLint destLevel = static_cast<GLint>(level); + int faceIndex = static_cast<int>(gl::CubeMapTextureTargetToLayerIndex(target)); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)), + static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1); + ANGLE_TRY(redefineImage(context, faceIndex, destLevel, internalFormatInfo.sizedInternalFormat, + size, false)); + + gl::Rectangle sourceRect(0, 0, size.width, size.height); + gl::Offset destOffset(0, 0, 0); + + if (!isSRGB(destLevel, faceIndex) && + canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidFaceLevel(faceIndex, destLevel)); + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture(context, source, static_cast<GLint>(sourceLevel), + sourceRect, internalFormatInfo.format, destOffset, + mTexStorage, target, destLevel, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + } + else + { + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); + + gl::ImageIndex destImageIndex = + gl::ImageIndex::MakeCube(target, static_cast<GLint>(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); + + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceRect, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); mDirtyImages = true; + + gl::Box destRegion(destOffset, size); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_Cube::copySubTexture(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + bool unpackFlipY, + bool unpackPremultiplyAlpha, + bool unpackUnmultiplyAlpha, + const gl::Texture *source) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + + GLint destLevel = static_cast<GLint>(level); + int faceIndex = static_cast<int>(gl::CubeMapTextureTargetToLayerIndex(target)); + + if (!isSRGB(destLevel, faceIndex) && + canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel))) + { + ANGLE_TRY(ensureRenderTarget(context)); + ASSERT(isValidFaceLevel(faceIndex, destLevel)); + ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, destLevel)); + + ANGLE_TRY(mRenderer->copyTexture( + context, source, static_cast<GLint>(sourceLevel), sourceArea, + gl::GetUnsizedFormat(getInternalFormat(destLevel, faceIndex)), destOffset, mTexStorage, + target, destLevel, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel)); + TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); + ImageD3D *sourceImage = nullptr; + ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); - if (isValidFaceLevel(faceIndex, level)) - { - error = updateStorageFaceLevel(faceIndex, level); - if (error.isError()) - { - return error; - } + gl::ImageIndex destImageIndex = + gl::ImageIndex::MakeCube(target, static_cast<GLint>(destLevel)); + ImageD3D *destImage = nullptr; + ANGLE_TRY(getImageAndSyncFromStorage(context, destImageIndex, &destImage)); - error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, target, level); - if (error.isError()) - { - return error; - } - } + ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceArea, destOffset, + unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); + + mDirtyImages = true; + + gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceArea.width, sourceArea.height, 1); + ANGLE_TRY(commitRegion(context, destImageIndex, destRegion)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_Cube::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(size.width == size.height); ASSERT(size.depth == 1); @@ -1541,28 +1980,20 @@ gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum inter } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); - TextureStorage *storage = mRenderer->createTextureStorageCube( - internalFormat, renderTarget, size.width, static_cast<int>(levels), false); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, + static_cast<int>(levels), false)); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - error = updateStorage(); + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. @@ -1579,7 +2010,7 @@ bool TextureD3D_Cube::isCubeComplete() const for (int faceIndex = 1; faceIndex < 6; faceIndex++) { - const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; + const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()]; if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight || @@ -1592,97 +2023,85 @@ bool TextureD3D_Cube::isCubeComplete() const return true; } -void TextureD3D_Cube::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_Cube::releaseTexImage() +gl::Error TextureD3D_Cube::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_Cube::initMipmapsImages() +gl::Error TextureD3D_Cube::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. for (int faceIndex = 0; faceIndex < 6; faceIndex++) { - for (int level = 1; level < levelCount; level++) + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); - redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), - gl::Extents(faceLevelSize, faceLevelSize, 1)); + int faceLevelSize = + (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1)); + ANGLE_TRY(redefineImage(context, faceIndex, level, + mImageArray[faceIndex][baseLevel]->getInternalFormat(), + gl::Extents(faceLevelSize, faceLevelSize, 1), false)); } } + return gl::NoError(); } -gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_Cube::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { ASSERT(gl::IsCubeMapTextureTarget(index.type)); // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageFaceLevel(index.layerIndex, index.mipIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageFaceLevel(context, index.layerIndex, index.mipIndex)); - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) +gl::Error TextureD3D_Cube::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isFaceLevelComplete(0, 0)) + if (!isFaceLevelComplete(0, getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei size = getBaseLevelWidth(); + GLsizei size = getLevelZeroWidth(); ASSERT(size > 0); @@ -1705,12 +2124,14 @@ gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStora } // TODO (geofflang): detect if storage creation succeeded - *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly); + outStorage->reset(mRenderer->createTextureStorageCube( + getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { @@ -1718,25 +2139,27 @@ gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexS { for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube( + context, newCompleteTexStorage, faceIndex, level)); } } } - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_Cube::updateStorage() +gl::Error TextureD3D_Cube::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int face = 0; face < 6; face++) { @@ -1744,16 +2167,13 @@ gl::Error TextureD3D_Cube::updateStorage() { if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) { - gl::Error error = updateStorageFaceLevel(face, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageFaceLevel(context, face, level)); } } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const @@ -1763,16 +2183,21 @@ bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const { - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + return false; + } + ASSERT(level >= 0 && faceIndex < 6 && level < static_cast<int>(mImageArray[faceIndex].size()) && + mImageArray[faceIndex][level] != nullptr); if (isImmutable()) { return true; } - int baseSize = getBaseLevelWidth(); + int levelZeroSize = getLevelZeroWidth(); - if (baseSize <= 0) + if (levelZeroSize <= 0) { return false; } @@ -1786,14 +2211,14 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const } // Check that non-zero levels are consistent with the base level. - const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; + const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get(); if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) { return false; } - if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) + if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level)) { return false; } @@ -1806,57 +2231,55 @@ bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const return isFaceLevelComplete(index.layerIndex, index.mipIndex); } -gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +gl::Error TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context, + int faceIndex, + int level) { - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); - ImageD3D *image = mImageArray[faceIndex][level]; + ASSERT(level >= 0 && faceIndex < 6 && level < static_cast<int>(mImageArray[faceIndex].size()) && + mImageArray[faceIndex][level] != nullptr); + ImageD3D *image = mImageArray[faceIndex][level].get(); if (image->isDirty()) { GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex); gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_Cube::redefineImage(const gl::Context *context, + int faceIndex, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); - mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false); + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, + forceRelease); + mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty(); if (mTexStorage) { const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || size.height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage + internalformat != storageFormat) // Discard mismatched storage { - for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) - { - for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) - { - mImageArray[dirtyFace][dirtyLevel]->markDirty(); - } - } - - SafeDelete(mTexStorage); - - mDirtyImages = true; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const @@ -1876,33 +2299,48 @@ bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_Cube::markAllImagesDirty() { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) { - mImageArray[i] = renderer->createImage(); + for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) + { + mImageArray[dirtyFace][dirtyLevel]->markDirty(); + } } + mDirtyImages = true; } -TextureD3D_3D::~TextureD3D_3D() +TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) { - delete mImageArray[i]; + mImageArray[i].reset(renderer->createImage()); } +} - SafeDelete(mTexStorage); +gl::Error TextureD3D_3D::onDestroy(const gl::Context *context) +{ + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. + for (auto &image : mImageArray) + { + image.reset(); + } + return TextureD3D::onDestroy(context); +} + +TextureD3D_3D::~TextureD3D_3D() +{ } ImageD3D *TextureD3D_3D::getImage(int level, int layer) const { ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(layer == 0); - return mImageArray[level]; + return mImageArray[level].get(); } ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const @@ -1910,7 +2348,7 @@ ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(!index.hasLayer()); ASSERT(index.type == GL_TEXTURE_3D); - return mImageArray[index.mipIndex]; + return mImageArray[index.mipIndex].get(); } GLsizei TextureD3D_3D::getLayerCount(int level) const @@ -1953,16 +2391,19 @@ GLenum TextureD3D_3D::getInternalFormat(GLint level) const bool TextureD3D_3D::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -gl::Error TextureD3D_3D::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_3D::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_3D::setImage(GLenum target, +gl::Error TextureD3D_3D::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -1972,33 +2413,29 @@ gl::Error TextureD3D_3D::setImage(GLenum target, const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_3D); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); GLint level = static_cast<GLint>(imageLevel); - redefineImage(level, sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormatInfo.sizedInternalFormat, size, false)); bool fastUnpacked = false; gl::ImageIndex index = gl::ImageIndex::Make3D(level); // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer - if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty()) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) && !size.empty() && + isLevelComplete(level)) { // Will try to create RT storage if it does not exist - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } + ANGLE_TRY(fastUnpackPixels(context, unpack, pixels, destArea, + internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); @@ -2008,17 +2445,14 @@ gl::Error TextureD3D_3D::setImage(GLenum target, if (!fastUnpacked) { - gl::Error error = setImageImpl(index, type, unpack, pixels, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, 0)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setSubImage(GLenum target, +gl::Error TextureD3D_3D::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -2032,26 +2466,25 @@ gl::Error TextureD3D_3D::setSubImage(GLenum target, gl::ImageIndex index = gl::ImageIndex::Make3D(level); // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer - if (isFastUnpackable(unpack, getInternalFormat(level))) + gl::Buffer *unpackBuffer = + context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); + if (isFastUnpackable(unpackBuffer, getInternalFormat(level)) && isLevelComplete(level)) { - RenderTargetD3D *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - + RenderTargetD3D *destRenderTarget = nullptr; + ANGLE_TRY(getRenderTarget(context, index, &destRenderTarget)); ASSERT(!mImageArray[level]->isDirty()); - return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget); + return fastUnpackPixels(context, unpack, pixels, area, getInternalFormat(level), type, + destRenderTarget); } else { - return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + return TextureD3D::subImage(context, index, area, format, type, unpack, pixels, 0); } } -gl::Error TextureD3D_3D::setCompressedImage(GLenum target, +gl::Error TextureD3D_3D::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2063,35 +2496,41 @@ gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level = static_cast<GLint>(imageLevel); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, internalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); gl::ImageIndex index = gl::ImageIndex::Make3D(level); - return setCompressedImageImpl(index, unpack, pixels, 0); + return setCompressedImageImpl(context, index, unpack, pixels, 0); } -gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_3D::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_3D); gl::ImageIndex index = gl::ImageIndex::Make3D(static_cast<GLint>(level)); - gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); - if (error.isError()) - { - return error; - } - - return commitRegion(index, area); + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); + return commitRegion(context, index, area); } -gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, +gl::Error TextureD3D_3D::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) { UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented."); + return gl::InternalError() << "Copying 3D textures is unimplemented."; } -gl::Error TextureD3D_3D::copySubImage(GLenum target, +gl::Error TextureD3D_3D::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, @@ -2099,49 +2538,47 @@ gl::Error TextureD3D_3D::copySubImage(GLenum target, { ASSERT(target == GL_TEXTURE_3D); - GLint level = static_cast<GLint>(imageLevel); - gl::ImageIndex index = gl::ImageIndex::Make3D(level); + GLint level = static_cast<GLint>(imageLevel); - if (canCreateRenderTargetForImage(index)) + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle clippedSourceArea; + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &clippedSourceArea)) { - gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; + return gl::NoError(); } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, + destOffset.y + clippedSourceArea.y - sourceArea.y, + destOffset.z); - if (isValidLevel(level)) - { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + // Currently, copying directly to the storage is not possible because it's not possible to + // create an SRV from a single layer of a 3D texture. Instead, make sure the image is up to + // date before the copy and then copy back to the storage afterwards if needed. + // TODO: Investigate 3D blits in D3D11. - error = mRenderer->copyImage3D(source, sourceArea, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } - } + bool syncTexStorage = mTexStorage && isLevelComplete(level); + if (syncTexStorage) + { + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + ANGLE_TRY(mImageArray[level]->copyFromTexStorage(context, index, mTexStorage)); } + ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, clippedDestOffset, clippedSourceArea, + source)); + mDirtyImages = true; - return gl::Error(GL_NO_ERROR); + if (syncTexStorage) + { + ANGLE_TRY(updateStorageLevel(context, level)); + } + + return gl::NoError(); } -gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_3D::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(target == GL_TEXTURE_3D); @@ -2159,130 +2596,106 @@ gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum interna } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = - mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, - size.depth, static_cast<int>(levels)); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, + size.height, size.depth, + static_cast<int>(levels))); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - error = updateStorage(); - - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_3D::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_3D::releaseTexImage() +gl::Error TextureD3D_3D::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_3D::initMipmapsImages() +gl::Error TextureD3D_3D::initMipmapImages(const gl::Context *context) { - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1; level <= maxLevel; level++) { - gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - std::max(getBaseLevelDepth() >> level, 1)); - redefineImage(level, getBaseLevelInternalFormat(), levelSize); + gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), + std::max(getLevelZeroHeight() >> level, 1), + std::max(getLevelZeroDepth() >> level, 1)); + ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); } + + return gl::NoError(); } -gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_3D::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); if (index.hasLayer()) { - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); } else { - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); } - return mTexStorage->getRenderTarget(index, outRT); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_3D::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLevelZeroDepth(); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2291,40 +2704,44 @@ gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); // TODO: Verify creation of the storage succeeded - *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); + outStorage->reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, + depth, levels)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_3D::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; // We do not support managed 3D storage, as that is D3D9/ES2-only ASSERT(!mTexStorage->isManaged()); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_3D::updateStorage() +gl::Error TextureD3D_3D::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (mImageArray[level]->isDirty() && isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_3D::isValidLevel(int level) const @@ -2334,28 +2751,29 @@ bool TextureD3D_3D::isValidLevel(int level) const bool TextureD3D_3D::isLevelComplete(int level) const { - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) && + mImageArray[level] != nullptr); if (isImmutable()) { return true; } - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLevelZeroDepth(); if (width <= 0 || height <= 0 || depth <= 0) { return false; } - if (level == 0) + if (level == static_cast<int>(getBaseLevel())) { return true; } - ImageD3D *levelImage = mImageArray[level]; + ImageD3D *levelImage = mImageArray[level].get(); if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) { @@ -2385,54 +2803,51 @@ bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const return isLevelComplete(index.mipIndex); } -gl::Error TextureD3D_3D::updateStorageLevel(int level) +gl::Error TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) && + mImageArray[level] != nullptr); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { gl::ImageIndex index = gl::ImageIndex::Make3D(level); gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_3D::redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = std::max(1, getBaseLevelDepth() >> level); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); + const int storageDepth = std::max(1, getLevelZeroDepth() >> level); const GLenum storageFormat = getBaseLevelInternalFormat(); - mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false); + mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); if (mTexStorage) { const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || - size.height != storageHeight || - size.depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || + size.height != storageHeight || size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_3D::imageIterator() const @@ -2453,23 +2868,42 @@ bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); } -TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) - : TextureD3D(renderer) +void TextureD3D_3D::markAllImagesDirty() +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + mDirtyImages = true; +} + +GLint TextureD3D_3D::getLevelZeroDepth() const +{ + ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel()); + return getBaseLevelDepth() << getBaseLevel(); +} + +TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) { for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) { mLayerCounts[level] = 0; - mImageArray[level] = NULL; + mImageArray[level] = nullptr; } } -TextureD3D_2DArray::~TextureD3D_2DArray() +gl::Error TextureD3D_2DArray::onDestroy(const gl::Context *context) { - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage + // for some of their data. If TextureStorage is deleted before the Images, then their data will + // be wastefully copied back from the GPU before we delete the Images. deleteImages(); - SafeDelete(mTexStorage); + return TextureD3D::onDestroy(context); +} + +TextureD3D_2DArray::~TextureD3D_2DArray() +{ } ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const @@ -2477,16 +2911,17 @@ ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]); - return (mImageArray[level] ? mImageArray[level][layer] : NULL); + return (mImageArray[level] ? mImageArray[level][layer] : nullptr); } ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const { ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(index.layerIndex != gl::ImageIndex::ENTIRE_LEVEL); ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) || index.layerIndex < mLayerCounts[index.mipIndex]); ASSERT(index.type == GL_TEXTURE_2D_ARRAY); - return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL); + return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : nullptr); } GLsizei TextureD3D_2DArray::getLayerCount(int level) const @@ -2512,16 +2947,19 @@ GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const bool TextureD3D_2DArray::isDepth(GLint level) const { - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; + return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -gl::Error TextureD3D_2DArray::setEGLImageTarget(GLenum target, egl::Image *image) +gl::Error TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) { UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + return gl::InternalError(); } -gl::Error TextureD3D_2DArray::setImage(GLenum target, +gl::Error TextureD3D_2DArray::setImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2532,30 +2970,28 @@ gl::Error TextureD3D_2DArray::setImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D_ARRAY); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); GLint level = static_cast<GLint>(imageLevel); - redefineImage(level, sizedInternalFormat, size); + ANGLE_TRY(redefineImage(context, level, formatInfo.sizedInternalFormat, size, false)); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch( - type, size.width, size.height, unpack.alignment, unpack.rowLength, unpack.imageHeight); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment, + unpack.rowLength, unpack.imageHeight), + inputDepthPitch); for (int i = 0; i < size.depth; i++) { const ptrdiff_t layerOffset = (inputDepthPitch * i); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); - gl::Error error = setImageImpl(index, type, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setImageImpl(context, index, type, unpack, pixels, layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setSubImage(GLenum target, +gl::Error TextureD3D_2DArray::setSubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Box &area, GLenum format, @@ -2565,9 +3001,12 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, { ASSERT(target == GL_TEXTURE_2D_ARRAY); GLint level = static_cast<GLint>(imageLevel); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level)); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch( - type, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight); + const gl::InternalFormat &formatInfo = + gl::GetInternalFormatInfo(getInternalFormat(level), type); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, + unpack.rowLength, unpack.imageHeight), + inputDepthPitch); for (int i = 0; i < area.depth; i++) { @@ -2577,17 +3016,15 @@ gl::Error TextureD3D_2DArray::setSubImage(GLenum target, gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImage(context, index, layerArea, format, type, unpack, pixels, + layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, +gl::Error TextureD3D_2DArray::setCompressedImage(const gl::Context *context, + GLenum target, size_t imageLevel, GLenum internalFormat, const gl::Extents &size, @@ -2599,35 +3036,41 @@ gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level = static_cast<GLint>(imageLevel); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, internalFormat, size); + ANGLE_TRY(redefineImage(context, level, internalFormat, size, false)); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - GLsizei inputDepthPitch = - formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0), + inputDepthPitch); for (int i = 0; i < size.depth; i++) { const ptrdiff_t layerOffset = (inputDepthPitch * i); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); - gl::Error error = setCompressedImageImpl(index, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } + ANGLE_TRY(setCompressedImageImpl(context, index, unpack, pixels, layerOffset)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, - const gl::PixelUnpackState &unpack, size_t imageSize, const uint8_t *pixels) +gl::Error TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) { ASSERT(target == GL_TEXTURE_2D_ARRAY); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); - GLsizei inputDepthPitch = - formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); + GLsizei inputDepthPitch = 0; + ANGLE_TRY_RESULT( + formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0), + inputDepthPitch); for (int i = 0; i < area.depth; i++) { @@ -2637,30 +3080,27 @@ gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); gl::ImageIndex index = gl::ImageIndex::Make2DArray(static_cast<GLint>(level), layer); - gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, pixels, layerOffset); - if (error.isError()) - { - return error; - } - - error = commitRegion(index, layerArea); - if (error.isError()) - { - return error; - } + ANGLE_TRY(TextureD3D::subImageCompressed(context, index, layerArea, format, unpack, pixels, + layerOffset)); + ANGLE_TRY(commitRegion(context, index, layerArea)); } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, +gl::Error TextureD3D_2DArray::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, const gl::Framebuffer *source) { UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented."); + return gl::InternalError() << "Copying 2D array textures is unimplemented."; } -gl::Error TextureD3D_2DArray::copySubImage(GLenum target, +gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context, + GLenum target, size_t imageLevel, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, @@ -2671,46 +3111,45 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level = static_cast<GLint>(imageLevel); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); - if (canCreateRenderTargetForImage(index)) + gl::Extents fbSize = source->getReadColorbuffer()->getSize(); + gl::Rectangle clippedSourceArea; + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), + &clippedSourceArea)) { - gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); - gl::Error error = mImageArray[level][destOffset.z]->copyFromFramebuffer(destLayerOffset, - sourceArea, source); - if (error.isError()) - { - return error; - } + return gl::NoError(); + } + const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, + destOffset.y + clippedSourceArea.y - sourceArea.y, + destOffset.z); + if (!canCreateRenderTargetForImage(index)) + { + gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0); + ANGLE_TRY(mImageArray[level][clippedDestOffset.z]->copyFromFramebuffer( + context, destLayerOffset, clippedSourceArea, source)); mDirtyImages = true; } else { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(ensureRenderTarget(context)); if (isValidLevel(level)) { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format, - destOffset, mTexStorage, level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); + ANGLE_TRY( + mRenderer->copyImage2DArray(context, source, clippedSourceArea, + gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())), + clippedDestOffset, mTexStorage, level)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +gl::Error TextureD3D_2DArray::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -2738,124 +3177,103 @@ gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum in } // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = - mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, - size.height, size.depth, static_cast<int>(levels)); + bool renderTarget = IsRenderTargetUsage(mState.getUsage()); + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, + size.height, size.depth, + static_cast<int>(levels))); - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); - error = updateStorage(); - - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); mImmutable = true; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) +gl::Error TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface) { UNREACHABLE(); + return gl::InternalError(); } -void TextureD3D_2DArray::releaseTexImage() +gl::Error TextureD3D_2DArray::releaseTexImage(const gl::Context *context) { UNREACHABLE(); + return gl::InternalError(); } - -void TextureD3D_2DArray::initMipmapsImages() +gl::Error TextureD3D_2DArray::initMipmapImages(const gl::Context *context) { - int baseWidth = getBaseLevelWidth(); - int baseHeight = getBaseLevelHeight(); - int baseDepth = getLayerCount(0); + const GLuint baseLevel = mState.getEffectiveBaseLevel(); + const GLuint maxLevel = mState.getMipmapMaxLevel(); + int baseWidth = getLevelZeroWidth(); + int baseHeight = getLevelZeroHeight(); + int baseDepth = getLayerCount(getBaseLevel()); GLenum baseFormat = getBaseLevelInternalFormat(); - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) + // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap + // levels. + for (GLuint level = baseLevel + 1u; level <= maxLevel; level++) { + ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0); gl::Extents levelLayerSize(std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); - redefineImage(level, baseFormat, levelLayerSize); + ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false)); } + + return gl::NoError(); } -gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +gl::Error TextureD3D_2DArray::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) { // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); + ANGLE_TRY(ensureRenderTarget(context)); + ANGLE_TRY(updateStorageLevel(context, index.mipIndex)); + return mTexStorage->getRenderTarget(context, index, outRT); } -gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2DArray::initializeStorage(const gl::Context *context, bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) + if (!isLevelComplete(getBaseLevel())) { - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); ASSERT(mTexStorage); // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorage(context)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const { - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getLayerCount(0); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); + GLsizei depth = getLayerCount(getBaseLevel()); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2864,40 +3282,44 @@ gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureSt GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); // TODO(geofflang): Verify storage creation succeeds - *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + outStorage->reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, + height, depth, levels)); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); + ANGLE_TRY(releaseTexStorage(context)); mTexStorage = newCompleteTexStorage; mDirtyImages = true; // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only ASSERT(!mTexStorage->isManaged()); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error TextureD3D_2DArray::updateStorage() +gl::Error TextureD3D_2DArray::updateStorage(const gl::Context *context) { - ASSERT(mTexStorage != NULL); + if (!mDirtyImages) + { + return gl::NoError(); + } + + ASSERT(mTexStorage != nullptr); GLint storageLevels = mTexStorage->getLevelCount(); for (int level = 0; level < storageLevels; level++) { if (isLevelComplete(level)) { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } + ANGLE_TRY(updateStorageLevel(context, level)); } } - return gl::Error(GL_NO_ERROR); + mDirtyImages = false; + return gl::NoError(); } bool TextureD3D_2DArray::isValidLevel(int level) const @@ -2914,21 +3336,29 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const return true; } - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei layers = getLayerCount(0); + GLsizei width = getLevelZeroWidth(); + GLsizei height = getLevelZeroHeight(); - if (width <= 0 || height <= 0 || layers <= 0) + if (width <= 0 || height <= 0) { return false; } - if (level == 0) + // Layers check needs to happen after the above checks, otherwise out-of-range base level may be + // queried. + GLsizei layers = getLayerCount(getBaseLevel()); + + if (layers <= 0) + { + return false; + } + + if (level == static_cast<int>(getBaseLevel())) { return true; } - if (getInternalFormat(level) != getInternalFormat(0)) + if (getInternalFormat(level) != getInternalFormat(getBaseLevel())) { return false; } @@ -2956,27 +3386,23 @@ bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const return isLevelComplete(index.mipIndex); } -gl::Error TextureD3D_2DArray::updateStorageLevel(int level) +gl::Error TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level) { - ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); + ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts))); ASSERT(isLevelComplete(level)); for (int layer = 0; layer < mLayerCounts[level]; layer++) { - ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); + ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr); if (mImageArray[level][layer]->isDirty()) { gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } + ANGLE_TRY(commitRegion(context, index, region)); } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } void TextureD3D_2DArray::deleteImages() @@ -2988,18 +3414,26 @@ void TextureD3D_2DArray::deleteImages() delete mImageArray[level][layer]; } delete[] mImageArray[level]; - mImageArray[level] = NULL; + mImageArray[level] = nullptr; mLayerCounts[level] = 0; } } -void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +gl::Error TextureD3D_2DArray::redefineImage(const gl::Context *context, + GLint level, + GLenum internalformat, + const gl::Extents &size, + bool forceRelease) { // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = getLayerCount(0); - const GLenum storageFormat = getBaseLevelInternalFormat(); + const int storageWidth = std::max(1, getLevelZeroWidth() >> level); + const int storageHeight = std::max(1, getLevelZeroHeight() >> level); + const GLuint baseLevel = getBaseLevel(); + int storageDepth = 0; + if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + storageDepth = getLayerCount(baseLevel); + } // Only reallocate the layers if the size doesn't match if (size.depth != mLayerCounts[level]) @@ -3026,33 +3460,27 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const for (int layer = 0; layer < mLayerCounts[level]; layer++) { mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, - gl::Extents(size.width, size.height, 1), false); + gl::Extents(size.width, size.height, 1), + forceRelease); + mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty(); } } if (mTexStorage) { + const GLenum storageFormat = getBaseLevelInternalFormat(); const int storageLevels = mTexStorage->getLevelCount(); - if ((level >= storageLevels && storageLevels != 0) || - size.width != storageWidth || - size.height != storageHeight || - size.depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage + if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || + size.height != storageHeight || size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage { - for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) - { - for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) - { - mImageArray[dirtyLevel][dirtyLayer]->markDirty(); - } - } - - delete mTexStorage; - mTexStorage = NULL; - mDirtyImages = true; + markAllImagesDirty(); + ANGLE_TRY(releaseTexStorage(context)); } } + + return gl::NoError(); } gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const @@ -3083,4 +3511,464 @@ bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); } +void TextureD3D_2DArray::markAllImagesDirty() +{ + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) + { + mImageArray[dirtyLevel][dirtyLayer]->markDirty(); + } + } + mDirtyImages = true; +} + +TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer) + : TextureD3D(state, renderer) +{ +} + +TextureD3D_External::~TextureD3D_External() +{ +} + +ImageD3D *TextureD3D_External::getImage(const gl::ImageIndex &index) const +{ + UNREACHABLE(); + return nullptr; +} + +GLsizei TextureD3D_External::getLayerCount(int level) const +{ + return 1; +} + +gl::Error TextureD3D_External::setImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + // Image setting is not supported for external images + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setSubImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setCompressedImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::copyImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::copySubImage(const gl::Context *context, + GLenum target, + size_t imageLevel, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setStorage(const gl::Context *context, + GLenum target, + size_t levels, + GLenum internalFormat, + const gl::Extents &size) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setImageExternal(const gl::Context *context, + GLenum target, + egl::Stream *stream, + const egl::Stream::GLTextureDescription &desc) +{ + ASSERT(target == GL_TEXTURE_EXTERNAL_OES); + + ANGLE_TRY(releaseTexStorage(context)); + + // If the stream is null, the external image is unbound and we release the storage + if (stream != nullptr) + { + mTexStorage = mRenderer->createTextureStorageExternal(stream, desc); + } + + return gl::NoError(); +} + +gl::Error TextureD3D_External::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::releaseTexImage(const gl::Context *context) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) +{ + EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image); + + // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. + RenderTargetD3D *renderTargetD3D = nullptr; + ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); + + ANGLE_TRY(releaseTexStorage(context)); + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D); + + return gl::NoError(); +} + +gl::Error TextureD3D_External::initMipmapImages(const gl::Context *context) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_External::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const +{ + return (index.mipIndex == 0) ? (mTexStorage != nullptr) : false; +} + +gl::Error TextureD3D_External::initializeStorage(const gl::Context *context, bool renderTarget) +{ + // Texture storage is created when an external image is bound + ASSERT(mTexStorage); + return gl::NoError(); +} + +gl::Error TextureD3D_External::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_External::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_External::updateStorage(const gl::Context *context) +{ + // Texture storage does not need to be updated since it is already loaded with the latest + // external image + ASSERT(mTexStorage); + return gl::NoError(); +} + +gl::ImageIndexIterator TextureD3D_External::imageIterator() const +{ + return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // "layer" does not apply to 2D Textures. + return gl::ImageIndex::Make2D(mip); +} + +bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_EXTERNAL_OES && index.mipIndex == 0); +} + +void TextureD3D_External::markAllImagesDirty() +{ + UNREACHABLE(); +} + +TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state, + RendererD3D *renderer) + : TextureD3D(state, renderer) +{ +} + +TextureD3D_2DMultisample::~TextureD3D_2DMultisample() +{ +} + +ImageD3D *TextureD3D_2DMultisample::getImage(const gl::ImageIndex &index) const +{ + return nullptr; +} + +gl::Error TextureD3D_2DMultisample::setImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setCompressedImage(const gl::Context *context, + GLenum target, + size_t level, + GLenum internalFormat, + const gl::Extents &size, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setCompressedSubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Box &area, + GLenum format, + const gl::PixelUnpackState &unpack, + size_t imageSize, + const uint8_t *pixels) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::copyImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Rectangle &sourceArea, + GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::copySubImage(const gl::Context *context, + GLenum target, + size_t level, + const gl::Offset &destOffset, + const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context, + GLenum target, + GLsizei samples, + GLint internalFormat, + const gl::Extents &size, + bool fixedSampleLocations) +{ + ASSERT(target == GL_TEXTURE_2D_MULTISAMPLE && size.depth == 1); + + TexStoragePointer storage(context); + storage.reset(mRenderer->createTextureStorage2DMultisample(internalFormat, size.width, + size.height, static_cast<int>(0), + samples, fixedSampleLocations)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ANGLE_TRY(updateStorage(context)); + + mImmutable = false; + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::bindTexImage(const gl::Context *context, egl::Surface *surface) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::releaseTexImage(const gl::Context *context) +{ + UNREACHABLE(); + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context, + GLenum target, + egl::Image *image) +{ + UNREACHABLE(); + return gl::InternalError(); +} + +gl::Error TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context, + const gl::ImageIndex &index, + RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + // ensure the underlying texture is created + ANGLE_TRY(ensureRenderTarget(context)); + + return mTexStorage->getRenderTarget(context, index, outRT); +} + +gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const +{ + return gl::ImageIndexIterator::Make2DMultisample(); +} + +gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const +{ + return gl::ImageIndex::Make2DMultisample(); +} + +bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_2D_MULTISAMPLE && index.mipIndex == 0); +} + +GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const +{ + return 1; } + +void TextureD3D_2DMultisample::markAllImagesDirty() +{ +} + +gl::Error TextureD3D_2DMultisample::initializeStorage(const gl::Context *context, bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::NoError(); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage())); + + TexStoragePointer storage(context); + ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage)); + + ANGLE_TRY(setCompleteTexStorage(context, storage.get())); + storage.release(); + + ASSERT(mTexStorage); + + // flush image data to the storage + ANGLE_TRY(updateStorage(context)); + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::createCompleteStorage(bool renderTarget, + TexStoragePointer *outStorage) const +{ + outStorage->reset(mTexStorage); + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context, + TextureStorage *newCompleteTexStorage) +{ + ANGLE_TRY(releaseTexStorage(context)); + mTexStorage = newCompleteTexStorage; + + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::updateStorage(const gl::Context *context) +{ + return gl::NoError(); +} + +gl::Error TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context) +{ + UNIMPLEMENTED(); + return gl::NoError(); +} + +bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const +{ + return true; +} + +} // namespace rx |