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 ...@@ -20,12 +20,14 @@ namespace gl
{ {
class Framebuffer; class Framebuffer;
struct Rectangle; struct Rectangle;
struct ImageIndex;
} }
namespace rx namespace rx
{ {
class Renderer; class Renderer;
class RenderTarget; class RenderTarget;
class TextureStorage;
class Image class Image
{ {
...@@ -54,6 +56,8 @@ class Image ...@@ -54,6 +56,8 @@ class Image
void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, gl::Framebuffer *source); 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, RenderTarget *source) = 0;
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0;
protected: protected:
GLsizei mWidth; GLsizei mWidth;
......
...@@ -26,10 +26,12 @@ enum D3DWorkaroundType ...@@ -26,10 +26,12 @@ enum D3DWorkaroundType
struct Workarounds struct Workarounds
{ {
Workarounds() Workarounds()
: mrtPerfWorkaround(false) : mrtPerfWorkaround(false),
setDataFasterThanImageUpload(false)
{} {}
bool mrtPerfWorkaround; bool mrtPerfWorkaround;
bool setDataFasterThanImageUpload;
}; };
} }
......
...@@ -102,7 +102,7 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, ...@@ -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. // 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. // 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) if (unpack.pixelBuffer.id() != 0)
{ {
...@@ -112,12 +112,30 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, ...@@ -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. // 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. // This functionality should be moved into renderer and the getData method of BufferImpl removed.
const void *bufferData = pixelBuffer->getImplementation()->getData(); 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) 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()) if (error.isError())
{ {
return error; return error;
...@@ -132,7 +150,7 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, ...@@ -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, 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) 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 // CPU readback & copy where direct GPU copy is not supported
if (unpack.pixelBuffer.id() != 0) if (unpack.pixelBuffer.id() != 0)
...@@ -142,7 +160,7 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi ...@@ -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. // 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. // This functionality should be moved into renderer and the getData method of BufferImpl removed.
const void *bufferData = pixelBuffer->getImplementation()->getData(); 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) if (pixelData != NULL)
...@@ -150,6 +168,16 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi ...@@ -150,6 +168,16 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
Image *image = getImage(index); Image *image = getImage(index);
ASSERT(image); 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, gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
type, pixelData); type, pixelData);
if (error.isError()) if (error.isError())
...@@ -157,7 +185,6 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi ...@@ -157,7 +185,6 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
return error; return error;
} }
gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
error = commitRegion(index, region); error = commitRegion(index, region);
if (error.isError()) if (error.isError())
{ {
...@@ -263,17 +290,43 @@ Image *TextureD3D::getBaseLevelImage() const ...@@ -263,17 +290,43 @@ Image *TextureD3D::getBaseLevelImage() const
void TextureD3D::generateMipmaps() 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(); initMipmapsImages();
// We know that all layers have the same dimension, for the texture to be complete // We know that all layers have the same dimension, for the texture to be complete
GLint layerCount = static_cast<GLint>(getLayerCount(0)); GLint layerCount = static_cast<GLint>(getLayerCount(0));
GLint mipCount = mipLevels();
// The following will create and initialize the storage, or update it if it exists // When making mipmaps with the setData workaround enabled, the texture storage has
TextureStorage *storage = getNativeTexture(); // 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) for (GLint layer = 0; layer < layerCount; ++layer)
{ {
...@@ -287,7 +340,7 @@ void TextureD3D::generateMipmaps() ...@@ -287,7 +340,7 @@ void TextureD3D::generateMipmaps()
if (renderableStorage) if (renderableStorage)
{ {
// GPU-side mipmapping // GPU-side mipmapping
storage->generateMipmap(sourceIndex, destIndex); mTexStorage->generateMipmap(sourceIndex, destIndex);
} }
else else
{ {
......
...@@ -323,27 +323,54 @@ gl::Error Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffse ...@@ -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) void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
{ {
RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(source); RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
ASSERT(renderTarget->getTexture()); ASSERT(sourceRenderTarget->getTexture());
ID3D11Texture2D *colorBufferTexture = d3d11::DynamicCastComObject<ID3D11Texture2D>(renderTarget->getTexture()); UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();
unsigned int subresourceIndex = renderTarget->getSubresourceIndex(); ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceRenderTarget->getTexture());
if (!colorBufferTexture) if (!sourceTexture2D)
{ {
// Error already generated // Error already generated
return; 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 // Error already generated
D3D11_TEXTURE2D_DESC textureDesc; return;
colorBufferTexture->GetDesc(&textureDesc); }
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(); ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
UINT subresourceAfterResolve = sourceSubResource;
ID3D11Texture2D* srcTex = NULL; ID3D11Texture2D* srcTex = NULL;
if (textureDesc.SampleDesc.Count > 1) if (textureDesc.SampleDesc.Count > 1)
{ {
...@@ -367,13 +394,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan ...@@ -367,13 +394,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan
return; return;
} }
deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format);
subresourceIndex = 0; subresourceAfterResolve = 0;
} }
else else
{ {
srcTex = colorBufferTexture; srcTex = source;
srcTex->AddRef();
} }
D3D11_BOX srcBox; D3D11_BOX srcBox;
...@@ -384,10 +410,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan ...@@ -384,10 +410,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan
srcBox.front = 0; srcBox.front = 0;
srcBox.back = 1; 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); if (textureDesc.SampleDesc.Count > 1)
SafeRelease(colorBufferTexture); {
SafeRelease(srcTex);
}
} }
else else
{ {
...@@ -406,10 +434,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan ...@@ -406,10 +434,12 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectan
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); 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(); unmap();
} }
mDirty = true;
} }
ID3D11Resource *Image11::getStagingTexture() ID3D11Resource *Image11::getStagingTexture()
......
...@@ -53,6 +53,8 @@ class Image11 : public ImageD3D ...@@ -53,6 +53,8 @@ class Image11 : public ImageD3D
const void *input); 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, RenderTarget *source);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source);
bool recoverFromAssociatedStorage(); bool recoverFromAssociatedStorage();
bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
...@@ -66,6 +68,7 @@ class Image11 : public ImageD3D ...@@ -66,6 +68,7 @@ class Image11 : public ImageD3D
DISALLOW_COPY_AND_ASSIGN(Image11); DISALLOW_COPY_AND_ASSIGN(Image11);
gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region); 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(); ID3D11Resource *getStagingTexture();
unsigned int getStagingSubresource(); unsigned int getStagingSubresource();
......
...@@ -1076,6 +1076,7 @@ Workarounds GenerateWorkarounds() ...@@ -1076,6 +1076,7 @@ Workarounds GenerateWorkarounds()
{ {
Workarounds workarounds; Workarounds workarounds;
workarounds.mrtPerfWorkaround = true; workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = true;
return workarounds; return workarounds;
} }
......
...@@ -717,4 +717,10 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectang ...@@ -717,4 +717,10 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectang
mDirty = true; 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 ...@@ -55,6 +55,8 @@ class Image9 : public ImageD3D
const void *input); 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, RenderTarget *source);
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
const gl::ImageIndex &sourceIndex, TextureStorage *source);
private: private:
DISALLOW_COPY_AND_ASSIGN(Image9); DISALLOW_COPY_AND_ASSIGN(Image9);
......
...@@ -543,6 +543,7 @@ Workarounds GenerateWorkarounds() ...@@ -543,6 +543,7 @@ Workarounds GenerateWorkarounds()
{ {
Workarounds workarounds; Workarounds workarounds;
workarounds.mrtPerfWorkaround = true; workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = false;
return workarounds; return workarounds;
} }
......
...@@ -40,9 +40,11 @@ protected: ...@@ -40,9 +40,11 @@ protected:
attribute vec4 position; attribute vec4 position;
varying vec2 texcoord; varying vec2 texcoord;
uniform vec2 textureScale;
void main() void main()
{ {
gl_Position = position; gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
texcoord = (position.xy * 0.5) + 0.5; texcoord = (position.xy * 0.5) + 0.5;
} }
); );
...@@ -81,6 +83,15 @@ protected: ...@@ -81,6 +83,15 @@ protected:
} }
mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex"); 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() virtual void TearDown()
...@@ -99,6 +110,7 @@ protected: ...@@ -99,6 +110,7 @@ protected:
GLuint m2DProgram; GLuint m2DProgram;
GLuint mCubeProgram; GLuint mCubeProgram;
GLint mTexture2DUniformLocation; GLint mTexture2DUniformLocation;
GLint mTextureScaleUniformLocation;
}; };
TYPED_TEST(TextureTest, NegativeAPISubImage) TYPED_TEST(TextureTest, NegativeAPISubImage)
...@@ -152,3 +164,64 @@ TYPED_TEST(TextureTest, CubeMapBug) ...@@ -152,3 +164,64 @@ TYPED_TEST(TextureTest, CubeMapBug)
drawQuad(mCubeProgram, "position", 0.5f); drawQuad(mCubeProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR(); 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