// // Copyright 2012 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived // classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 // texture. #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" #include #include "common/MemoryBuffer.h" #include "common/utilities.h" #include "libANGLE/Context.h" #include "libANGLE/ImageIndex.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/EGLImageD3D.h" #include "libANGLE/renderer/d3d/TextureD3D.h" #include "libANGLE/renderer/d3d/d3d11/Blit11.h" #include "libANGLE/renderer/d3d/d3d11/Context11.h" #include "libANGLE/renderer/d3d/d3d11/Image11.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/StreamProducerD3DTexture.h" #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" namespace rx { TextureStorage11::SamplerKey::SamplerKey() : baseLevel(0), mipLevels(0), swizzle(false), dropStencil(false) {} TextureStorage11::SamplerKey::SamplerKey(int baseLevel, int mipLevels, bool swizzle, bool dropStencil) : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle), dropStencil(dropStencil) {} bool TextureStorage11::SamplerKey::operator<(const SamplerKey &rhs) const { return std::tie(baseLevel, mipLevels, swizzle, dropStencil) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle, rhs.dropStencil); } TextureStorage11::ImageKey::ImageKey() : level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI) {} TextureStorage11::ImageKey::ImageKey(int level, bool layered, int layer, GLenum access, GLenum format) : level(level), layered(layered), layer(layer), access(access), format(format) {} bool TextureStorage11::ImageKey::operator<(const ImageKey &rhs) const { return std::tie(level, layered, layer, access, format) < std::tie(rhs.level, rhs.layered, rhs.layer, rhs.access, rhs.format); } MultisampledRenderToTextureInfo::MultisampledRenderToTextureInfo(const GLsizei samples, const gl::ImageIndex &indexSS, const gl::ImageIndex &indexMS) : samples(samples), indexSS(indexSS), indexMS(indexMS), msTextureNeedsResolve(false) {} MultisampledRenderToTextureInfo::~MultisampledRenderToTextureInfo() {} TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags, UINT miscFlags, GLenum internalFormat) : mRenderer(renderer), mTopLevel(0), mMipLevels(0), mFormatInfo(d3d11::Format::Get(internalFormat, mRenderer->getRenderer11DeviceCaps())), mTextureWidth(0), mTextureHeight(0), mTextureDepth(0), mDropStencilTexture(), mBindFlags(bindFlags), mMiscFlags(miscFlags) {} TextureStorage11::~TextureStorage11() { mSrvCacheForSampler.clear(); } DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget) { UINT bindFlags = 0; const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) { bindFlags |= D3D11_BIND_SHADER_RESOURCE; } if (formatInfo.uavFormat != DXGI_FORMAT_UNKNOWN && renderer11DeviceCaps.featureLevel >= d3d11_gl::GetMinimumFeatureLevelForES31()) { // If we find performance issues later on some specific GPUs, this may be the cause. bindFlags |= D3D11_BIND_UNORDERED_ACCESS; } if (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { bindFlags |= D3D11_BIND_DEPTH_STENCIL; } if (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN && renderTarget) { bindFlags |= D3D11_BIND_RENDER_TARGET; } return bindFlags; } DWORD TextureStorage11::GetTextureMiscFlags(GLenum internalFormat, const Renderer11DeviceCaps &renderer11DeviceCaps, bool renderTarget, int levels) { UINT miscFlags = 0; const d3d11::Format &formatInfo = d3d11::Format::Get(internalFormat, renderer11DeviceCaps); if (renderTarget && levels > 1) { if (d3d11::SupportsMipGen(formatInfo.texFormat, renderer11DeviceCaps.featureLevel)) { miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; } } return miscFlags; } UINT TextureStorage11::getBindFlags() const { return mBindFlags; } UINT TextureStorage11::getMiscFlags() const { return mMiscFlags; } int TextureStorage11::getTopLevel() const { // Applying top level is meant to be encapsulated inside TextureStorage11. UNREACHABLE(); return mTopLevel; } bool TextureStorage11::isRenderTarget() const { return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; } bool TextureStorage11::isManaged() const { return false; } bool TextureStorage11::supportsNativeMipmapFunction() const { return (mMiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) != 0; } int TextureStorage11::getLevelCount() const { return mMipLevels - mTopLevel; } int TextureStorage11::getLevelWidth(int mipLevel) const { return std::max(static_cast(mTextureWidth) >> mipLevel, 1); } int TextureStorage11::getLevelHeight(int mipLevel) const { return std::max(static_cast(mTextureHeight) >> mipLevel, 1); } int TextureStorage11::getLevelDepth(int mipLevel) const { return std::max(static_cast(mTextureDepth) >> mipLevel, 1); } angle::Result TextureStorage11::getMippedResource(const gl::Context *context, const TextureHelper11 **outResource) { return getResource(context, outResource); } angle::Result TextureStorage11::getSubresourceIndex(const gl::Context *context, const gl::ImageIndex &index, UINT *outSubresourceIndex) const { UINT mipSlice = static_cast(index.getLevelIndex() + mTopLevel); UINT arraySlice = static_cast(index.hasLayer() ? index.getLayerIndex() : 0); UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); ASSERT(subresource != std::numeric_limits::max()); *outSubresourceIndex = subresource; return angle::Result::Continue; } angle::Result TextureStorage11::getSRVForSampler(const gl::Context *context, const gl::TextureState &textureState, const gl::SamplerState &sampler, const d3d11::SharedSRV **outSRV) { ANGLE_TRY(resolveTexture(context)); // Make sure to add the level offset for our tiny compressed texture workaround const GLuint effectiveBaseLevel = textureState.getEffectiveBaseLevel(); const bool swizzleRequired = textureState.swizzleRequired(); const bool mipmapping = gl::IsMipmapFiltered(sampler.getMinFilter()); unsigned int mipLevels = mipmapping ? (textureState.getEffectiveMaxLevel() - effectiveBaseLevel + 1) : 1; // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, // which corresponds to GL level 0) mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - effectiveBaseLevel); if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { ASSERT(!swizzleRequired); ASSERT(mipLevels == 1 || mipLevels == mMipLevels); } if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { // We must ensure that the level zero texture is in sync with mipped texture. ANGLE_TRY(useLevelZeroWorkaroundTexture(context, mipLevels == 1)); } if (swizzleRequired) { verifySwizzleExists(textureState.getSwizzleState()); } // We drop the stencil when sampling from the SRV if three conditions hold: // 1. the drop stencil workaround is enabled. const bool emulateTinyStencilTextures = mRenderer->getFeatures().emulateTinyStencilTextures.enabled; // 2. this is a stencil texture. const bool hasStencil = (mFormatInfo.format().stencilBits > 0); // 3. the texture has a 1x1 or 2x2 mip. const int effectiveTopLevel = effectiveBaseLevel + mipLevels - 1; const bool hasSmallMips = (getLevelWidth(effectiveTopLevel) <= 2 || getLevelHeight(effectiveTopLevel) <= 2); const bool useDropStencil = (emulateTinyStencilTextures && hasStencil && hasSmallMips); const SamplerKey key(effectiveBaseLevel, mipLevels, swizzleRequired, useDropStencil); if (useDropStencil) { // Ensure drop texture gets created. DropStencil result = DropStencil::CREATED; ANGLE_TRY(ensureDropStencilTexture(context, &result)); // Clear the SRV cache if necessary. // TODO(jmadill): Re-use find query result. const auto srvEntry = mSrvCacheForSampler.find(key); if (result == DropStencil::CREATED && srvEntry != mSrvCacheForSampler.end()) { mSrvCacheForSampler.erase(key); } } ANGLE_TRY(getCachedOrCreateSRVForSampler(context, key, outSRV)); return angle::Result::Continue; } angle::Result TextureStorage11::getCachedOrCreateSRVForSampler(const gl::Context *context, const SamplerKey &key, const d3d11::SharedSRV **outSRV) { auto iter = mSrvCacheForSampler.find(key); if (iter != mSrvCacheForSampler.end()) { *outSRV = &iter->second; return angle::Result::Continue; } const TextureHelper11 *texture = nullptr; DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; if (key.swizzle) { const auto &swizzleFormat = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); ASSERT(!key.dropStencil || swizzleFormat.format().stencilBits == 0); ANGLE_TRY(getSwizzleTexture(context, &texture)); format = swizzleFormat.srvFormat; } else if (key.dropStencil) { ASSERT(mDropStencilTexture.valid()); texture = &mDropStencilTexture; format = DXGI_FORMAT_R32_FLOAT; } else { ANGLE_TRY(getResource(context, &texture)); format = mFormatInfo.srvFormat; } d3d11::SharedSRV srv; ANGLE_TRY(createSRVForSampler(context, key.baseLevel, key.mipLevels, format, *texture, &srv)); const auto &insertIt = mSrvCacheForSampler.insert(std::make_pair(key, std::move(srv))); *outSRV = &insertIt.first->second; return angle::Result::Continue; } angle::Result TextureStorage11::getSRVLevel(const gl::Context *context, int mipLevel, bool blitSRV, const d3d11::SharedSRV **outSRV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ANGLE_TRY(resolveTexture(context)); auto &levelSRVs = (blitSRV) ? mLevelBlitSRVs : mLevelSRVs; auto &otherLevelSRVs = (blitSRV) ? mLevelSRVs : mLevelBlitSRVs; if (!levelSRVs[mipLevel].valid()) { // Only create a different SRV for blit if blit format is different from regular srv format if (otherLevelSRVs[mipLevel].valid() && mFormatInfo.srvFormat == mFormatInfo.blitSRVFormat) { levelSRVs[mipLevel] = otherLevelSRVs[mipLevel].makeCopy(); } else { const TextureHelper11 *resource = nullptr; ANGLE_TRY(getResource(context, &resource)); DXGI_FORMAT resourceFormat = blitSRV ? mFormatInfo.blitSRVFormat : mFormatInfo.srvFormat; ANGLE_TRY(createSRVForSampler(context, mipLevel, 1, resourceFormat, *resource, &levelSRVs[mipLevel])); } } *outSRV = &levelSRVs[mipLevel]; return angle::Result::Continue; } angle::Result TextureStorage11::getSRVLevels(const gl::Context *context, GLint baseLevel, GLint maxLevel, const d3d11::SharedSRV **outSRV) { ANGLE_TRY(resolveTexture(context)); unsigned int mipLevels = maxLevel - baseLevel + 1; // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, // which corresponds to GL level 0) mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - baseLevel); if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { ASSERT(mipLevels == 1 || mipLevels == mMipLevels); } if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { // We must ensure that the level zero texture is in sync with mipped texture. ANGLE_TRY(useLevelZeroWorkaroundTexture(context, mipLevels == 1)); } // TODO(jmadill): Assert we don't need to drop stencil. SamplerKey key(baseLevel, mipLevels, false, false); ANGLE_TRY(getCachedOrCreateSRVForSampler(context, key, outSRV)); return angle::Result::Continue; } angle::Result TextureStorage11::getSRVForImage(const gl::Context *context, const gl::ImageUnit &imageUnit, const d3d11::SharedSRV **outSRV) { ANGLE_TRY(resolveTexture(context)); // TODO(Xinghua.cao@intel.com): Add solution to handle swizzle required. ImageKey key(imageUnit.level, (imageUnit.layered == GL_TRUE), imageUnit.layer, imageUnit.access, imageUnit.format); ANGLE_TRY(getCachedOrCreateSRVForImage(context, key, outSRV)); return angle::Result::Continue; } angle::Result TextureStorage11::getCachedOrCreateSRVForImage(const gl::Context *context, const ImageKey &key, const d3d11::SharedSRV **outSRV) { auto iter = mSrvCacheForImage.find(key); if (iter != mSrvCacheForImage.end()) { *outSRV = &iter->second; return angle::Result::Continue; } const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); DXGI_FORMAT format = d3d11::Format::Get(key.format, mRenderer->getRenderer11DeviceCaps()).srvFormat; d3d11::SharedSRV srv; ANGLE_TRY(createSRVForImage(context, key.level, format, *texture, &srv)); const auto &insertIt = mSrvCacheForImage.insert(std::make_pair(key, std::move(srv))); *outSRV = &insertIt.first->second; return angle::Result::Continue; } angle::Result TextureStorage11::getUAVForImage(const gl::Context *context, const gl::ImageUnit &imageUnit, const d3d11::SharedUAV **outUAV) { ANGLE_TRY(resolveTexture(context)); // TODO(Xinghua.cao@intel.com): Add solution to handle swizzle required. ImageKey key(imageUnit.level, (imageUnit.layered == GL_TRUE), imageUnit.layer, imageUnit.access, imageUnit.format); ANGLE_TRY(getCachedOrCreateUAVForImage(context, key, outUAV)); return angle::Result::Continue; } angle::Result TextureStorage11::getCachedOrCreateUAVForImage(const gl::Context *context, const ImageKey &key, const d3d11::SharedUAV **outUAV) { auto iter = mUavCacheForImage.find(key); if (iter != mUavCacheForImage.end()) { *outUAV = &iter->second; return angle::Result::Continue; } const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); DXGI_FORMAT format = d3d11::Format::Get(key.format, mRenderer->getRenderer11DeviceCaps()).uavFormat; d3d11::SharedUAV uav; ANGLE_TRY(createUAVForImage(context, key.level, format, *texture, &uav)); const auto &insertIt = mUavCacheForImage.insert(std::make_pair(key, std::move(uav))); *outUAV = &insertIt.first->second; return angle::Result::Continue; } const d3d11::Format &TextureStorage11::getFormatSet() const { return mFormatInfo; } angle::Result TextureStorage11::generateSwizzles(const gl::Context *context, const gl::SwizzleState &swizzleTarget) { ANGLE_TRY(resolveTexture(context)); for (int level = 0; level < getLevelCount(); level++) { // Check if the swizzle for this level is out of date if (mSwizzleCache[level] != swizzleTarget) { // Need to re-render the swizzle for this level const d3d11::SharedSRV *sourceSRV = nullptr; ANGLE_TRY(getSRVLevel(context, level, true, &sourceSRV)); const d3d11::RenderTargetView *destRTV; ANGLE_TRY(getSwizzleRenderTarget(context, level, &destRTV)); gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); Blit11 *blitter = mRenderer->getBlitter(); ANGLE_TRY(blitter->swizzleTexture(context, *sourceSRV, *destRTV, size, swizzleTarget)); mSwizzleCache[level] = swizzleTarget; } } return angle::Result::Continue; } void TextureStorage11::markLevelDirty(int mipLevel) { if (mipLevel >= 0 && static_cast(mipLevel) < mSwizzleCache.size()) { // The default constructor of SwizzleState has GL_INVALID_INDEX for all channels which is // not a valid swizzle combination if (mSwizzleCache[mipLevel] != gl::SwizzleState()) { // TODO(jmadill): Invalidate specific swizzle. mRenderer->getStateManager()->invalidateSwizzles(); mSwizzleCache[mipLevel] = gl::SwizzleState(); } } if (mDropStencilTexture.valid()) { mDropStencilTexture.reset(); } } void TextureStorage11::markDirty() { for (size_t mipLevel = 0; mipLevel < mSwizzleCache.size(); ++mipLevel) { markLevelDirty(static_cast(mipLevel)); } } angle::Result TextureStorage11::updateSubresourceLevel(const gl::Context *context, const TextureHelper11 &srcTexture, unsigned int sourceSubresource, const gl::ImageIndex &index, const gl::Box ©Area) { ASSERT(srcTexture.valid()); ANGLE_TRY(resolveTexture(context)); const GLint level = index.getLevelIndex(); markLevelDirty(level); gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); bool fullCopy = copyArea.coversSameExtent(texSize); const TextureHelper11 *dstTexture = nullptr; // If the zero-LOD workaround is active and we want to update a level greater than zero, then we // should update the mipmapped texture, even if mapmaps are currently disabled. if (level > 0 && mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ANGLE_TRY(getMippedResource(context, &dstTexture)); } else { ANGLE_TRY(getResource(context, &dstTexture)); } unsigned int dstSubresource = 0; ANGLE_TRY(getSubresourceIndex(context, index, &dstSubresource)); ASSERT(dstTexture->valid()); const d3d11::DXGIFormatSize &dxgiFormatSizeInfo = d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat); if (!fullCopy && mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead Blit11 *blitter = mRenderer->getBlitter(); return blitter->copyDepthStencil(context, srcTexture, sourceSubresource, copyArea, texSize, *dstTexture, dstSubresource, copyArea, texSize, nullptr); } D3D11_BOX srcBox; srcBox.left = copyArea.x; srcBox.top = copyArea.y; srcBox.right = copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatSizeInfo.blockWidth); srcBox.bottom = copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatSizeInfo.blockHeight); srcBox.front = copyArea.z; srcBox.back = copyArea.z + copyArea.depth; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); deviceContext->CopySubresourceRegion(dstTexture->get(), dstSubresource, copyArea.x, copyArea.y, copyArea.z, srcTexture.get(), sourceSubresource, fullCopy ? nullptr : &srcBox); return angle::Result::Continue; } angle::Result TextureStorage11::copySubresourceLevel(const gl::Context *context, const TextureHelper11 &dstTexture, unsigned int dstSubresource, const gl::ImageIndex &index, const gl::Box ®ion) { ASSERT(dstTexture.valid()); ANGLE_TRY(resolveTexture(context)); const TextureHelper11 *srcTexture = nullptr; // If the zero-LOD workaround is active and we want to update a level greater than zero, then we // should update the mipmapped texture, even if mapmaps are currently disabled. if (index.getLevelIndex() > 0 && mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ANGLE_TRY(getMippedResource(context, &srcTexture)); } else { ANGLE_TRY(getResource(context, &srcTexture)); } ASSERT(srcTexture->valid()); unsigned int srcSubresource = 0; ANGLE_TRY(getSubresourceIndex(context, index, &srcSubresource)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox // should be nullptr. D3D11_BOX srcBox; D3D11_BOX *pSrcBox = nullptr; if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3) { GLsizei width = region.width; GLsizei height = region.height; d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, nullptr); // Keep srcbox as nullptr if we're dealing with tiny mips of compressed textures. if (width == region.width && height == region.height) { // However, D3D10Level9 doesn't always perform CopySubresourceRegion correctly unless // the source box is specified. This is okay, since we don't perform // CopySubresourceRegion on depth/stencil textures on 9_3. ASSERT(mFormatInfo.dsvFormat == DXGI_FORMAT_UNKNOWN); srcBox.left = region.x; srcBox.right = region.x + region.width; srcBox.top = region.y; srcBox.bottom = region.y + region.height; srcBox.front = region.z; srcBox.back = region.z + region.depth; pSrcBox = &srcBox; } } deviceContext->CopySubresourceRegion(dstTexture.get(), dstSubresource, region.x, region.y, region.z, srcTexture->get(), srcSubresource, pSrcBox); return angle::Result::Continue; } angle::Result TextureStorage11::generateMipmap(const gl::Context *context, const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) { ASSERT(sourceIndex.getLayerIndex() == destIndex.getLayerIndex()); ANGLE_TRY(resolveTexture(context)); markLevelDirty(destIndex.getLevelIndex()); RenderTargetD3D *source = nullptr; ANGLE_TRY(getRenderTarget(context, sourceIndex, 0, &source)); // dest will always have 0 since, we have just released the MS Texture struct RenderTargetD3D *dest = nullptr; ANGLE_TRY(getRenderTarget(context, destIndex, 0, &dest)); RenderTarget11 *srcRT11 = GetAs(source); RenderTarget11 *dstRT11 = GetAs(dest); const d3d11::SharedSRV &sourceSRV = srcRT11->getBlitShaderResourceView(context); const d3d11::RenderTargetView &destRTV = dstRT11->getRenderTargetView(); gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); Blit11 *blitter = mRenderer->getBlitter(); const gl::InternalFormat &sourceInternalFormat = gl::GetSizedInternalFormatInfo(source->getInternalFormat()); GLenum format = sourceInternalFormat.format; GLenum type = sourceInternalFormat.type; return blitter->copyTexture(context, sourceSRV, sourceArea, sourceSize, format, destRTV, destArea, destSize, nullptr, format, type, GL_LINEAR, false, false, false); } void TextureStorage11::verifySwizzleExists(const gl::SwizzleState &swizzleState) { for (unsigned int level = 0; level < mMipLevels; level++) { ASSERT(mSwizzleCache[level] == swizzleState); } } void TextureStorage11::clearSRVCache() { markDirty(); mSrvCacheForSampler.clear(); for (size_t level = 0; level < mLevelSRVs.size(); level++) { mLevelSRVs[level].reset(); mLevelBlitSRVs[level].reset(); } } angle::Result TextureStorage11::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); ANGLE_TRY(resolveTexture(context)); const TextureHelper11 *sourceResouce = nullptr; ANGLE_TRY(getResource(context, &sourceResouce)); TextureStorage11 *dest11 = GetAs(destStorage); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); immediateContext->CopyResource(destResource->get(), sourceResouce->get()); dest11->markDirty(); return angle::Result::Continue; } void TextureStorage11::invalidateTextures() { mRenderer->getStateManager()->invalidateTexturesAndSamplers(); } angle::Result TextureStorage11::setData(const gl::Context *context, const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixelData) { ASSERT(!image->isDirty()); ANGLE_TRY(resolveTexture(context)); markLevelDirty(index.getLevelIndex()); const TextureHelper11 *resource = nullptr; ANGLE_TRY(getResource(context, &resource)); ASSERT(resource && resource->valid()); UINT destSubresource = 0; ANGLE_TRY(getSubresourceIndex(context, index, &destSubresource)); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat(), type); gl::Box levelBox(0, 0, 0, getLevelWidth(index.getLevelIndex()), getLevelHeight(index.getLevelIndex()), getLevelDepth(index.getLevelIndex())); bool fullUpdate = (destBox == nullptr || *destBox == levelBox); ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); // TODO(jmadill): Handle compressed formats // Compressed formats have different load syntax, so we'll have to handle them with slightly // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData // with compressed formats in the calling logic. ASSERT(!internalFormatInfo.compressed); Context11 *context11 = GetImplAs(context); const int width = destBox ? destBox->width : static_cast(image->getWidth()); const int height = destBox ? destBox->height : static_cast(image->getHeight()); const int depth = destBox ? destBox->depth : static_cast(image->getDepth()); GLuint srcRowPitch = 0; ANGLE_CHECK_GL_MATH(context11, internalFormatInfo.computeRowPitch(type, width, unpack.alignment, unpack.rowLength, &srcRowPitch)); GLuint srcDepthPitch = 0; ANGLE_CHECK_GL_MATH(context11, internalFormatInfo.computeDepthPitch( height, unpack.imageHeight, srcRowPitch, &srcDepthPitch)); GLuint srcSkipBytes = 0; ANGLE_CHECK_GL_MATH( context11, internalFormatInfo.computeSkipBytes(type, srcRowPitch, srcDepthPitch, unpack, index.usesTex3D(), &srcSkipBytes)); const d3d11::Format &d3d11Format = d3d11::Format::Get(image->getInternalFormat(), mRenderer->getRenderer11DeviceCaps()); const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(d3d11Format.texFormat); const size_t outputPixelSize = dxgiFormatInfo.pixelBytes; UINT bufferRowPitch = static_cast(outputPixelSize) * width; UINT bufferDepthPitch = bufferRowPitch * height; const size_t neededSize = bufferDepthPitch * depth; angle::MemoryBuffer *conversionBuffer = nullptr; const uint8_t *data = nullptr; LoadImageFunctionInfo loadFunctionInfo = d3d11Format.getLoadFunctions()(type); if (loadFunctionInfo.requiresConversion) { ANGLE_TRY(mRenderer->getScratchMemoryBuffer(context11, neededSize, &conversionBuffer)); loadFunctionInfo.loadFunction(width, height, depth, pixelData + srcSkipBytes, srcRowPitch, srcDepthPitch, conversionBuffer->data(), bufferRowPitch, bufferDepthPitch); data = conversionBuffer->data(); } else { data = pixelData + srcSkipBytes; bufferRowPitch = srcRowPitch; bufferDepthPitch = srcDepthPitch; } ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); if (!fullUpdate) { ASSERT(destBox); D3D11_BOX destD3DBox; destD3DBox.left = destBox->x; destD3DBox.right = destBox->x + destBox->width; destD3DBox.top = destBox->y; destD3DBox.bottom = destBox->y + destBox->height; destD3DBox.front = destBox->z; destD3DBox.back = destBox->z + destBox->depth; immediateContext->UpdateSubresource(resource->get(), destSubresource, &destD3DBox, data, bufferRowPitch, bufferDepthPitch); } else { immediateContext->UpdateSubresource(resource->get(), destSubresource, nullptr, data, bufferRowPitch, bufferDepthPitch); } return angle::Result::Continue; } angle::Result TextureStorage11::ensureDropStencilTexture( const gl::Context *context, TextureStorage11::DropStencil *dropStencilOut) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11::initDropStencilTexture(const gl::Context *context, const gl::ImageIndexIterator &it) { const TextureHelper11 *sourceTexture = nullptr; ANGLE_TRY(getResource(context, &sourceTexture)); gl::ImageIndexIterator itCopy = it; while (itCopy.hasNext()) { gl::ImageIndex index = itCopy.next(); gl::Box wholeArea(0, 0, 0, getLevelWidth(index.getLevelIndex()), getLevelHeight(index.getLevelIndex()), 1); gl::Extents wholeSize(wholeArea.width, wholeArea.height, 1); UINT subresource = 0; ANGLE_TRY(getSubresourceIndex(context, index, &subresource)); ANGLE_TRY(mRenderer->getBlitter()->copyDepthStencil( context, *sourceTexture, subresource, wholeArea, wholeSize, mDropStencilTexture, subresource, wholeArea, wholeSize, nullptr)); } return angle::Result::Continue; } angle::Result TextureStorage11::resolveTextureHelper(const gl::Context *context, const TextureHelper11 &texture) { UINT subresourceIndexSS; ANGLE_TRY(getSubresourceIndex(context, mMSTexInfo->indexSS, &subresourceIndexSS)); UINT subresourceIndexMS; ANGLE_TRY(getSubresourceIndex(context, mMSTexInfo->indexMS, &subresourceIndexMS)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); const TextureHelper11 *resource = nullptr; ANGLE_TRY(mMSTexInfo->msTex->getResource(context, &resource)); deviceContext->ResolveSubresource(texture.get(), subresourceIndexSS, resource->get(), subresourceIndexMS, texture.getFormat()); mMSTexInfo->msTextureNeedsResolve = false; return angle::Result::Continue; } angle::Result TextureStorage11::releaseMultisampledTexStorageForLevel(size_t level) { if (mMSTexInfo && mMSTexInfo->indexSS.getLevelIndex() == static_cast(level)) { mMSTexInfo->msTex.reset(); onStateChange(angle::SubjectMessage::ContentsChanged); } return angle::Result::Continue; } GLsizei TextureStorage11::getRenderToTextureSamples() const { if (mMSTexInfo) { return mMSTexInfo->samples; } return 0; } angle::Result TextureStorage11::findMultisampledRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { const int level = index.getLevelIndex(); if (!mMSTexInfo || level != mMSTexInfo->indexSS.getLevelIndex() || samples != mMSTexInfo->samples || !mMSTexInfo->msTex) { *outRT = nullptr; return angle::Result::Continue; } RenderTargetD3D *rt; ANGLE_TRY(mMSTexInfo->msTex->findRenderTarget(context, mMSTexInfo->indexMS, samples, &rt)); *outRT = rt; return angle::Result::Continue; } angle::Result TextureStorage11::getMultisampledRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { const int level = index.getLevelIndex(); if (!mMSTexInfo || level != mMSTexInfo->indexSS.getLevelIndex() || samples != mMSTexInfo->samples || !mMSTexInfo->msTex) { // if mMSTexInfo already exists, then we want to resolve and release it // since the mMSTexInfo must be for a different sample count or level ANGLE_TRY(resolveTexture(context)); // Now we can create a new object for the correct sample and level GLsizei width = getLevelWidth(level); GLsizei height = getLevelHeight(level); GLenum internalFormat = mFormatInfo.internalFormat; std::unique_ptr texMS( GetAs(mRenderer->createTextureStorage2DMultisample( internalFormat, width, height, level, samples, true))); // make sure multisample object has the blitted information. gl::Rectangle area(0, 0, width, height); RenderTargetD3D *readRenderTarget = nullptr; // use incoming index here since the index will correspond to the single sampled texture ANGLE_TRY(getRenderTarget(context, index, 0, &readRenderTarget)); gl::ImageIndex indexMS = gl::ImageIndex::Make2DMultisample(); RenderTargetD3D *drawRenderTarget = nullptr; ANGLE_TRY(texMS->getRenderTarget(context, indexMS, samples, &drawRenderTarget)); // blit SS -> MS // mask: GL_COLOR_BUFFER_BIT, filter: GL_NEAREST ANGLE_TRY(mRenderer->blitRenderbufferRect(context, area, area, readRenderTarget, drawRenderTarget, GL_NEAREST, nullptr, true, false, false)); mMSTexInfo = std::make_unique(samples, index, indexMS); mMSTexInfo->msTex = std::move(texMS); } RenderTargetD3D *rt; ANGLE_TRY(mMSTexInfo->msTex->getRenderTarget(context, mMSTexInfo->indexMS, samples, &rt)); // By returning the multisampled render target to the caller, the render target // is expected to be changed so we need to resolve to a single sampled texture // next time resolveTexture is called. mMSTexInfo->msTextureNeedsResolve = true; *outRT = rt; return angle::Result::Continue; } TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0, swapchain->getRenderTargetInternalFormat()), mTexture(swapchain->getOffscreenTexture()), mLevelZeroTexture(), mLevelZeroRenderTarget(nullptr), mUseLevelZeroTexture(false), mSwizzleTexture() { for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { mAssociatedImages[i] = nullptr; mRenderTarget[i] = nullptr; } D3D11_TEXTURE2D_DESC texDesc; mTexture.getDesc(&texDesc); mMipLevels = texDesc.MipLevels; mTextureWidth = texDesc.Width; mTextureHeight = texDesc.Height; mTextureDepth = 1; mHasKeyedMutex = (texDesc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) != 0; } TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) : TextureStorage11( renderer, GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels), internalformat), mTexture(), mHasKeyedMutex(false), mLevelZeroTexture(), mLevelZeroRenderTarget(nullptr), mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), mSwizzleTexture() { for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { mAssociatedImages[i] = nullptr; mRenderTarget[i] = nullptr; } d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); mMipLevels = mTopLevel + levels; mTextureWidth = width; mTextureHeight = height; mTextureDepth = 1; // The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. ASSERT(!mUseLevelZeroTexture || mRenderer->getFeatures().zeroMaxLodWorkaround.enabled); } angle::Result TextureStorage11_2D::onDestroy(const gl::Context *context) { for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { if (mAssociatedImages[i] != nullptr) { mAssociatedImages[i]->verifyAssociatedStorageValid(this); // We must let the Images recover their data before we delete it from the // TextureStorage. ANGLE_TRY(mAssociatedImages[i]->recoverFromAssociatedStorage(context)); } } if (mHasKeyedMutex) { // If the keyed mutex is released that will unbind it and cause the state cache to become // desynchronized. mRenderer->getStateManager()->invalidateBoundViews(); } return angle::Result::Continue; } TextureStorage11_2D::~TextureStorage11_2D() {} angle::Result TextureStorage11_2D::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); TextureStorage11_2D *dest11 = GetAs(destStorage); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the // corresponding textures in destStorage. if (mTexture.valid()) { ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, false)); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); immediateContext->CopyResource(destResource->get(), mTexture.get()); } if (mLevelZeroTexture.valid()) { ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, true)); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); immediateContext->CopyResource(destResource->get(), mLevelZeroTexture.get()); } return angle::Result::Continue; } const TextureHelper11 *sourceResouce = nullptr; ANGLE_TRY(getResource(context, &sourceResouce)); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); immediateContext->CopyResource(destResource->get(), sourceResouce->get()); dest11->markDirty(); return angle::Result::Continue; } angle::Result TextureStorage11_2D::useLevelZeroWorkaroundTexture(const gl::Context *context, bool useLevelZeroTexture) { if (useLevelZeroTexture && mMipLevels > 1) { if (!mUseLevelZeroTexture && mTexture.valid()) { ANGLE_TRY(ensureTextureExists(context, 1)); // Pull data back from the mipped texture if necessary. ASSERT(mLevelZeroTexture.valid()); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); deviceContext->CopySubresourceRegion(mLevelZeroTexture.get(), 0, 0, 0, 0, mTexture.get(), 0, nullptr); } mUseLevelZeroTexture = true; } else { if (mUseLevelZeroTexture && mLevelZeroTexture.valid()) { ANGLE_TRY(ensureTextureExists(context, mMipLevels)); // Pull data back from the level zero texture if necessary. ASSERT(mTexture.valid()); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); deviceContext->CopySubresourceRegion(mTexture.get(), 0, 0, 0, 0, mLevelZeroTexture.get(), 0, nullptr); } mUseLevelZeroTexture = false; } return angle::Result::Continue; } void TextureStorage11_2D::associateImage(Image11 *image, const gl::ImageIndex &index) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { mAssociatedImages[level] = image; } } void TextureStorage11_2D::verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); // This validation check should never return false. It means the Image/TextureStorage // association is broken. ASSERT(mAssociatedImages[level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(mAssociatedImages[level] == expectedImage); mAssociatedImages[level] = nullptr; } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image // recover its data before ending the association. angle::Result TextureStorage11_2D::releaseAssociatedImage(const gl::Context *context, const gl::ImageIndex &index, Image11 *incomingImage) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // No need to let the old Image recover its data, if it is also the incoming Image. if (mAssociatedImages[level] != nullptr && mAssociatedImages[level] != incomingImage) { // Ensure that the Image is still associated with this TextureStorage. mAssociatedImages[level]->verifyAssociatedStorageValid(this); // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to nullptr too. ANGLE_TRY(mAssociatedImages[level]->recoverFromAssociatedStorage(context)); } } return angle::Result::Continue; } angle::Result TextureStorage11_2D::getResource(const gl::Context *context, const TextureHelper11 **outResource) { if (mUseLevelZeroTexture && mMipLevels > 1) { ANGLE_TRY(ensureTextureExists(context, 1)); *outResource = &mLevelZeroTexture; return angle::Result::Continue; } ANGLE_TRY(ensureTextureExists(context, mMipLevels)); *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2D::getMippedResource(const gl::Context *context, const TextureHelper11 **outResource) { // This shouldn't be called unless the zero max LOD workaround is active. ASSERT(mRenderer->getFeatures().zeroMaxLodWorkaround.enabled); ANGLE_TRY(ensureTextureExists(context, mMipLevels)); *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2D::ensureTextureExists(const gl::Context *context, int mipLevels) { // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. ANGLE_TRY(resolveTexture(context)); bool useLevelZeroTexture = mRenderer->getFeatures().zeroMaxLodWorkaround.enabled ? (mipLevels == 1) && (mMipLevels > 1) : false; TextureHelper11 *outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation if (!outputTexture->valid() && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mipLevels > 0); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; // Compressed texture size constraints? desc.Height = mTextureHeight; desc.MipLevels = mipLevels; desc.ArraySize = 1; desc.Format = mFormatInfo.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = getBindFlags(); desc.CPUAccessFlags = 0; desc.MiscFlags = getMiscFlags(); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, mFormatInfo, outputTexture)); if (useLevelZeroTexture) { outputTexture->setDebugName("TexStorage2D.Level0Texture"); } else { outputTexture->setDebugName("TexStorage2D.Texture"); } } return angle::Result::Continue; } angle::Result TextureStorage11_2D::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { ASSERT(!index.hasLayer()); const int level = index.getLevelIndex(); ASSERT(level >= 0 && level < getLevelCount()); bool needMS = samples > 0; if (needMS) { return findMultisampledRenderTarget(context, index, samples, outRT); } ASSERT(outRT); if (mRenderTarget[level]) { *outRT = mRenderTarget[level].get(); return angle::Result::Continue; } if (mUseLevelZeroTexture) { ASSERT(level == 0); *outRT = mLevelZeroRenderTarget.get(); return angle::Result::Continue; } *outRT = nullptr; return angle::Result::Continue; } angle::Result TextureStorage11_2D::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); const int level = index.getLevelIndex(); ASSERT(level >= 0 && level < getLevelCount()); bool needMS = samples > 0; if (needMS) { return getMultisampledRenderTarget(context, index, samples, outRT); } else { ANGLE_TRY(resolveTexture(context)); } // In GL ES 2.0, the application can only render to level zero of the texture (Section 4.4.3 of // the GLES 2.0 spec, page 113 of version 2.0.25). Other parts of TextureStorage11_2D could // create RTVs on non-zero levels of the texture (e.g. generateMipmap). // On Feature Level 9_3, this is unlikely to be useful. The renderer can't create SRVs on the // individual levels of the texture, so methods like generateMipmap can't do anything useful // with non-zero-level RTVs. Therefore if level > 0 on 9_3 then there's almost certainly // something wrong. ASSERT( !(mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3 && level > 0)); ASSERT(outRT); if (mRenderTarget[level]) { *outRT = mRenderTarget[level].get(); return angle::Result::Continue; } if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ASSERT(level == 0); ANGLE_TRY(useLevelZeroWorkaroundTexture(context, true)); } const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); const d3d11::SharedSRV *srv = nullptr; ANGLE_TRY(getSRVLevel(context, level, false, &srv)); const d3d11::SharedSRV *blitSRV = nullptr; ANGLE_TRY(getSRVLevel(context, level, true, &blitSRV)); Context11 *context11 = GetImplAs(context); if (mUseLevelZeroTexture) { if (!mLevelZeroRenderTarget) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = mTopLevel + level; d3d11::RenderTargetView rtv; ANGLE_TRY( mRenderer->allocateResource(context11, rtvDesc, mLevelZeroTexture.get(), &rtv)); rtv.setDebugName("TexStorage2D.Level0RTV"); mLevelZeroRenderTarget.reset(new TextureRenderTarget11( std::move(rtv), mLevelZeroTexture, d3d11::SharedSRV(), d3d11::SharedSRV(), mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, 0)); } *outRT = mLevelZeroRenderTarget.get(); return angle::Result::Continue; } if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = mTopLevel + level; d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(context11, rtvDesc, texture->get(), &rtv)); rtv.setDebugName("TexStorage2D.RTV"); mRenderTarget[level].reset(new TextureRenderTarget11( std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, 0)); *outRT = mRenderTarget[level].get(); return angle::Result::Continue; } ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Format = mFormatInfo.dsvFormat; dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; dsvDesc.Texture2D.MipSlice = mTopLevel + level; dsvDesc.Flags = 0; d3d11::DepthStencilView dsv; ANGLE_TRY(mRenderer->allocateResource(context11, dsvDesc, texture->get(), &dsv)); dsv.setDebugName("TexStorage2D.DSV"); mRenderTarget[level].reset(new TextureRenderTarget11( std::move(dsv), *texture, *srv, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, 0)); *outRT = mRenderTarget[level].get(); return angle::Result::Continue; } angle::Result TextureStorage11_2D::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2D.MipLevels = mipLevels; const TextureHelper11 *srvTexture = &texture; if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ASSERT(mTopLevel == 0); ASSERT(baseLevel == 0); // This code also assumes that the incoming texture equals either mLevelZeroTexture or // mTexture. if (mipLevels == 1 && mMipLevels > 1) { // We must use a SRV on the level-zero-only texture. ANGLE_TRY(ensureTextureExists(context, 1)); srvTexture = &mLevelZeroTexture; } else { ASSERT(mipLevels == static_cast(mMipLevels)); ASSERT(mTexture.valid() && texture == mTexture); srvTexture = &mTexture; } } ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), srvDesc, srvTexture->get(), outSRV)); outSRV->setDebugName("TexStorage2D.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_2D::createSRVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = mTopLevel + level; srvDesc.Texture2D.MipLevels = 1; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage2D.SRVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_2D::createUAVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedUAV *outUAV) { ASSERT(outUAV); D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; uavDesc.Format = format; uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; uavDesc.Texture2D.MipSlice = mTopLevel + level; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), uavDesc, texture.get(), outUAV)); outUAV->setDebugName("TexStorage2D.UAVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_2D::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { ASSERT(outTexture); if (!mSwizzleTexture.valid()) { const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = 1; desc.Format = format.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, format, &mSwizzleTexture)); mSwizzleTexture.setDebugName("TexStorage2D.SwizzleTexture"); } *outTexture = &mSwizzleTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2D::getSwizzleRenderTarget(const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); if (!mSwizzleRenderTargets[mipLevel].valid()) { const TextureHelper11 *swizzleTexture = nullptr; ANGLE_TRY(getSwizzleTexture(context, &swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, mSwizzleTexture.get(), &mSwizzleRenderTargets[mipLevel])); } *outRTV = &mSwizzleRenderTargets[mipLevel]; return angle::Result::Continue; } angle::Result TextureStorage11_2D::ensureDropStencilTexture(const gl::Context *context, DropStencil *dropStencilOut) { if (mDropStencilTexture.valid()) { *dropStencilOut = DropStencil::ALREADY_EXISTS; return angle::Result::Continue; } D3D11_TEXTURE2D_DESC dropDesc = {}; dropDesc.ArraySize = 1; dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; dropDesc.CPUAccessFlags = 0; dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; dropDesc.Height = mTextureHeight; dropDesc.MipLevels = mMipLevels; dropDesc.MiscFlags = 0; dropDesc.SampleDesc.Count = 1; dropDesc.SampleDesc.Quality = 0; dropDesc.Usage = D3D11_USAGE_DEFAULT; dropDesc.Width = mTextureWidth; const auto &format = d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), dropDesc, format, &mDropStencilTexture)); mDropStencilTexture.setDebugName("TexStorage2D.DropStencil"); ANGLE_TRY(initDropStencilTexture(context, gl::ImageIndexIterator::Make2D(0, mMipLevels))); *dropStencilOut = DropStencil::CREATED; return angle::Result::Continue; } angle::Result TextureStorage11_2D::resolveTexture(const gl::Context *context) { if (mMSTexInfo && mMSTexInfo->msTex && mMSTexInfo->msTextureNeedsResolve) { ANGLE_TRY(resolveTextureHelper(context, mTexture)); onStateChange(angle::SubjectMessage::ContentsChanged); } return angle::Result::Continue; } TextureStorage11_External::TextureStorage11_External( Renderer11 *renderer, egl::Stream *stream, const egl::Stream::GLTextureDescription &glDesc) : TextureStorage11(renderer, D3D11_BIND_SHADER_RESOURCE, 0, glDesc.internalFormat) { ASSERT(stream->getProducerType() == egl::Stream::ProducerType::D3D11Texture); auto *producer = static_cast(stream->getImplementation()); mTexture.set(producer->getD3DTexture(), mFormatInfo); mSubresourceIndex = producer->getArraySlice(); mTexture.get()->AddRef(); mMipLevels = 1; D3D11_TEXTURE2D_DESC desc; mTexture.getDesc(&desc); mTextureWidth = desc.Width; mTextureHeight = desc.Height; mTextureDepth = 1; mHasKeyedMutex = (desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) != 0; } angle::Result TextureStorage11_External::onDestroy(const gl::Context *context) { if (mHasKeyedMutex) { // If the keyed mutex is released that will unbind it and cause the state cache to become // desynchronized. mRenderer->getStateManager()->invalidateBoundViews(); } return angle::Result::Continue; } TextureStorage11_External::~TextureStorage11_External() {} angle::Result TextureStorage11_External::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { UNIMPLEMENTED(); return angle::Result::Continue; } void TextureStorage11_External::associateImage(Image11 *image, const gl::ImageIndex &index) { ASSERT(index.getLevelIndex() == 0); mAssociatedImage = image; } void TextureStorage11_External::verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) { ASSERT(index.getLevelIndex() == 0 && mAssociatedImage == expectedImage); } void TextureStorage11_External::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { ASSERT(index.getLevelIndex() == 0); ASSERT(mAssociatedImage == expectedImage); mAssociatedImage = nullptr; } angle::Result TextureStorage11_External::releaseAssociatedImage(const gl::Context *context, const gl::ImageIndex &index, Image11 *incomingImage) { ASSERT(index.getLevelIndex() == 0); if (mAssociatedImage != nullptr && mAssociatedImage != incomingImage) { mAssociatedImage->verifyAssociatedStorageValid(this); ANGLE_TRY(mAssociatedImage->recoverFromAssociatedStorage(context)); } return angle::Result::Continue; } angle::Result TextureStorage11_External::getResource(const gl::Context *context, const TextureHelper11 **outResource) { *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_External::getMippedResource(const gl::Context *context, const TextureHelper11 **outResource) { *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_External::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { // Render targets are not supported for external textures ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_External::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { // Render targets are not supported for external textures ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_External::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { // Since external textures are treates as non-mipmapped textures, we ignore mipmap levels and // use the specified subresource ID the storage was created with. ASSERT(mipLevels == 1); ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // subresource index is equal to the mip level for 2D textures srvDesc.Texture2DArray.MostDetailedMip = 0; srvDesc.Texture2DArray.MipLevels = 1; srvDesc.Texture2DArray.FirstArraySlice = mSubresourceIndex; srvDesc.Texture2DArray.ArraySize = 1; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage2D.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_External::createSRVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_External::createUAVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedUAV *outUAV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_External::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_External::getSwizzleRenderTarget( const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } TextureStorage11ImmutableBase::TextureStorage11ImmutableBase(Renderer11 *renderer, UINT bindFlags, UINT miscFlags, GLenum internalFormat) : TextureStorage11(renderer, bindFlags, miscFlags, internalFormat) {} void TextureStorage11ImmutableBase::associateImage(Image11 *, const gl::ImageIndex &) {} void TextureStorage11ImmutableBase::disassociateImage(const gl::ImageIndex &, Image11 *) {} void TextureStorage11ImmutableBase::verifyAssociatedImageValid(const gl::ImageIndex &, Image11 *) {} angle::Result TextureStorage11ImmutableBase::releaseAssociatedImage(const gl::Context *context, const gl::ImageIndex &, Image11 *) { return angle::Result::Continue; } angle::Result TextureStorage11ImmutableBase::createSRVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11ImmutableBase::createUAVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedUAV *outUAV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } TextureStorage11_EGLImage::TextureStorage11_EGLImage(Renderer11 *renderer, EGLImageD3D *eglImage, RenderTarget11 *renderTarget11) : TextureStorage11ImmutableBase(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, 0, renderTarget11->getInternalFormat()), mImage(eglImage), mCurrentRenderTarget(0), mSwizzleTexture(), mSwizzleRenderTargets(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { mCurrentRenderTarget = reinterpret_cast(renderTarget11); mMipLevels = 1; mTextureWidth = renderTarget11->getWidth(); mTextureHeight = renderTarget11->getHeight(); mTextureDepth = 1; } TextureStorage11_EGLImage::~TextureStorage11_EGLImage() {} angle::Result TextureStorage11_EGLImage::getSubresourceIndex(const gl::Context *context, const gl::ImageIndex &index, UINT *outSubresourceIndex) const { ASSERT(index.getType() == gl::TextureType::_2D); ASSERT(index.getLevelIndex() == 0); RenderTarget11 *renderTarget11 = nullptr; ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); *outSubresourceIndex = renderTarget11->getSubresourceIndex(); return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::getResource(const gl::Context *context, const TextureHelper11 **outResource) { ANGLE_TRY(checkForUpdatedRenderTarget(context)); RenderTarget11 *renderTarget11 = nullptr; ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); *outResource = &renderTarget11->getTexture(); return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::getSRVForSampler(const gl::Context *context, const gl::TextureState &textureState, const gl::SamplerState &sampler, const d3d11::SharedSRV **outSRV) { ANGLE_TRY(checkForUpdatedRenderTarget(context)); return TextureStorage11::getSRVForSampler(context, textureState, sampler, outSRV); } angle::Result TextureStorage11_EGLImage::getMippedResource(const gl::Context *context, const TextureHelper11 **) { // This shouldn't be called unless the zero max LOD workaround is active. // EGL images are unavailable in this configuration. ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_EGLImage::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { // Since the render target of an EGL image will be updated when orphaning, trying to find a // cache of it can be rarely useful. ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_EGLImage::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); ASSERT(index.getLevelIndex() == 0); ANGLE_TRY(checkForUpdatedRenderTarget(context)); return mImage->getRenderTarget(context, outRT); } angle::Result TextureStorage11_EGLImage::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { const TextureHelper11 *sourceResouce = nullptr; ANGLE_TRY(getResource(context, &sourceResouce)); ASSERT(destStorage); TextureStorage11_2D *dest11 = GetAs(destStorage); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); immediateContext->CopyResource(destResource->get(), sourceResouce->get()); dest11->markDirty(); return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::useLevelZeroWorkaroundTexture(const gl::Context *context, bool) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_EGLImage::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { ASSERT(outTexture); if (!mSwizzleTexture.valid()) { const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = 1; desc.Format = format.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, format, &mSwizzleTexture)); mSwizzleTexture.setDebugName("TexStorageEGLImage.SwizzleTexture"); } *outTexture = &mSwizzleTexture; return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::getSwizzleRenderTarget( const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); if (!mSwizzleRenderTargets[mipLevel].valid()) { const TextureHelper11 *swizzleTexture = nullptr; ANGLE_TRY(getSwizzleTexture(context, &swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, mSwizzleTexture.get(), &mSwizzleRenderTargets[mipLevel])); } *outRTV = &mSwizzleRenderTargets[mipLevel]; return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::checkForUpdatedRenderTarget(const gl::Context *context) { RenderTarget11 *renderTarget11 = nullptr; ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); if (mCurrentRenderTarget != reinterpret_cast(renderTarget11)) { clearSRVCache(); mCurrentRenderTarget = reinterpret_cast(renderTarget11); } return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(baseLevel == 0); ASSERT(mipLevels == 1); ASSERT(outSRV); // Create a new SRV only for the swizzle texture. Otherwise just return the Image's // RenderTarget's SRV. if (texture == mSwizzleTexture) { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2D.MipLevels = mipLevels; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorageEGLImage.SRV"); } else { RenderTarget11 *renderTarget = nullptr; ANGLE_TRY(getImageRenderTarget(context, &renderTarget)); ASSERT(texture == renderTarget->getTexture()); *outSRV = renderTarget->getShaderResourceView(context).makeCopy(); } return angle::Result::Continue; } angle::Result TextureStorage11_EGLImage::getImageRenderTarget(const gl::Context *context, RenderTarget11 **outRT) const { RenderTargetD3D *renderTargetD3D = nullptr; ANGLE_TRY(mImage->getRenderTarget(context, &renderTargetD3D)); *outRT = GetAs(renderTargetD3D); return angle::Result::Continue; } TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) : TextureStorage11( renderer, GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels), internalformat), mTexture(), mLevelZeroTexture(), mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), mSwizzleTexture() { for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { for (unsigned int face = 0; face < gl::kCubeFaceCount; face++) { mAssociatedImages[face][level] = nullptr; mRenderTarget[face][level] = nullptr; } } for (unsigned int face = 0; face < gl::kCubeFaceCount; face++) { mLevelZeroRenderTarget[face] = nullptr; } // adjust size if needed for compressed textures int height = size; d3d11::MakeValidSize(false, mFormatInfo.texFormat, &size, &height, &mTopLevel); mMipLevels = mTopLevel + levels; mTextureWidth = size; mTextureHeight = size; mTextureDepth = 1; // The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. ASSERT(!mUseLevelZeroTexture || mRenderer->getFeatures().zeroMaxLodWorkaround.enabled); } angle::Result TextureStorage11_Cube::onDestroy(const gl::Context *context) { for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { for (unsigned int face = 0; face < gl::kCubeFaceCount; face++) { if (mAssociatedImages[face][level] != nullptr) { mAssociatedImages[face][level]->verifyAssociatedStorageValid(this); // We must let the Images recover their data before we delete it from the // TextureStorage. ANGLE_TRY(mAssociatedImages[face][level]->recoverFromAssociatedStorage(context)); } } } return angle::Result::Continue; } TextureStorage11_Cube::~TextureStorage11_Cube() {} angle::Result TextureStorage11_Cube::getSubresourceIndex(const gl::Context *context, const gl::ImageIndex &index, UINT *outSubresourceIndex) const { UINT arraySlice = index.cubeMapFaceIndex(); if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled && mUseLevelZeroTexture && index.getLevelIndex() == 0) { UINT subresource = D3D11CalcSubresource(0, arraySlice, 1); ASSERT(subresource != std::numeric_limits::max()); *outSubresourceIndex = subresource; } else { UINT mipSlice = static_cast(index.getLevelIndex() + mTopLevel); UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); ASSERT(subresource != std::numeric_limits::max()); *outSubresourceIndex = subresource; } return angle::Result::Continue; } angle::Result TextureStorage11_Cube::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ASSERT(destStorage); TextureStorage11_Cube *dest11 = GetAs(destStorage); if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the // corresponding textures in destStorage. if (mTexture.valid()) { ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, false)); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); immediateContext->CopyResource(destResource->get(), mTexture.get()); } if (mLevelZeroTexture.valid()) { ANGLE_TRY(dest11->useLevelZeroWorkaroundTexture(context, true)); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); immediateContext->CopyResource(destResource->get(), mLevelZeroTexture.get()); } } else { const TextureHelper11 *sourceResouce = nullptr; ANGLE_TRY(getResource(context, &sourceResouce)); const TextureHelper11 *destResource = nullptr; ANGLE_TRY(dest11->getResource(context, &destResource)); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); immediateContext->CopyResource(destResource->get(), sourceResouce->get()); } dest11->markDirty(); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::useLevelZeroWorkaroundTexture(const gl::Context *context, bool useLevelZeroTexture) { if (useLevelZeroTexture && mMipLevels > 1) { if (!mUseLevelZeroTexture && mTexture.valid()) { ANGLE_TRY(ensureTextureExists(context, 1)); // Pull data back from the mipped texture if necessary. ASSERT(mLevelZeroTexture.valid()); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (int face = 0; face < 6; face++) { deviceContext->CopySubresourceRegion(mLevelZeroTexture.get(), D3D11CalcSubresource(0, face, 1), 0, 0, 0, mTexture.get(), face * mMipLevels, nullptr); } } mUseLevelZeroTexture = true; } else { if (mUseLevelZeroTexture && mLevelZeroTexture.valid()) { ANGLE_TRY(ensureTextureExists(context, mMipLevels)); // Pull data back from the level zero texture if necessary. ASSERT(mTexture.valid()); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); for (int face = 0; face < 6; face++) { deviceContext->CopySubresourceRegion(mTexture.get(), D3D11CalcSubresource(0, face, mMipLevels), 0, 0, 0, mLevelZeroTexture.get(), face, nullptr); } } mUseLevelZeroTexture = false; } return angle::Result::Continue; } void TextureStorage11_Cube::associateImage(Image11 *image, const gl::ImageIndex &index) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.cubeMapFaceIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::kCubeFaceCount)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { if (0 <= layerTarget && layerTarget < static_cast(gl::kCubeFaceCount)) { mAssociatedImages[layerTarget][level] = image; } } } void TextureStorage11_Cube::verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.cubeMapFaceIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::kCubeFaceCount)); // This validation check should never return false. It means the Image/TextureStorage // association is broken. ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.cubeMapFaceIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::kCubeFaceCount)); ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); mAssociatedImages[layerTarget][level] = nullptr; } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image // recover its data before ending the association. angle::Result TextureStorage11_Cube::releaseAssociatedImage(const gl::Context *context, const gl::ImageIndex &index, Image11 *incomingImage) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.cubeMapFaceIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < static_cast(gl::kCubeFaceCount)); if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) { if (0 <= layerTarget && layerTarget < static_cast(gl::kCubeFaceCount)) { // No need to let the old Image recover its data, if it is also the incoming Image. if (mAssociatedImages[layerTarget][level] != nullptr && mAssociatedImages[layerTarget][level] != incomingImage) { // Ensure that the Image is still associated with this TextureStorage. mAssociatedImages[layerTarget][level]->verifyAssociatedStorageValid(this); // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to nullptr too. ANGLE_TRY( mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(context)); } } } return angle::Result::Continue; } angle::Result TextureStorage11_Cube::getResource(const gl::Context *context, const TextureHelper11 **outResource) { if (mUseLevelZeroTexture && mMipLevels > 1) { ANGLE_TRY(ensureTextureExists(context, 1)); *outResource = &mLevelZeroTexture; } else { ANGLE_TRY(ensureTextureExists(context, mMipLevels)); *outResource = &mTexture; } return angle::Result::Continue; } angle::Result TextureStorage11_Cube::getMippedResource(const gl::Context *context, const TextureHelper11 **outResource) { // This shouldn't be called unless the zero max LOD workaround is active. ASSERT(mRenderer->getFeatures().zeroMaxLodWorkaround.enabled); ANGLE_TRY(ensureTextureExists(context, mMipLevels)); *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_Cube::ensureTextureExists(const gl::Context *context, int mipLevels) { // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. ANGLE_TRY(resolveTexture(context)); bool useLevelZeroTexture = mRenderer->getFeatures().zeroMaxLodWorkaround.enabled ? (mipLevels == 1) && (mMipLevels > 1) : false; TextureHelper11 *outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; // if the size is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation if (!outputTexture->valid() && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mipLevels; desc.ArraySize = gl::kCubeFaceCount; desc.Format = mFormatInfo.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = getBindFlags(); desc.CPUAccessFlags = 0; desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE | getMiscFlags(); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, mFormatInfo, outputTexture)); outputTexture->setDebugName("TexStorageCube.Texture"); } return angle::Result::Continue; } angle::Result TextureStorage11_Cube::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { const int faceIndex = index.cubeMapFaceIndex(); const int level = index.getLevelIndex(); ASSERT(level >= 0 && level < getLevelCount()); ASSERT(faceIndex >= 0 && faceIndex < static_cast(gl::kCubeFaceCount)); bool needMS = samples > 0; if (needMS) { return findMultisampledRenderTarget(context, index, samples, outRT); } if (!mRenderTarget[faceIndex][level]) { if (mUseLevelZeroTexture) { ASSERT(index.getLevelIndex() == 0); ASSERT(outRT); *outRT = mLevelZeroRenderTarget[faceIndex].get(); return angle::Result::Continue; } } ASSERT(outRT); *outRT = mRenderTarget[faceIndex][level].get(); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::createRenderTargetSRV(const gl::Context *context, const TextureHelper11 &texture, const gl::ImageIndex &index, DXGI_FORMAT resourceFormat, d3d11::SharedSRV *srv) const { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = resourceFormat; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + index.getLevelIndex(); srvDesc.Texture2DArray.MipLevels = 1; srvDesc.Texture2DArray.FirstArraySlice = index.cubeMapFaceIndex(); srvDesc.Texture2DArray.ArraySize = 1; if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_10_0) { srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; } else { // Will be used with Texture2D sampler, not TextureCube srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; } ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), srv)); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { const int faceIndex = index.cubeMapFaceIndex(); const int level = index.getLevelIndex(); ASSERT(level >= 0 && level < getLevelCount()); ASSERT(faceIndex >= 0 && faceIndex < static_cast(gl::kCubeFaceCount)); bool needMS = samples > 0; if (needMS) { return getMultisampledRenderTarget(context, index, samples, outRT); } else { ANGLE_TRY(resolveTexture(context)); } Context11 *context11 = GetImplAs(context); if (!mRenderTarget[faceIndex][level]) { if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ASSERT(index.getLevelIndex() == 0); ANGLE_TRY(useLevelZeroWorkaroundTexture(context, true)); } const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); if (mUseLevelZeroTexture) { if (!mLevelZeroRenderTarget[faceIndex]) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; rtvDesc.Texture2DArray.ArraySize = 1; d3d11::RenderTargetView rtv; ANGLE_TRY( mRenderer->allocateResource(context11, rtvDesc, mLevelZeroTexture.get(), &rtv)); mLevelZeroRenderTarget[faceIndex].reset(new TextureRenderTarget11( std::move(rtv), mLevelZeroTexture, d3d11::SharedSRV(), d3d11::SharedSRV(), mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, 0)); } ASSERT(outRT); *outRT = mLevelZeroRenderTarget[faceIndex].get(); return angle::Result::Continue; } d3d11::SharedSRV srv; ANGLE_TRY(createRenderTargetSRV(context, *texture, index, mFormatInfo.srvFormat, &srv)); d3d11::SharedSRV blitSRV; if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { ANGLE_TRY(createRenderTargetSRV(context, *texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } else { blitSRV = srv.makeCopy(); } srv.setDebugName("TexStorageCube.RenderTargetSRV"); if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; rtvDesc.Texture2DArray.ArraySize = 1; d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(context11, rtvDesc, texture->get(), &rtv)); rtv.setDebugName("TexStorageCube.RenderTargetRTV"); mRenderTarget[faceIndex][level].reset(new TextureRenderTarget11( std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, 0)); } else if (mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Format = mFormatInfo.dsvFormat; dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; dsvDesc.Flags = 0; dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; dsvDesc.Texture2DArray.ArraySize = 1; d3d11::DepthStencilView dsv; ANGLE_TRY(mRenderer->allocateResource(context11, dsvDesc, texture->get(), &dsv)); dsv.setDebugName("TexStorageCube.RenderTargetDSV"); mRenderTarget[faceIndex][level].reset(new TextureRenderTarget11( std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, 0)); } else { UNREACHABLE(); } } ASSERT(outRT); *outRT = mRenderTarget[faceIndex][level].get(); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six // 2D textures const GLenum componentType = d3d11::GetComponentType(format); if (componentType == GL_INT || componentType == GL_UNSIGNED_INT) { srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2DArray.MipLevels = mipLevels; srvDesc.Texture2DArray.FirstArraySlice = 0; srvDesc.Texture2DArray.ArraySize = gl::kCubeFaceCount; } else { srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; srvDesc.TextureCube.MipLevels = mipLevels; srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; } const TextureHelper11 *srvTexture = &texture; if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) { ASSERT(mTopLevel == 0); ASSERT(baseLevel == 0); // This code also assumes that the incoming texture equals either mLevelZeroTexture or // mTexture. if (mipLevels == 1 && mMipLevels > 1) { // We must use a SRV on the level-zero-only texture. ANGLE_TRY(ensureTextureExists(context, 1)); srvTexture = &mLevelZeroTexture; } else { ASSERT(mipLevels == static_cast(mMipLevels)); ASSERT(mTexture.valid() && texture == mTexture); srvTexture = &mTexture; } } ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), srvDesc, srvTexture->get(), outSRV)); outSRV->setDebugName("TexStorageCube.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::createSRVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; srvDesc.Texture2DArray.MipLevels = 1; srvDesc.Texture2DArray.FirstArraySlice = 0; srvDesc.Texture2DArray.ArraySize = gl::kCubeFaceCount; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorageCube.SRVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::createUAVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedUAV *outUAV) { ASSERT(outUAV); D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; uavDesc.Format = format; uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; uavDesc.Texture2DArray.MipSlice = mTopLevel + level; uavDesc.Texture2DArray.FirstArraySlice = 0; uavDesc.Texture2DArray.ArraySize = gl::kCubeFaceCount; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), uavDesc, texture.get(), outUAV)); outUAV->setDebugName("TexStorageCube.UAVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_Cube::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { ASSERT(outTexture); if (!mSwizzleTexture.valid()) { const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = gl::kCubeFaceCount; desc.Format = format.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; desc.CPUAccessFlags = 0; desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, format, &mSwizzleTexture)); mSwizzleTexture.setDebugName("TexStorageCube.SwizzleTexture"); } *outTexture = &mSwizzleTexture; return angle::Result::Continue; } angle::Result TextureStorage11_Cube::getSwizzleRenderTarget(const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); if (!mSwizzleRenderTargets[mipLevel].valid()) { const TextureHelper11 *swizzleTexture = nullptr; ANGLE_TRY(getSwizzleTexture(context, &swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = 0; rtvDesc.Texture2DArray.ArraySize = gl::kCubeFaceCount; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, mSwizzleTexture.get(), &mSwizzleRenderTargets[mipLevel])); } *outRTV = &mSwizzleRenderTargets[mipLevel]; return angle::Result::Continue; } angle::Result TextureStorage11_Cube::ensureDropStencilTexture(const gl::Context *context, DropStencil *dropStencilOut) { if (mDropStencilTexture.valid()) { *dropStencilOut = DropStencil::ALREADY_EXISTS; return angle::Result::Continue; } D3D11_TEXTURE2D_DESC dropDesc = {}; dropDesc.ArraySize = 6; dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; dropDesc.CPUAccessFlags = 0; dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; dropDesc.Height = mTextureHeight; dropDesc.MipLevels = mMipLevels; dropDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; dropDesc.SampleDesc.Count = 1; dropDesc.SampleDesc.Quality = 0; dropDesc.Usage = D3D11_USAGE_DEFAULT; dropDesc.Width = mTextureWidth; const auto &format = d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), dropDesc, format, &mDropStencilTexture)); mDropStencilTexture.setDebugName("TexStorageCube.DropStencil"); ANGLE_TRY(initDropStencilTexture(context, gl::ImageIndexIterator::MakeCube(0, mMipLevels))); *dropStencilOut = DropStencil::CREATED; return angle::Result::Continue; } angle::Result TextureStorage11_Cube::resolveTexture(const gl::Context *context) { if (mMSTexInfo && mMSTexInfo->msTex && mMSTexInfo->msTextureNeedsResolve) { ANGLE_TRY(resolveTextureHelper(context, mTexture)); onStateChange(angle::SubjectMessage::ContentsChanged); } return angle::Result::Continue; } TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) : TextureStorage11( renderer, GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels), internalformat) { for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { mAssociatedImages[i] = nullptr; mLevelRenderTargets[i] = nullptr; } // adjust size if needed for compressed textures d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); mMipLevels = mTopLevel + levels; mTextureWidth = width; mTextureHeight = height; mTextureDepth = depth; } angle::Result TextureStorage11_3D::onDestroy(const gl::Context *context) { for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { if (mAssociatedImages[i] != nullptr) { mAssociatedImages[i]->verifyAssociatedStorageValid(this); // We must let the Images recover their data before we delete it from the // TextureStorage. ANGLE_TRY(mAssociatedImages[i]->recoverFromAssociatedStorage(context)); } } return angle::Result::Continue; } TextureStorage11_3D::~TextureStorage11_3D() {} void TextureStorage11_3D::associateImage(Image11 *image, const gl::ImageIndex &index) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { mAssociatedImages[level] = image; } } void TextureStorage11_3D::verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); // This validation check should never return false. It means the Image/TextureStorage // association is broken. ASSERT(mAssociatedImages[level] == expectedImage); } // disassociateImage allows an Image to end its association with a Storage. void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(mAssociatedImages[level] == expectedImage); mAssociatedImages[level] = nullptr; } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image // recover its data before ending the association. angle::Result TextureStorage11_3D::releaseAssociatedImage(const gl::Context *context, const gl::ImageIndex &index, Image11 *incomingImage) { const GLint level = index.getLevelIndex(); ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // No need to let the old Image recover its data, if it is also the incoming Image. if (mAssociatedImages[level] != nullptr && mAssociatedImages[level] != incomingImage) { // Ensure that the Image is still associated with this TextureStorage. mAssociatedImages[level]->verifyAssociatedStorageValid(this); // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to nullptr too. ANGLE_TRY(mAssociatedImages[level]->recoverFromAssociatedStorage(context)); } } return angle::Result::Continue; } angle::Result TextureStorage11_3D::getResource(const gl::Context *context, const TextureHelper11 **outResource) { // If the width, height or depth are not positive this should be treated as an incomplete // texture. We handle that here by skipping the d3d texture creation. if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) { ASSERT(mMipLevels > 0); D3D11_TEXTURE3D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.Depth = mTextureDepth; desc.MipLevels = mMipLevels; desc.Format = mFormatInfo.texFormat; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = getBindFlags(); desc.CPUAccessFlags = 0; desc.MiscFlags = getMiscFlags(); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, mFormatInfo, &mTexture)); mTexture.setDebugName("TexStorage3D.Texture"); } *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_3D::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; srvDesc.Texture3D.MostDetailedMip = baseLevel; srvDesc.Texture3D.MipLevels = mipLevels; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage3D.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_3D::createSRVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; srvDesc.Texture3D.MostDetailedMip = mTopLevel + level; srvDesc.Texture3D.MipLevels = 1; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage3D.SRVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_3D::createUAVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedUAV *outUAV) { ASSERT(outUAV); D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; uavDesc.Format = format; uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D; uavDesc.Texture3D.MipSlice = mTopLevel + level; uavDesc.Texture3D.FirstWSlice = 0; uavDesc.Texture3D.WSize = mTextureDepth; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), uavDesc, texture.get(), outUAV)); outUAV->setDebugName("TexStorage3D.UAVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_3D::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { const int mipLevel = index.getLevelIndex(); ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); if (!index.hasLayer()) { ASSERT(outRT); *outRT = mLevelRenderTargets[mipLevel].get(); return angle::Result::Continue; } const int layer = index.getLayerIndex(); LevelLayerKey key(mipLevel, layer); if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) { ASSERT(outRT); *outRT = nullptr; return angle::Result::Continue; } ASSERT(outRT); *outRT = mLevelLayerRenderTargets.at(key).get(); return angle::Result::Continue; } angle::Result TextureStorage11_3D::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { const int mipLevel = index.getLevelIndex(); ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); Context11 *context11 = GetImplAs(context); if (!index.hasLayer()) { if (!mLevelRenderTargets[mipLevel]) { const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); const d3d11::SharedSRV *srv = nullptr; ANGLE_TRY(getSRVLevel(context, mipLevel, false, &srv)); const d3d11::SharedSRV *blitSRV = nullptr; ANGLE_TRY(getSRVLevel(context, mipLevel, true, &blitSRV)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture3D.FirstWSlice = 0; rtvDesc.Texture3D.WSize = static_cast(-1); d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(context11, rtvDesc, texture->get(), &rtv)); rtv.setDebugName("TexStorage3D.RTV"); mLevelRenderTargets[mipLevel].reset(new TextureRenderTarget11( std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0)); } ASSERT(outRT); *outRT = mLevelRenderTargets[mipLevel].get(); return angle::Result::Continue; } const int layer = index.getLayerIndex(); LevelLayerKey key(mipLevel, layer); if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) { const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); // TODO, what kind of SRV is expected here? const d3d11::SharedSRV srv; const d3d11::SharedSRV blitSRV; D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture3D.FirstWSlice = layer; rtvDesc.Texture3D.WSize = 1; d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(context11, rtvDesc, texture->get(), &rtv)); rtv.setDebugName("TexStorage3D.LayerRTV"); mLevelLayerRenderTargets[key].reset(new TextureRenderTarget11( std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } ASSERT(outRT); *outRT = mLevelLayerRenderTargets[key].get(); return angle::Result::Continue; } angle::Result TextureStorage11_3D::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { ASSERT(outTexture); if (!mSwizzleTexture.valid()) { const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE3D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.Depth = mTextureDepth; desc.MipLevels = mMipLevels; desc.Format = format.texFormat; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, format, &mSwizzleTexture)); mSwizzleTexture.setDebugName("TexStorage3D.SwizzleTexture"); } *outTexture = &mSwizzleTexture; return angle::Result::Continue; } angle::Result TextureStorage11_3D::getSwizzleRenderTarget(const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); if (!mSwizzleRenderTargets[mipLevel].valid()) { const TextureHelper11 *swizzleTexture = nullptr; ANGLE_TRY(getSwizzleTexture(context, &swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture3D.FirstWSlice = 0; rtvDesc.Texture3D.WSize = static_cast(-1); ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, mSwizzleTexture.get(), &mSwizzleRenderTargets[mipLevel])); mSwizzleRenderTargets[mipLevel].setDebugName("TexStorage3D.SwizzleRTV"); } *outRTV = &mSwizzleRenderTargets[mipLevel]; return angle::Result::Continue; } TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) : TextureStorage11( renderer, GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget), GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), renderTarget, levels), internalformat) { // adjust size if needed for compressed textures d3d11::MakeValidSize(false, mFormatInfo.texFormat, &width, &height, &mTopLevel); mMipLevels = mTopLevel + levels; mTextureWidth = width; mTextureHeight = height; mTextureDepth = depth; } angle::Result TextureStorage11_2DArray::onDestroy(const gl::Context *context) { for (auto iter : mAssociatedImages) { if (iter.second) { iter.second->verifyAssociatedStorageValid(this); // We must let the Images recover their data before we delete it from the // TextureStorage. ANGLE_TRY(iter.second->recoverFromAssociatedStorage(context)); } } mAssociatedImages.clear(); return angle::Result::Continue; } TextureStorage11_2DArray::~TextureStorage11_2DArray() {} void TextureStorage11_2DArray::associateImage(Image11 *image, const gl::ImageIndex &index) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.getLayerIndex(); const GLint numLayers = index.getLayerCount(); ASSERT(0 <= level && level < getLevelCount()); if (0 <= level && level < getLevelCount()) { LevelLayerRangeKey key(level, layerTarget, numLayers); mAssociatedImages[key] = image; } } void TextureStorage11_2DArray::verifyAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.getLayerIndex(); const GLint numLayers = index.getLayerCount(); LevelLayerRangeKey key(level, layerTarget, numLayers); // This validation check should never return false. It means the Image/TextureStorage // association is broken. bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); ASSERT(retValue); } // disassociateImage allows an Image to end its association with a Storage. void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.getLayerIndex(); const GLint numLayers = index.getLayerCount(); LevelLayerRangeKey key(level, layerTarget, numLayers); bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); ASSERT(imageAssociationCorrect); mAssociatedImages[key] = nullptr; } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image // recover its data before ending the association. angle::Result TextureStorage11_2DArray::releaseAssociatedImage(const gl::Context *context, const gl::ImageIndex &index, Image11 *incomingImage) { const GLint level = index.getLevelIndex(); const GLint layerTarget = index.getLayerIndex(); const GLint numLayers = index.getLayerCount(); LevelLayerRangeKey key(level, layerTarget, numLayers); if (mAssociatedImages.find(key) != mAssociatedImages.end()) { if (mAssociatedImages[key] != nullptr && mAssociatedImages[key] != incomingImage) { // Ensure that the Image is still associated with this TextureStorage. mAssociatedImages[key]->verifyAssociatedStorageValid(this); // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to nullptr too. ANGLE_TRY(mAssociatedImages[key]->recoverFromAssociatedStorage(context)); } } return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::getResource(const gl::Context *context, const TextureHelper11 **outResource) { // if the width, height or depth is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) { ASSERT(mMipLevels > 0); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = mTextureDepth; desc.Format = mFormatInfo.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = getBindFlags(); desc.CPUAccessFlags = 0; desc.MiscFlags = getMiscFlags(); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, mFormatInfo, &mTexture)); mTexture.setDebugName("TexStorage2DArray.Texture"); } *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2DArray.MipLevels = mipLevels; srvDesc.Texture2DArray.FirstArraySlice = 0; srvDesc.Texture2DArray.ArraySize = mTextureDepth; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage2DArray.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::createSRVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; srvDesc.Texture2DArray.MipLevels = 1; srvDesc.Texture2DArray.FirstArraySlice = 0; srvDesc.Texture2DArray.ArraySize = mTextureDepth; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage2DArray.SRVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::createUAVForImage(const gl::Context *context, int level, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedUAV *outUAV) { ASSERT(outUAV); D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; uavDesc.Format = format; uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; uavDesc.Texture2DArray.MipSlice = mTopLevel + level; uavDesc.Texture2DArray.FirstArraySlice = 0; uavDesc.Texture2DArray.ArraySize = mTextureDepth; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), uavDesc, texture.get(), outUAV)); outUAV->setDebugName("TexStorage2DArray.UAVForImage"); return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { ASSERT(index.hasLayer()); const int mipLevel = index.getLevelIndex(); const int layer = index.getLayerIndex(); const int numLayers = index.getLayerCount(); ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); LevelLayerRangeKey key(mipLevel, layer, numLayers); if (mRenderTargets.find(key) == mRenderTargets.end()) { ASSERT(outRT); *outRT = nullptr; return angle::Result::Continue; } ASSERT(outRT); *outRT = mRenderTargets.at(key).get(); return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::createRenderTargetSRV(const gl::Context *context, const TextureHelper11 &texture, const gl::ImageIndex &index, DXGI_FORMAT resourceFormat, d3d11::SharedSRV *srv) const { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = resourceFormat; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + index.getLevelIndex(); srvDesc.Texture2DArray.MipLevels = 1; srvDesc.Texture2DArray.FirstArraySlice = index.getLayerIndex(); srvDesc.Texture2DArray.ArraySize = index.getLayerCount(); ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), srv)); return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { ASSERT(index.hasLayer()); const int mipLevel = index.getLevelIndex(); const int layer = index.getLayerIndex(); const int numLayers = index.getLayerCount(); ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); LevelLayerRangeKey key(mipLevel, layer, numLayers); if (mRenderTargets.find(key) == mRenderTargets.end()) { const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); d3d11::SharedSRV srv; ANGLE_TRY(createRenderTargetSRV(context, *texture, index, mFormatInfo.srvFormat, &srv)); d3d11::SharedSRV blitSRV; if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { ANGLE_TRY(createRenderTargetSRV(context, *texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } else { blitSRV = srv.makeCopy(); } srv.setDebugName("TexStorage2DArray.RenderTargetSRV"); if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = layer; rtvDesc.Texture2DArray.ArraySize = numLayers; d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, texture->get(), &rtv)); rtv.setDebugName("TexStorage2DArray.RenderTargetRTV"); mRenderTargets[key].reset(new TextureRenderTarget11( std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } else { ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Format = mFormatInfo.dsvFormat; dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; dsvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; dsvDesc.Texture2DArray.FirstArraySlice = layer; dsvDesc.Texture2DArray.ArraySize = numLayers; dsvDesc.Flags = 0; d3d11::DepthStencilView dsv; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), dsvDesc, texture->get(), &dsv)); dsv.setDebugName("TexStorage2DArray.RenderTargetDSV"); mRenderTargets[key].reset(new TextureRenderTarget11( std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0)); } } ASSERT(outRT); *outRT = mRenderTargets[key].get(); return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { if (!mSwizzleTexture.valid()) { const auto &format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()); D3D11_TEXTURE2D_DESC desc; desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; desc.ArraySize = mTextureDepth; desc.Format = format.texFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, format, &mSwizzleTexture)); mSwizzleTexture.setDebugName("TexStorage2DArray.SwizzleTexture"); } *outTexture = &mSwizzleTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::getSwizzleRenderTarget( const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); ASSERT(outRTV); if (!mSwizzleRenderTargets[mipLevel].valid()) { const TextureHelper11 *swizzleTexture = nullptr; ANGLE_TRY(getSwizzleTexture(context, &swizzleTexture)); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.getSwizzleFormat(mRenderer->getRenderer11DeviceCaps()).rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; rtvDesc.Texture2DArray.FirstArraySlice = 0; rtvDesc.Texture2DArray.ArraySize = mTextureDepth; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, mSwizzleTexture.get(), &mSwizzleRenderTargets[mipLevel])); } *outRTV = &mSwizzleRenderTargets[mipLevel]; return angle::Result::Continue; } angle::Result TextureStorage11_2DArray::ensureDropStencilTexture(const gl::Context *context, DropStencil *dropStencilOut) { if (mDropStencilTexture.valid()) { *dropStencilOut = DropStencil::ALREADY_EXISTS; return angle::Result::Continue; } D3D11_TEXTURE2D_DESC dropDesc = {}; dropDesc.ArraySize = mTextureDepth; dropDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL; dropDesc.CPUAccessFlags = 0; dropDesc.Format = DXGI_FORMAT_R32_TYPELESS; dropDesc.Height = mTextureHeight; dropDesc.MipLevels = mMipLevels; dropDesc.MiscFlags = 0; dropDesc.SampleDesc.Count = 1; dropDesc.SampleDesc.Quality = 0; dropDesc.Usage = D3D11_USAGE_DEFAULT; dropDesc.Width = mTextureWidth; const auto &format = d3d11::Format::Get(GL_DEPTH_COMPONENT32F, mRenderer->getRenderer11DeviceCaps()); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), dropDesc, format, &mDropStencilTexture)); mDropStencilTexture.setDebugName("TexStorage2DArray.DropStencil"); std::vector layerCounts(mMipLevels, mTextureDepth); ANGLE_TRY(initDropStencilTexture( context, gl::ImageIndexIterator::Make2DArray(0, mMipLevels, layerCounts.data()))); *dropStencilOut = DropStencil::CREATED; return angle::Result::Continue; } TextureStorage11_2DMultisample::TextureStorage11_2DMultisample(Renderer11 *renderer, GLenum internalformat, GLsizei width, GLsizei height, int levels, int samples, bool fixedSampleLocations) : TextureStorage11ImmutableBase( renderer, GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), true), GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), true, levels), internalformat), mTexture(), mRenderTarget(nullptr) { // There are no multisampled compressed formats, so there's no need to adjust texture size // according to block size. ASSERT(d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat).blockWidth <= 1); ASSERT(d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat).blockHeight <= 1); mMipLevels = 1; mTextureWidth = width; mTextureHeight = height; mTextureDepth = 1; mSamples = samples; mFixedSampleLocations = fixedSampleLocations; } angle::Result TextureStorage11_2DMultisample::onDestroy(const gl::Context *context) { mRenderTarget.reset(); return angle::Result::Continue; } TextureStorage11_2DMultisample::~TextureStorage11_2DMultisample() {} angle::Result TextureStorage11_2DMultisample::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_2DMultisample::getResource(const gl::Context *context, const TextureHelper11 **outResource) { ANGLE_TRY(ensureTextureExists(context, 1)); *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisample::ensureTextureExists(const gl::Context *context, int mipLevels) { // For Multisampled textures, mipLevels always equals 1. ASSERT(mipLevels == 1); // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0) { D3D11_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(desc)); desc.Width = mTextureWidth; // Compressed texture size constraints? desc.Height = mTextureHeight; desc.MipLevels = mipLevels; desc.ArraySize = 1; desc.Format = mFormatInfo.texFormat; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = getBindFlags() & ~D3D11_BIND_UNORDERED_ACCESS; desc.CPUAccessFlags = 0; desc.MiscFlags = getMiscFlags(); const gl::TextureCaps &textureCaps = mRenderer->getNativeTextureCaps().get(mFormatInfo.internalFormat); GLuint supportedSamples = textureCaps.getNearestSamples(mSamples); desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; desc.SampleDesc.Quality = mRenderer->getSampleDescQuality(supportedSamples); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, mFormatInfo, &mTexture)); mTexture.setDebugName("TexStorage2DMS.Texture"); } return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisample::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { ASSERT(!index.hasLayer()); const int level = index.getLevelIndex(); ASSERT(level == 0); ASSERT(outRT); *outRT = mRenderTarget.get(); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisample::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { ASSERT(!index.hasLayer()); const int level = index.getLevelIndex(); ASSERT(level == 0); ASSERT(outRT); if (mRenderTarget) { *outRT = mRenderTarget.get(); return angle::Result::Continue; } const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); const d3d11::SharedSRV *srv = nullptr; ANGLE_TRY(getSRVLevel(context, level, false, &srv)); const d3d11::SharedSRV *blitSRV = nullptr; ANGLE_TRY(getSRVLevel(context, level, true, &blitSRV)); Context11 *context11 = GetImplAs(context); if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(context11, rtvDesc, texture->get(), &rtv)); mRenderTarget.reset(new TextureRenderTarget11( std::move(rtv), *texture, *srv, *blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, mSamples)); *outRT = mRenderTarget.get(); return angle::Result::Continue; } ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Format = mFormatInfo.dsvFormat; dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; dsvDesc.Flags = 0; d3d11::DepthStencilView dsv; ANGLE_TRY(mRenderer->allocateResource(context11, dsvDesc, texture->get(), &dsv)); mRenderTarget.reset(new TextureRenderTarget11( std::move(dsv), *texture, *srv, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(level), getLevelHeight(level), 1, mSamples)); *outRT = mRenderTarget.get(); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisample::createSRVForSampler(const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage2DMS.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisample::getSwizzleTexture(const gl::Context *context, const TextureHelper11 **outTexture) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_2DMultisample::getSwizzleRenderTarget( const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_2DMultisample::ensureDropStencilTexture(const gl::Context *context, DropStencil *dropStencilOut) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } TextureStorage11_2DMultisampleArray::TextureStorage11_2DMultisampleArray(Renderer11 *renderer, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, int levels, int samples, bool fixedSampleLocations) : TextureStorage11ImmutableBase( renderer, GetTextureBindFlags(internalformat, renderer->getRenderer11DeviceCaps(), true), GetTextureMiscFlags(internalformat, renderer->getRenderer11DeviceCaps(), true, levels), internalformat), mTexture() { // There are no multisampled compressed formats, so there's no need to adjust texture size // according to block size. ASSERT(d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat).blockWidth <= 1); ASSERT(d3d11::GetDXGIFormatSizeInfo(mFormatInfo.texFormat).blockHeight <= 1); mMipLevels = 1; mTextureWidth = width; mTextureHeight = height; mTextureDepth = depth; mSamples = samples; mFixedSampleLocations = fixedSampleLocations; } angle::Result TextureStorage11_2DMultisampleArray::onDestroy(const gl::Context *context) { return angle::Result::Continue; } TextureStorage11_2DMultisampleArray::~TextureStorage11_2DMultisampleArray() {} angle::Result TextureStorage11_2DMultisampleArray::copyToStorage(const gl::Context *context, TextureStorage *destStorage) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_2DMultisampleArray::getResource(const gl::Context *context, const TextureHelper11 **outResource) { ANGLE_TRY(ensureTextureExists(context, 1)); *outResource = &mTexture; return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisampleArray::ensureTextureExists(const gl::Context *context, int mipLevels) { // For multisampled textures, mipLevels always equals 1. ASSERT(mipLevels == 1); // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation if (!mTexture.valid() && mTextureWidth > 0 && mTextureHeight > 0) { D3D11_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(desc)); desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mipLevels; desc.ArraySize = mTextureDepth; desc.Format = mFormatInfo.texFormat; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = getBindFlags() & ~D3D11_BIND_UNORDERED_ACCESS; desc.CPUAccessFlags = 0; desc.MiscFlags = getMiscFlags(); const gl::TextureCaps &textureCaps = mRenderer->getNativeTextureCaps().get(mFormatInfo.internalFormat); GLuint supportedSamples = textureCaps.getNearestSamples(mSamples); desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; desc.SampleDesc.Quality = mRenderer->getSampleDescQuality(supportedSamples); ANGLE_TRY(mRenderer->allocateTexture(GetImplAs(context), desc, mFormatInfo, &mTexture)); mTexture.setDebugName("TexStorage2DMSArray.Texture"); } return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisampleArray::findRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) const { ASSERT(index.hasLayer()); const int mipLevel = index.getLevelIndex(); ASSERT(mipLevel == 0); const int layer = index.getLayerIndex(); const int numLayers = index.getLayerCount(); ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); TextureStorage11_2DArray::LevelLayerRangeKey key(mipLevel, layer, numLayers); if (mRenderTargets.find(key) == mRenderTargets.end()) { ASSERT(outRT); *outRT = nullptr; return angle::Result::Continue; } ASSERT(outRT); *outRT = mRenderTargets.at(key).get(); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisampleArray::createRenderTargetSRV( const gl::Context *context, const TextureHelper11 &texture, const gl::ImageIndex &index, DXGI_FORMAT resourceFormat, d3d11::SharedSRV *srv) const { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = resourceFormat; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; srvDesc.Texture2DMSArray.FirstArraySlice = index.getLayerIndex(); srvDesc.Texture2DMSArray.ArraySize = index.getLayerCount(); ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), srv)); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisampleArray::getRenderTarget(const gl::Context *context, const gl::ImageIndex &index, GLsizei samples, RenderTargetD3D **outRT) { ASSERT(index.hasLayer()); const int mipLevel = index.getLevelIndex(); ASSERT(mipLevel == 0); const int layer = index.getLayerIndex(); const int numLayers = index.getLayerCount(); ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); TextureStorage11_2DArray::LevelLayerRangeKey key(mipLevel, layer, numLayers); if (mRenderTargets.find(key) == mRenderTargets.end()) { const TextureHelper11 *texture = nullptr; ANGLE_TRY(getResource(context, &texture)); d3d11::SharedSRV srv; ANGLE_TRY(createRenderTargetSRV(context, *texture, index, mFormatInfo.srvFormat, &srv)); d3d11::SharedSRV blitSRV; if (mFormatInfo.blitSRVFormat != mFormatInfo.srvFormat) { ANGLE_TRY(createRenderTargetSRV(context, *texture, index, mFormatInfo.blitSRVFormat, &blitSRV)); } else { blitSRV = srv.makeCopy(); } srv.setDebugName("TexStorage2DMSArray.RenderTargetSRV"); if (mFormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = mFormatInfo.rtvFormat; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; rtvDesc.Texture2DMSArray.FirstArraySlice = layer; rtvDesc.Texture2DMSArray.ArraySize = numLayers; d3d11::RenderTargetView rtv; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), rtvDesc, texture->get(), &rtv)); rtv.setDebugName("TexStorage2DMSArray.RenderTargetRTV"); mRenderTargets[key].reset(new TextureRenderTarget11( std::move(rtv), *texture, srv, blitSRV, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, mSamples)); } else { ASSERT(mFormatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Format = mFormatInfo.dsvFormat; dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; dsvDesc.Texture2DMSArray.FirstArraySlice = layer; dsvDesc.Texture2DMSArray.ArraySize = numLayers; dsvDesc.Flags = 0; d3d11::DepthStencilView dsv; ANGLE_TRY(mRenderer->allocateResource(GetImplAs(context), dsvDesc, texture->get(), &dsv)); dsv.setDebugName("TexStorage2DMSArray.RenderTargetDSV"); mRenderTargets[key].reset(new TextureRenderTarget11( std::move(dsv), *texture, srv, mFormatInfo.internalFormat, getFormatSet(), getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, mSamples)); } } ASSERT(outRT); *outRT = mRenderTargets[key].get(); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisampleArray::createSRVForSampler( const gl::Context *context, int baseLevel, int mipLevels, DXGI_FORMAT format, const TextureHelper11 &texture, d3d11::SharedSRV *outSRV) { ASSERT(outSRV); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; srvDesc.Texture2DMSArray.FirstArraySlice = 0; srvDesc.Texture2DMSArray.ArraySize = mTextureDepth; ANGLE_TRY( mRenderer->allocateResource(GetImplAs(context), srvDesc, texture.get(), outSRV)); outSRV->setDebugName("TexStorage2DMSArray.SRV"); return angle::Result::Continue; } angle::Result TextureStorage11_2DMultisampleArray::getSwizzleTexture( const gl::Context *context, const TextureHelper11 **outTexture) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_2DMultisampleArray::getSwizzleRenderTarget( const gl::Context *context, int mipLevel, const d3d11::RenderTargetView **outRTV) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } angle::Result TextureStorage11_2DMultisampleArray::ensureDropStencilTexture( const gl::Context *context, DropStencil *dropStencilOut) { ANGLE_HR_UNREACHABLE(GetImplAs(context)); return angle::Result::Stop; } } // namespace rx