Commit 9aca059f by Jamie Madill

Enable TexSubImage workaround on D3D11.

This workaround uses UpdateResource instead of staging buffers for texture data updates. It improves performance for highly dynamic textures, especially in some benchmarks, eg the turbulenz particle demo. Re-land, with fix to the issue with glGenerateMipmaps. BUG=angle:729 BUG=365078 Change-Id: I4c9398e0645176c296bf95e35eab97a44eae4319 Reviewed-on: https://chromium-review.googlesource.com/221493Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 6b51c1a0
......@@ -20,12 +20,14 @@ namespace gl
{
class Framebuffer;
struct Rectangle;
struct ImageIndex;
}
namespace rx
{
class Renderer;
class RenderTarget;
class TextureStorage;
class Image
{
......@@ -54,6 +56,8 @@ class Image
void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, gl::Framebuffer *source);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) = 0;
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0;
protected:
GLsizei mWidth;
......
......@@ -26,10 +26,12 @@ enum D3DWorkaroundType
struct Workarounds
{
Workarounds()
: mrtPerfWorkaround(false)
: mrtPerfWorkaround(false),
setDataFasterThanImageUpload(false)
{}
bool mrtPerfWorkaround;
bool setDataFasterThanImageUpload;
};
}
......
......@@ -102,7 +102,7 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type,
// We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
// From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
const void *pixelData = pixels;
const uint8_t *pixelData = NULL;
if (unpack.pixelBuffer.id() != 0)
{
......@@ -112,12 +112,30 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type,
// TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
// This functionality should be moved into renderer and the getData method of BufferImpl removed.
const void *bufferData = pixelBuffer->getImplementation()->getData();
pixelData = static_cast<const unsigned char *>(bufferData) + offset;
pixelData = static_cast<const uint8_t *>(bufferData) + offset;
}
else
{
pixelData = static_cast<const uint8_t *>(pixels);
}
if (pixelData != NULL)
{
gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
gl::Error error(GL_NO_ERROR);
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
// TODO(jmadill): Handle compressed internal formats
if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
{
gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData);
}
else
{
error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
}
if (error.isError())
{
return error;
......@@ -132,7 +150,7 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type,
gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
{
const void *pixelData = pixels;
const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
// CPU readback & copy where direct GPU copy is not supported
if (unpack.pixelBuffer.id() != 0)
......@@ -142,7 +160,7 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
// TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
// This functionality should be moved into renderer and the getData method of BufferImpl removed.
const void *bufferData = pixelBuffer->getImplementation()->getData();
pixelData = static_cast<const unsigned char *>(bufferData) + offset;
pixelData = static_cast<const uint8_t *>(bufferData)+offset;
}
if (pixelData != NULL)
......@@ -150,6 +168,16 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
Image *image = getImage(index);
ASSERT(image);
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
// TODO(jmadill): Handle compressed internal formats
if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
{
return mTexStorage->setData(index, region, image->getInternalFormat(),
type, unpack, pixelData);
}
gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
type, pixelData);
if (error.isError())
......@@ -157,7 +185,6 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
return error;
}
gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
error = commitRegion(index, region);
if (error.isError())
{
......@@ -263,17 +290,43 @@ Image *TextureD3D::getBaseLevelImage() const
void TextureD3D::generateMipmaps()
{
// Set up proper image sizes.
GLint mipCount = mipLevels();
if (mipCount == 1)
{
return; // no-op
}
// 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));
GLint mipCount = mipLevels();
// The following will create and initialize the storage, or update it if it exists
TextureStorage *storage = getNativeTexture();
// When making mipmaps with the setData workaround enabled, the texture storage has
// the image data already. For non-render-target storage, we have to pull it out into
// an image layer.
if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
{
if (!mTexStorage->isRenderTarget())
{
// Copy from the storage mip 0 to Image mip 0
for (GLint layer = 0; layer < layerCount; ++layer)
{
gl::ImageIndex srcIndex = getImageIndex(0, layer);
Image *image = getImage(srcIndex);
gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
image->copy(0, 0, 0, area, srcIndex, mTexStorage);
}
}
else
{
updateStorage();
}
}
bool renderableStorage = (storage && storage->isRenderTarget());
bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
for (GLint layer = 0; layer < layerCount; ++layer)
{
......@@ -287,7 +340,7 @@ void TextureD3D::generateMipmaps()
if (renderableStorage)
{
// GPU-side mipmapping
storage->generateMipmap(sourceIndex, destIndex);
mTexStorage->generateMipmap(sourceIndex, destIndex);
}
else
{
......
......@@ -323,27 +323,54 @@ gl::Error Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffse
void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
{
RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(source);
ASSERT(renderTarget->getTexture());
RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
ASSERT(sourceRenderTarget->getTexture());
ID3D11Texture2D *colorBufferTexture = d3d11::DynamicCastComObject<ID3D11Texture2D>(renderTarget->getTexture());
unsigned int subresourceIndex = renderTarget->getSubresourceIndex();
UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();
ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceRenderTarget->getTexture());
if (!colorBufferTexture)
if (!sourceTexture2D)
{
// Error already generated
return;
}
if (source->getActualFormat() == mActualFormat)
copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
SafeRelease(sourceTexture2D);
}
void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
{
TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source);
UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex);
ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceStorage11->getResource());
if (!sourceTexture2D)
{
// No conversion needed-- use copyback fastpath
D3D11_TEXTURE2D_DESC textureDesc;
colorBufferTexture->GetDesc(&textureDesc);
// Error already generated
return;
}
copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
SafeRelease(sourceTexture2D);
}
void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource)
{
D3D11_TEXTURE2D_DESC textureDesc;
source->GetDesc(&textureDesc);
if (textureDesc.Format == mDXGIFormat)
{
// No conversion needed-- use copyback fastpath
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
UINT subresourceAfterResolve = sourceSubResource;
ID3D11Texture2D* srcTex = NULL;
if (textureDesc.SampleDesc.Count > 1)
{
......@@ -367,13 +394,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan
return;
}
deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
subresourceIndex = 0;
deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format);
subresourceAfterResolve = 0;
}
else
{
srcTex = colorBufferTexture;
srcTex->AddRef();
srcTex = source;
}
D3D11_BOX srcBox;
......@@ -384,10 +410,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan
srcBox.front = 0;
srcBox.back = 1;
deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox);
deviceContext->CopySubresourceRegion(getStagingTexture(), 0, xoffset, yoffset, zoffset, srcTex, subresourceAfterResolve, &srcBox);
SafeRelease(srcTex);
SafeRelease(colorBufferTexture);
if (textureDesc.SampleDesc.Count > 1)
{
SafeRelease(srcTex);
}
}
else
{
......@@ -406,10 +434,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
mRenderer->readTextureData(colorBufferTexture, subresourceIndex, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
unmap();
}
mDirty = true;
}
ID3D11Resource *Image11::getStagingTexture()
......
......@@ -53,6 +53,8 @@ class Image11 : public ImageD3D
const void *input);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source);
bool recoverFromAssociatedStorage();
bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
......@@ -66,6 +68,7 @@ class Image11 : public ImageD3D
DISALLOW_COPY_AND_ASSIGN(Image11);
gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region);
void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource);
ID3D11Resource *getStagingTexture();
unsigned int getStagingSubresource();
......
......@@ -1076,6 +1076,7 @@ Workarounds GenerateWorkarounds()
{
Workarounds workarounds;
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = true;
return workarounds;
}
......
......@@ -717,4 +717,10 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectang
mDirty = true;
}
void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
{
// Currently unreachable, due to only being used in a D3D11-only workaround
UNIMPLEMENTED();
}
}
......@@ -55,6 +55,8 @@ class Image9 : public ImageD3D
const void *input);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source);
private:
DISALLOW_COPY_AND_ASSIGN(Image9);
......
......@@ -543,6 +543,7 @@ Workarounds GenerateWorkarounds()
{
Workarounds workarounds;
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = false;
return workarounds;
}
......
......@@ -40,9 +40,11 @@ protected:
attribute vec4 position;
varying vec2 texcoord;
uniform vec2 textureScale;
void main()
{
gl_Position = position;
gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
texcoord = (position.xy * 0.5) + 0.5;
}
);
......@@ -81,6 +83,15 @@ protected:
}
mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex");
ASSERT_NE(-1, mTexture2DUniformLocation);
mTextureScaleUniformLocation = glGetUniformLocation(m2DProgram, "textureScale");
ASSERT_NE(-1, mTextureScaleUniformLocation);
glUseProgram(m2DProgram);
glUniform2f(mTextureScaleUniformLocation, 1.0f, 1.0f);
glUseProgram(0);
ASSERT_GL_NO_ERROR();
}
virtual void TearDown()
......@@ -99,6 +110,7 @@ protected:
GLuint m2DProgram;
GLuint mCubeProgram;
GLint mTexture2DUniformLocation;
GLint mTextureScaleUniformLocation;
};
TYPED_TEST(TextureTest, NegativeAPISubImage)
......@@ -152,3 +164,64 @@ TYPED_TEST(TextureTest, CubeMapBug)
drawQuad(mCubeProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
}
// Copy of a test in conformance/textures/texture-mips, to test generate mipmaps
TYPED_TEST(TextureTest, MipmapsTwice)
{
int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
// Fill 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;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
glUseProgram(m2DProgram);
glUniform1i(mTexture2DUniformLocation, 0);
glUniform2f(mTextureScaleUniformLocation, 0.0625f, 0.0625f);
drawQuad(m2DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
// Fill with blue
for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
{
pixels[pixelId * 4 + 0] = 0;
pixels[pixelId * 4 + 1] = 0;
pixels[pixelId * 4 + 2] = 255;
pixels[pixelId * 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
glGenerateMipmap(GL_TEXTURE_2D);
// Fill 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;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
glGenerateMipmap(GL_TEXTURE_2D);
drawQuad(m2DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 0, 255, 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