Commit 32334afe by Gregoire Payen de La Garanderie Committed by Jamie Madill

Implement the copy from a 3D texture to Image11.

Fixes the generation of 3D texture mipmaps. BUG=angle:915 Change-Id: Icc0c91099f60713d511ebe1a2248a21b63efddaa Reviewed-on: https://chromium-review.googlesource.com/244720Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarGregoire Payen de La Garanderie <Gregory.Payen@imgtec.com>
parent b6e07a6a
......@@ -55,7 +55,7 @@ class Image
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0;
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0;
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0;
protected:
......
......@@ -60,7 +60,7 @@ class ImageD3D
virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); };
virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0;
gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source);
......
......@@ -402,7 +402,7 @@ gl::Error TextureD3D::generateMipmaps()
gl::ImageIndex srcIndex = getImageIndex(0, layer);
ImageD3D *image = getImage(srcIndex);
gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
gl::Box area(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
gl::Offset offset(0, 0, 0);
gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
if (error.isError())
......
......@@ -523,7 +523,7 @@ gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &s
BlitParameters parameters = { 0 };
parameters.mDestinationFormat = destFormat;
parameters.mSignedInteger = (internalFormatInfo.componentType == GL_INT);
parameters.m3DBlit = sourceArea.depth > 1;
parameters.m3DBlit = sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D;
BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters);
if (i == mBlitShaderMap.end())
......
......@@ -317,22 +317,18 @@ gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourc
RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
ASSERT(sourceRenderTarget->getTexture());
ID3D11Resource *resource = sourceRenderTarget->getTexture();
UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();
ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceRenderTarget->getTexture());
if (!sourceTexture2D)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source RenderTarget.");
}
gl::Error error = copy(destOffset, sourceArea, sourceTexture2D, subresourceIndex);
gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
gl::Error error = copy(destOffset, sourceBox, resource, subresourceIndex);
SafeRelease(sourceTexture2D);
SafeRelease(resource);
return error;
}
gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
{
TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source);
......@@ -344,26 +340,52 @@ gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourc
return error;
}
ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource);
if (!sourceTexture2D)
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source TextureStorage.");
}
error = copy(destOffset, sourceArea, sourceTexture2D, subresourceIndex);
error = copy(destOffset, sourceArea, resource, subresourceIndex);
SafeRelease(sourceTexture2D);
SafeRelease(resource);
return error;
}
gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource)
gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource)
{
D3D11_TEXTURE2D_DESC textureDesc;
source->GetDesc(&textureDesc);
D3D11_RESOURCE_DIMENSION dim;
source->GetType(&dim);
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
gl::Extents extents;
UINT sampleCount = 0;
ID3D11Texture2D *source2D = NULL;
if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D)
{
D3D11_TEXTURE2D_DESC textureDesc2D;
source2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(source);
ASSERT(source2D);
source2D->GetDesc(&textureDesc2D);
format = textureDesc2D.Format;
extents = gl::Extents(textureDesc2D.Width, textureDesc2D.Height, 1);
sampleCount = textureDesc2D.SampleDesc.Count;
}
else if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
{
D3D11_TEXTURE3D_DESC textureDesc3D;
ID3D11Texture3D *source3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(source);
ASSERT(source3D);
source3D->GetDesc(&textureDesc3D);
format = textureDesc3D.Format;
extents = gl::Extents(textureDesc3D.Width, textureDesc3D.Height, textureDesc3D.Depth);
sampleCount = 1;
}
else
{
UNREACHABLE();
}
if (textureDesc.Format == mDXGIFormat)
if (format == mDXGIFormat)
{
// No conversion needed-- use copyback fastpath
ID3D11Resource *stagingTexture = NULL;
......@@ -379,15 +401,18 @@ gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourc
UINT subresourceAfterResolve = sourceSubResource;
ID3D11Texture2D* srcTex = NULL;
if (textureDesc.SampleDesc.Count > 1)
ID3D11Resource *srcTex = NULL;
bool needResolve = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D && sampleCount > 1);
if (needResolve)
{
D3D11_TEXTURE2D_DESC resolveDesc;
resolveDesc.Width = textureDesc.Width;
resolveDesc.Height = textureDesc.Height;
resolveDesc.Width = extents.width;
resolveDesc.Height = extents.height;
resolveDesc.MipLevels = 1;
resolveDesc.ArraySize = 1;
resolveDesc.Format = textureDesc.Format;
resolveDesc.Format = format;
resolveDesc.SampleDesc.Count = 1;
resolveDesc.SampleDesc.Quality = 0;
resolveDesc.Usage = D3D11_USAGE_DEFAULT;
......@@ -395,13 +420,15 @@ gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourc
resolveDesc.CPUAccessFlags = 0;
resolveDesc.MiscFlags = 0;
HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
ID3D11Texture2D *srcTex2D = NULL;
HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
}
srcTex = srcTex2D;
deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format);
deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, format);
subresourceAfterResolve = 0;
}
else
......@@ -414,13 +441,13 @@ gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourc
srcBox.right = sourceArea.x + sourceArea.width;
srcBox.top = sourceArea.y;
srcBox.bottom = sourceArea.y + sourceArea.height;
srcBox.front = 0;
srcBox.back = 1;
srcBox.front = sourceArea.z;
srcBox.back = sourceArea.z + sourceArea.depth;
deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x, destOffset.y,
destOffset.z, srcTex, subresourceAfterResolve, &srcBox);
if (textureDesc.SampleDesc.Count > 1)
if (needResolve)
{
SafeRelease(srcTex);
}
......@@ -442,7 +469,12 @@ gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourc
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
error = mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
// Currently in ANGLE, the source data may only need to be converted if the source is the current framebuffer
// and OpenGL ES framebuffers must be 2D textures therefore we should not need to convert 3D textures between different formats.
ASSERT(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D);
ASSERT(sourceArea.z == 0 && sourceArea.depth == 1);
gl::Rectangle sourceRect(sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height);
error = mRenderer->readTextureData(source2D, sourceSubResource, sourceRect, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
unmap();
......
......@@ -47,7 +47,7 @@ class Image11 : public ImageD3D
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input);
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source);
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source);
gl::Error recoverFromAssociatedStorage();
......@@ -62,7 +62,7 @@ class Image11 : public ImageD3D
DISALLOW_COPY_AND_ASSIGN(Image11);
gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region);
gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource);
gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource);
gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex);
gl::Error createStagingTexture();
......
......@@ -778,7 +778,7 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source
return gl::Error(GL_NO_ERROR);
}
gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Box &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
{
// Currently unreachable, due to only being used in a D3D11-only workaround
UNIMPLEMENTED();
......
......@@ -48,7 +48,7 @@ class Image9 : public ImageD3D
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input);
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source);
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source);
private:
......
......@@ -287,6 +287,49 @@ protected:
glUniform2f(mTextureArrayScaleUniformLocation, 1.0f, 1.0f);
glUseProgram(0);
ASSERT_GL_NO_ERROR();
glGenTextures(1, &mTexture3D);
ASSERT_GL_NO_ERROR();
const std::string fragmentShaderSource3D = SHADER_SOURCE
( #version 300 es\n
precision highp float;
uniform sampler3D tex;
uniform float slice;
uniform float lod;
in vec2 texcoord;
out vec4 out_FragColor;
void main()
{
out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
}
);
m3DProgram = CompileProgram(vertexShaderSource, fragmentShaderSource3D);
if (m3DProgram == 0)
{
FAIL() << "shader compilation failed.";
}
mTexture3DUniformLocation = glGetUniformLocation(m3DProgram, "tex");
ASSERT_NE(-1, mTexture3DUniformLocation);
mTexture3DScaleUniformLocation = glGetUniformLocation(m3DProgram, "textureScale");
ASSERT_NE(-1, mTexture3DScaleUniformLocation);
mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
ASSERT_NE(-1, mTexture3DSliceUniformLocation);
mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
ASSERT_NE(-1, mTexture3DLODUniformLocation);
glUseProgram(m3DProgram);
glUniform2f(mTexture3DScaleUniformLocation, 1.0f, 1.0f);
glUniform1f(mTexture3DLODUniformLocation, 0);
glUseProgram(0);
ASSERT_GL_NO_ERROR();
}
virtual void TearDown()
......@@ -294,15 +337,25 @@ protected:
glDeleteTextures(1, &mTextureArray);
glDeleteProgram(mArrayProgram);
glDeleteTextures(1, &mTexture3D);
glDeleteProgram(m3DProgram);
ANGLETest::TearDown();
}
GLuint mTextureArray;
GLuint mTexture3D;
GLuint mArrayProgram;
GLint mTextureArrayUniformLocation;
GLint mTextureArrayScaleUniformLocation;
GLint mTextureArraySliceUniformLocation;
GLuint m3DProgram;
GLint mTexture3DUniformLocation;
GLint mTexture3DScaleUniformLocation;
GLint mTexture3DSliceUniformLocation;
GLint mTexture3DLODUniformLocation;
};
// This test uses init data for the first three levels of the texture. It passes the level 0 data in, then renders, then level 1, then renders, etc.
......@@ -777,4 +830,85 @@ TYPED_TEST(MipmapTestES3, DISABLED_MipmapsForTextureArray)
drawQuad(mArrayProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 0, 0, 255, 255);
}
\ No newline at end of file
}
// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
// Then tests if the mipmaps are rendered correctly for all two layers.
TYPED_TEST(MipmapTestES3, MipmapsForTexture3D)
{
int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
// Fill the first layer with red
std::vector<GLubyte> pixels(4 * 16 * 16);
for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
{
pixels[pixelId * 4 + 0] = 255;
pixels[pixelId * 4 + 1] = 0;
pixels[pixelId * 4 + 2] = 0;
pixels[pixelId * 4 + 3] = 255;
}
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
// Fill the second layer with green
for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
{
pixels[pixelId * 4 + 0] = 0;
pixels[pixelId * 4 + 1] = 255;
pixels[pixelId * 4 + 2] = 0;
pixels[pixelId * 4 + 3] = 255;
}
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
EXPECT_GL_NO_ERROR();
glGenerateMipmap(GL_TEXTURE_3D);
EXPECT_GL_NO_ERROR();
glUseProgram(m3DProgram);
glUniform1i(mTexture3DUniformLocation, 0);
EXPECT_GL_NO_ERROR();
// Mipmap level 0
// Draw the first slice
glUseProgram(m3DProgram);
glUniform1f(mTexture3DLODUniformLocation, 0.);
glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
// Draw the second slice
glUseProgram(m3DProgram);
glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
// Mipmap level 1
// The second mipmap should only have one slice.
glUseProgram(m3DProgram);
glUniform1f(mTexture3DLODUniformLocation, 1.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 127, 127, 0, 255);
glUseProgram(m3DProgram);
glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 127, 127, 0, 255);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment