Improve D3D11 FL9_3 zero-LOD workaround (e.g. TextureCubes)
D3D11 Feature Level 9_3 can't disable mipmaps on a mipmapped
texture, and sample from level zero of it. A previous commit
added a workaround for this in ANGLE to Texture2Ds. This
commit fixes some minor issues in that commit, and extends
the workaround to apply to TextureCubes too.
Change-Id: Ic97321af6f8bbf7ad5d96e58655c342db3978a6a
Reviewed-on: https://chromium-review.googlesource.com/241944
Tested-by: Austin Kinross <aukinros@microsoft.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index 13548ee..d80b4d1 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -135,7 +135,7 @@
virtual gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) = 0;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0;
virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) = 0;
- virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0;
+ virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) = 0;
virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0;
virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0;
diff --git a/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/libANGLE/renderer/d3d/TextureD3D.cpp
index 2173462..7b7c822 100644
--- a/src/libANGLE/renderer/d3d/TextureD3D.cpp
+++ b/src/libANGLE/renderer/d3d/TextureD3D.cpp
@@ -352,9 +352,6 @@
return gl::Error(GL_NO_ERROR); // no-op
}
- // Set up proper mipmap chain in our Image array.
- initMipmapsImages();
-
if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
// Switch to using the mipmapped texture.
@@ -365,6 +362,9 @@
}
}
+ // Set up proper mipmap chain in our Image array.
+ initMipmapsImages();
+
// We know that all layers have the same dimension, for the texture to be complete
GLint layerCount = static_cast<GLint>(getLayerCount(0));
@@ -728,7 +728,9 @@
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
gl::Offset destOffset(0, 0, 0);
- if (!canCreateRenderTargetForImage(index))
+ // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
+ // so we should use the non-rendering copy path.
+ if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
if (error.isError())
@@ -771,7 +773,9 @@
gl::ImageIndex index = gl::ImageIndex::Make2D(level);
- if (!canCreateRenderTargetForImage(index))
+ // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
+ // so we should use the non-rendering copy path.
+ if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{
gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
if (error.isError())
@@ -1030,11 +1034,9 @@
// If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with.
// Otherwise, it should use the level-zero-only texture.
hintLevelZeroOnly = true;
- int level = 1;
- while (hintLevelZeroOnly && level < levels)
+ for (int level = 1; level < levels && hintLevelZeroOnly; level++)
{
hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
- level += 1;
}
}
@@ -1381,7 +1383,8 @@
// TODO(geofflang): Verify storage creation had no errors
bool renderTarget = IsRenderTargetUsage(mUsage);
- TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels);
+
+ TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false);
gl::Error error = setCompleteTexStorage(storage);
if (error.isError())
@@ -1524,8 +1527,23 @@
// use existing storage level count, when previously specified by TexStorage*D
GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
+ bool hintLevelZeroOnly = false;
+ if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
+ {
+ // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the mipped texture to begin with.
+ // Otherwise, it should use the level-zero-only texture.
+ hintLevelZeroOnly = true;
+ for (int faceIndex = 0; faceIndex < 6 && hintLevelZeroOnly; faceIndex++)
+ {
+ for (int level = 1; level < levels && hintLevelZeroOnly; level++)
+ {
+ hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && isFaceLevelComplete(faceIndex, level));
+ }
+ }
+ }
+
// TODO (geofflang): detect if storage creation succeeded
- *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
+ *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly);
return gl::Error(GL_NO_ERROR);
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 87786a4..c472707 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -2829,9 +2829,9 @@
return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, hintLevelZeroOnly);
}
-TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels)
+TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
{
- return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels);
+ return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly);
}
TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels)
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 4deda39..94e62ca 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -155,7 +155,7 @@
gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain);
virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly);
- virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels);
+ virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels);
virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels);
diff --git a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
index 7d1261c..58d756f 100644
--- a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -426,8 +426,28 @@
unsigned int srcSubresource = getSubresourceIndex(index);
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox should be NULL.
+ D3D11_BOX srcBox;
+ D3D11_BOX *pSrcBox = NULL;
+ if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ {
+ // 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(d3d11::GetDXGIFormatInfo(mTextureFormat).depthBits == 0);
+ ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).stencilBits == 0);
+ 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;
+ }
+
context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z,
- srcTexture, srcSubresource, NULL);
+ srcTexture, srcSubresource, pSrcBox);
return gl::Error(GL_NO_ERROR);
}
@@ -662,7 +682,7 @@
mTextureHeight = height;
mTextureDepth = 1;
- if (hintLevelZeroOnly)
+ if (hintLevelZeroOnly && levels > 1)
{
//The LevelZeroOnly hint should only be true if the zero max LOD workaround is active.
ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround);
@@ -787,7 +807,7 @@
gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture)
{
- if (useLevelZeroTexture)
+ if (useLevelZeroTexture && mMipLevels > 1)
{
if (!mUseLevelZeroTexture && mTexture)
{
@@ -798,8 +818,8 @@
}
// Pull data back from the mipped texture if necessary.
- ASSERT(mTexture);
- ID3D11DeviceContext* context = mRenderer->getDeviceContext();
+ ASSERT(mLevelZeroTexture);
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
context->CopySubresourceRegion(mLevelZeroTexture, 0, 0, 0, 0, mTexture, 0, NULL);
}
@@ -817,7 +837,7 @@
// Pull data back from the level zero texture if necessary.
ASSERT(mTexture);
- ID3D11DeviceContext* context = mRenderer->getDeviceContext();
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
context->CopySubresourceRegion(mTexture, 0, 0, 0, 0, mLevelZeroTexture, 0, NULL);
}
@@ -906,7 +926,7 @@
gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource)
{
- if (mUseLevelZeroTexture)
+ if (mUseLevelZeroTexture && mMipLevels > 1)
{
gl::Error error = ensureTextureExists(1);
if (error.isError())
@@ -947,7 +967,9 @@
gl::Error TextureStorage11_2D::ensureTextureExists(int mipLevels)
{
- ID3D11Texture2D** outputTexture = (mipLevels == 1 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) ? &mLevelZeroTexture : &mTexture;
+ // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture.
+ bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false;
+ ID3D11Texture2D **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
@@ -1126,7 +1148,7 @@
ASSERT(baseLevel == 0);
// This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture.
- if (mipLevels == 1)
+ if (mipLevels == 1 && mMipLevels > 1)
{
// We must use a SRV on the level-zero-only texture.
ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture);
@@ -1220,7 +1242,7 @@
return gl::Error(GL_NO_ERROR);
}
-TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels)
+TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
: TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget))
{
mTexture = NULL;
@@ -1236,6 +1258,14 @@
}
}
+ mLevelZeroTexture = NULL;
+ mUseLevelZeroTexture = false;
+
+ for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++)
+ {
+ mLevelZeroRenderTarget[face] = NULL;
+ }
+
mInternalFormat = internalformat;
const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel());
@@ -1256,6 +1286,13 @@
mTextureHeight = size;
mTextureDepth = 1;
+ if (hintLevelZeroOnly && levels > 1)
+ {
+ //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active.
+ ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround);
+ mUseLevelZeroTexture = true;
+ }
+
initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT);
}
@@ -1281,6 +1318,12 @@
SafeRelease(mTexture);
SafeRelease(mSwizzleTexture);
+ SafeRelease(mLevelZeroTexture);
+
+ for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++)
+ {
+ SafeDelete(mLevelZeroRenderTarget[face]);
+ }
for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
{
@@ -1298,6 +1341,147 @@
return static_cast<TextureStorage11_Cube*>(storage);
}
+UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const
+{
+ if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && index.mipIndex == 0)
+ {
+ UINT arraySlice = static_cast<UINT>(index.hasLayer() ? index.layerIndex : 0);
+ UINT subresource = D3D11CalcSubresource(0, arraySlice, 1);
+ ASSERT(subresource != std::numeric_limits<UINT>::max());
+ return subresource;
+ }
+ else
+ {
+ UINT mipSlice = static_cast<UINT>(index.mipIndex + mTopLevel);
+ UINT arraySlice = static_cast<UINT>(index.hasLayer() ? index.layerIndex : 0);
+ UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels);
+ ASSERT(subresource != std::numeric_limits<UINT>::max());
+ return subresource;
+ }
+}
+
+gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage)
+{
+ ASSERT(destStorage);
+
+ TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(destStorage);
+
+ if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
+ {
+ ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
+
+ // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage.
+ if (mTexture)
+ {
+ gl::Error error = dest11->useLevelZeroWorkaroundTexture(false);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11Resource *destResource = NULL;
+ error = dest11->getResource(&destResource);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ immediateContext->CopyResource(destResource, mTexture);
+ }
+
+ if (mLevelZeroTexture)
+ {
+ gl::Error error = dest11->useLevelZeroWorkaroundTexture(true);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11Resource *destResource = NULL;
+ error = dest11->getResource(&destResource);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ immediateContext->CopyResource(destResource, mLevelZeroTexture);
+ }
+ }
+ else
+ {
+ ID3D11Resource *sourceResouce = NULL;
+ gl::Error error = getResource(&sourceResouce);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11Resource *destResource = NULL;
+ error = dest11->getResource(&destResource);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
+ immediateContext->CopyResource(destResource, sourceResouce);
+ }
+
+ dest11->invalidateSwizzleCache();
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture)
+{
+ if (useLevelZeroTexture && mMipLevels > 1)
+ {
+ if (!mUseLevelZeroTexture && mTexture)
+ {
+ gl::Error error = ensureTextureExists(1);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Pull data back from the mipped texture if necessary.
+ ASSERT(mLevelZeroTexture);
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ for (int face = 0; face < 6; face++)
+ {
+ context->CopySubresourceRegion(mLevelZeroTexture, D3D11CalcSubresource(0, face, 1), 0, 0, 0, mTexture, face * mMipLevels, NULL);
+ }
+ }
+
+ mUseLevelZeroTexture = true;
+ }
+ else
+ {
+ if (mUseLevelZeroTexture && mLevelZeroTexture)
+ {
+ gl::Error error = ensureTextureExists(mMipLevels);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Pull data back from the level zero texture if necessary.
+ ASSERT(mTexture);
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ for (int face = 0; face < 6; face++)
+ {
+ context->CopySubresourceRegion(mTexture, D3D11CalcSubresource(0, face, mMipLevels), 0, 0, 0, mLevelZeroTexture, face, NULL);
+ }
+ }
+
+ mUseLevelZeroTexture = false;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index)
{
GLint level = index.mipIndex;
@@ -1396,9 +1580,54 @@
gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource)
{
+ if (mUseLevelZeroTexture && mMipLevels > 1)
+ {
+ gl::Error error = ensureTextureExists(1);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outResource = mLevelZeroTexture;
+ return gl::Error(GL_NO_ERROR);
+ }
+ else
+ {
+ gl::Error error = ensureTextureExists(mMipLevels);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outResource = mTexture;
+ return gl::Error(GL_NO_ERROR);
+ }
+}
+
+gl::Error TextureStorage11_Cube::getMippedResource(ID3D11Resource **outResource)
+{
+ // This shouldn't be called unless the zero max LOD workaround is active.
+ ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround);
+
+ gl::Error error = ensureTextureExists(mMipLevels);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ *outResource = mTexture;
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error TextureStorage11_Cube::ensureTextureExists(int mipLevels)
+{
+ // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture.
+ bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false;
+ ID3D11Texture2D **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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
+ if (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0)
{
ASSERT(mMipLevels > 0);
@@ -1407,7 +1636,7 @@
D3D11_TEXTURE2D_DESC desc;
desc.Width = mTextureWidth;
desc.Height = mTextureHeight;
- desc.MipLevels = mMipLevels;
+ desc.MipLevels = mipLevels;
desc.ArraySize = CUBE_FACE_COUNT;
desc.Format = mTextureFormat;
desc.SampleDesc.Count = 1;
@@ -1417,7 +1646,7 @@
desc.CPUAccessFlags = 0;
desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
- HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture);
+ HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture);
// this can happen from windows TDR
if (d3d11::isDeviceLostError(result))
@@ -1432,7 +1661,6 @@
}
}
- *outResource = mTexture;
return gl::Error(GL_NO_ERROR);
}
@@ -1456,14 +1684,53 @@
return error;
}
+ if (mUseLevelZeroTexture)
+ {
+ if (!mLevelZeroRenderTarget[faceIndex])
+ {
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtvDesc.Format = mRenderTargetFormat;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.MipSlice = mTopLevel + level;
+ rtvDesc.Texture2DArray.FirstArraySlice = faceIndex;
+ rtvDesc.Texture2DArray.ArraySize = 1;
+
+ ID3D11RenderTargetView *rtv;
+ result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result);
+ }
+ ASSERT(SUCCEEDED(result));
+
+ mLevelZeroRenderTarget[faceIndex] = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0);
+
+ // RenderTarget will take ownership of these resources
+ SafeRelease(rtv);
+ }
+
+ ASSERT(outRT);
+ *outRT = mLevelZeroRenderTarget[faceIndex];
+ return gl::Error(GL_NO_ERROR);
+ }
+
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = mShaderResourceFormat;
- srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube
srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level;
srvDesc.Texture2DArray.MipLevels = 1;
srvDesc.Texture2DArray.FirstArraySlice = faceIndex;
srvDesc.Texture2DArray.ArraySize = 1;
+ if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
+ }
+ else
+ {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube
+ }
+
ID3D11ShaderResourceView *srv;
result = device->CreateShaderResourceView(texture, &srvDesc, &srv);
@@ -1560,8 +1827,30 @@
srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel;
}
+ ID3D11Resource *srvTexture = texture;
+
+ if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
+ {
+ 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.
+ ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture);
+ srvTexture = mLevelZeroTexture;
+ }
+ else
+ {
+ ASSERT(mipLevels == static_cast<int>(mMipLevels));
+ ASSERT(mTexture != NULL && texture == mTexture);
+ srvTexture = mTexture;
+ }
+ }
+
ID3D11Device *device = mRenderer->getDevice();
- HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV);
+ HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV);
ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result));
if (FAILED(result))
diff --git a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
index 97f0d76..4b3760b 100644
--- a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
@@ -50,7 +50,7 @@
virtual bool isRenderTarget() const;
virtual bool isManaged() const;
virtual int getLevelCount() const;
- UINT getSubresourceIndex(const gl::ImageIndex &index) const;
+ virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const;
gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
void invalidateSwizzleCacheLevel(int mipLevel);
@@ -201,23 +201,32 @@
class TextureStorage11_Cube : public TextureStorage11
{
public:
- TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels);
+ TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual ~TextureStorage11_Cube();
static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage);
+ virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const;
+
virtual gl::Error getResource(ID3D11Resource **outResource);
+ virtual gl::Error getMippedResource(ID3D11Resource **outResource);
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
+ virtual gl::Error copyToStorage(TextureStorage *destStorage);
+
virtual void associateImage(Image11* image, const gl::ImageIndex &index);
virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage);
virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage);
virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage);
+ virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture);
+
protected:
virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture);
virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV);
+ gl::Error ensureTextureExists(int mipLevels);
+
private:
DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube);
@@ -229,6 +238,11 @@
ID3D11Texture2D *mTexture;
RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+ // Level-zero workaround members. See TextureStorage11_2D's workaround members for a description.
+ ID3D11Texture2D *mLevelZeroTexture;
+ RenderTarget11 *mLevelZeroRenderTarget[CUBE_FACE_COUNT];
+ bool mUseLevelZeroTexture;
+
ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 1fc9874..7125e2b 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -2832,9 +2832,9 @@
return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels);
}
-TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels)
+TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
{
- return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels);
+ return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly);
}
TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels)
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index 82e2e68..5d8c698 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -164,7 +164,7 @@
gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain);
virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly);
- virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels);
+ virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels);
virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels);
diff --git a/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
index b33645b..139cb3e 100644
--- a/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp
@@ -286,7 +286,7 @@
return gl::Error(GL_NO_ERROR);
}
-TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels)
+TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly)
: TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget))
{
mTexture = NULL;
diff --git a/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
index 0b5d9cc..49667e1 100644
--- a/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h
@@ -88,7 +88,7 @@
class TextureStorage9_Cube : public TextureStorage9
{
public:
- TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels);
+ TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly);
virtual ~TextureStorage9_Cube();
static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage);