Commit e2509a39 by Jamie Madill

D3D11: Fix basic ReadPixels from 3D attachments.

Use the TextureHelper class to abstractly handle 2D and 3d textures. Also refactor the Image11 copy methods to be a bit cleaner and not use the copy conversion path when unnecessary. This patch does not yet fix layer attachments - the fix for that will come up in a subsequent patch. BUG=angleproject:1290 Change-Id: If8b7aa8848ca4260e0dde690e7a99e115a97fabb Reviewed-on: https://chromium-review.googlesource.com/323442 Tryjob-Request: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 5e017349
...@@ -48,7 +48,23 @@ class Error final ...@@ -48,7 +48,23 @@ class Error final
mutable std::unique_ptr<std::string> mMessage; mutable std::unique_ptr<std::string> mMessage;
}; };
} template <typename T>
class ErrorOrResult
{
public:
ErrorOrResult(const gl::Error &error) : mError(error) {}
ErrorOrResult(T &&result) : mError(GL_NO_ERROR), mResult(std::move(result)) {}
bool isError() const { return mError.isError(); }
const gl::Error &getError() const { return mError; }
T &&getResult() { return std::move(mResult); }
private:
Error mError;
T mResult;
};
} // namespace gl
namespace egl namespace egl
{ {
...@@ -79,7 +95,7 @@ class Error final ...@@ -79,7 +95,7 @@ class Error final
mutable std::unique_ptr<std::string> mMessage; mutable std::unique_ptr<std::string> mMessage;
}; };
} } // namespace egl
#include "Error.inl" #include "Error.inl"
......
...@@ -29,20 +29,4 @@ ImageD3D::ImageD3D() ...@@ -29,20 +29,4 @@ ImageD3D::ImageD3D()
{ {
} }
gl::Error ImageD3D::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) } // namespace rx
{
const gl::FramebufferAttachment *srcAttachment = source->getReadColorbuffer();
ASSERT(srcAttachment);
RenderTargetD3D *renderTarget = NULL;
gl::Error error = srcAttachment->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
ASSERT(renderTarget);
return copy(destOffset, sourceArea, renderTarget);
}
}
...@@ -60,13 +60,11 @@ class ImageD3D : angle::NonCopyable ...@@ -60,13 +60,11 @@ class ImageD3D : angle::NonCopyable
virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); }; 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 copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, virtual gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex,
const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; TextureStorage *source) = 0;
virtual gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source); const gl::Rectangle &sourceArea,
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Framebuffer *source) = 0;
const gl::Rectangle &sourceArea,
RenderTargetD3D *source) = 0;
protected: protected:
GLsizei mWidth; GLsizei mWidth;
......
...@@ -450,9 +450,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages() ...@@ -450,9 +450,7 @@ gl::Error TextureD3D::generateMipmapsUsingImages()
gl::ImageIndex srcIndex = getImageIndex(0, layer); gl::ImageIndex srcIndex = getImageIndex(0, layer);
ImageD3D *image = getImage(srcIndex); ImageD3D *image = getImage(srcIndex);
gl::Box area(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); gl::Error error = image->copyFromTexStorage(srcIndex, mTexStorage);
gl::Offset offset(0, 0, 0);
gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -827,7 +825,7 @@ gl::Error TextureD3D_2D::copyImage(GLenum target, ...@@ -827,7 +825,7 @@ gl::Error TextureD3D_2D::copyImage(GLenum target,
// so we should use the non-rendering copy path. // so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{ {
gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -876,7 +874,7 @@ gl::Error TextureD3D_2D::copySubImage(GLenum target, ...@@ -876,7 +874,7 @@ gl::Error TextureD3D_2D::copySubImage(GLenum target,
// so we should use the non-rendering copy path. // so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{ {
gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -1254,16 +1252,8 @@ void TextureD3D_2D::redefineImage(size_t level, ...@@ -1254,16 +1252,8 @@ void TextureD3D_2D::redefineImage(size_t level,
// while orphaning // while orphaning
if (level != 0 && mEGLImageTarget) if (level != 0 && mEGLImageTarget)
{ {
gl::Offset offset(0, 0, 0); // TODO(jmadill): Don't discard error.
gl::Rectangle sourceArea(0, 0, mImageArray[0]->getWidth(), mImageArray[0]->getHeight()); mImageArray[0]->copyFromTexStorage(gl::ImageIndex::Make2D(0), mTexStorage);
RenderTargetD3D *storageRendertarget = nullptr;
gl::Error error =
mTexStorage->getRenderTarget(gl::ImageIndex::Make2D(0), &storageRendertarget);
if (!error.isError())
{
mImageArray[0]->copy(offset, sourceArea, storageRendertarget);
}
} }
if ((level >= storageLevels && storageLevels != 0) || if ((level >= storageLevels && storageLevels != 0) ||
...@@ -1442,7 +1432,8 @@ gl::Error TextureD3D_Cube::copyImage(GLenum target, ...@@ -1442,7 +1432,8 @@ gl::Error TextureD3D_Cube::copyImage(GLenum target,
// so we should use the non-rendering copy path. // so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{ {
gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source); gl::Error error =
mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -1490,7 +1481,8 @@ gl::Error TextureD3D_Cube::copySubImage(GLenum target, ...@@ -1490,7 +1481,8 @@ gl::Error TextureD3D_Cube::copySubImage(GLenum target,
// so we should use the non-rendering copy path. // so we should use the non-rendering copy path.
if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
{ {
gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source); gl::Error error =
mImageArray[faceIndex][level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -2112,7 +2104,7 @@ gl::Error TextureD3D_3D::copySubImage(GLenum target, ...@@ -2112,7 +2104,7 @@ gl::Error TextureD3D_3D::copySubImage(GLenum target,
if (canCreateRenderTargetForImage(index)) if (canCreateRenderTargetForImage(index))
{ {
gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); gl::Error error = mImageArray[level]->copyFromFramebuffer(destOffset, sourceArea, source);
if (error.isError()) if (error.isError())
{ {
return error; return error;
...@@ -2682,7 +2674,8 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target, ...@@ -2682,7 +2674,8 @@ gl::Error TextureD3D_2DArray::copySubImage(GLenum target,
if (canCreateRenderTargetForImage(index)) if (canCreateRenderTargetForImage(index))
{ {
gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source); gl::Error error = mImageArray[level][destOffset.z]->copyFromFramebuffer(destLayerOffset,
sourceArea, source);
if (error.isError()) if (error.isError())
{ {
return error; return error;
......
...@@ -1393,7 +1393,7 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand() ...@@ -1393,7 +1393,7 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand()
if (mQueuedPackCommand) if (mQueuedPackCommand)
{ {
TextureHelper11 stagingHelper(mStagingTexture); TextureHelper11 stagingHelper = TextureHelper11::MakeAndReference(mStagingTexture);
gl::Error error = gl::Error error =
mRenderer->packPixels(stagingHelper, *mQueuedPackCommand, mMemoryBuffer.data()); mRenderer->packPixels(stagingHelper, *mQueuedPackCommand, mMemoryBuffer.data());
......
...@@ -283,7 +283,7 @@ gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area, ...@@ -283,7 +283,7 @@ gl::Error Framebuffer11::readPixelsImpl(const gl::Rectangle &area,
ASSERT(renderTargetResource); ASSERT(renderTargetResource);
unsigned int subresourceIndex = renderTarget->getSubresourceIndex(); unsigned int subresourceIndex = renderTarget->getSubresourceIndex();
TextureHelper11 textureHelper(renderTargetResource); TextureHelper11 textureHelper = TextureHelper11::MakeAndReference(renderTargetResource);
gl::Buffer *packBuffer = pack.pixelBuffer.get(); gl::Buffer *packBuffer = pack.pixelBuffer.get();
if (packBuffer != nullptr) if (packBuffer != nullptr)
......
...@@ -23,6 +23,7 @@ class Framebuffer; ...@@ -23,6 +23,7 @@ class Framebuffer;
namespace rx namespace rx
{ {
class Renderer11; class Renderer11;
class TextureHelper11;
class TextureStorage11; class TextureStorage11;
class Image11 : public ImageD3D class Image11 : public ImageD3D
...@@ -44,9 +45,10 @@ class Image11 : public ImageD3D ...@@ -44,9 +45,10 @@ class Image11 : public ImageD3D
virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input); virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input);
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input); 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); gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override;
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
const gl::ImageIndex &sourceIndex, TextureStorage *source); const gl::Rectangle &sourceArea,
const gl::Framebuffer *source) override;
gl::Error recoverFromAssociatedStorage(); gl::Error recoverFromAssociatedStorage();
bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
...@@ -57,8 +59,10 @@ class Image11 : public ImageD3D ...@@ -57,8 +59,10 @@ class Image11 : public ImageD3D
void unmap(); void unmap();
private: private:
gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region); gl::Error copyWithoutConversion(const gl::Offset &destOffset,
gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource); const gl::Box &sourceArea,
const TextureHelper11 &textureHelper,
UINT sourceSubResource);
gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex);
gl::Error createStagingTexture(); gl::Error createStagingTexture();
......
...@@ -3634,35 +3634,22 @@ gl::Error Renderer11::readTextureData(const TextureHelper11 &textureHelper, ...@@ -3634,35 +3634,22 @@ gl::Error Renderer11::readTextureData(const TextureHelper11 &textureHelper,
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
D3D11_TEXTURE2D_DESC stagingDesc; gl::Extents safeSize(safeArea.width, safeArea.height, 1);
stagingDesc.Width = safeArea.width; auto errorOrResult = CreateStagingTexture(textureHelper.getTextureType(),
stagingDesc.Height = safeArea.height; textureHelper.getFormat(), safeSize, mDevice);
stagingDesc.MipLevels = 1; if (errorOrResult.isError())
stagingDesc.ArraySize = 1;
stagingDesc.Format = textureHelper.getFormat();
stagingDesc.SampleDesc.Count = 1;
stagingDesc.SampleDesc.Quality = 0;
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.BindFlags = 0;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.MiscFlags = 0;
ID3D11Texture2D *stagingTex = nullptr;
HRESULT result = mDevice->CreateTexture2D(&stagingDesc, nullptr, &stagingTex);
if (FAILED(result))
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging texture for ReadPixels, HRESULT: 0x%X.", result); return errorOrResult.getError();
} }
ID3D11Texture2D *texture = textureHelper.getTexture2D(); TextureHelper11 stagingHelper(errorOrResult.getResult());
if (!texture) TextureHelper11 resolvedTextureHelper;
{
// TODO(jmadill): Implement for 3D Textures. // "srcTexture" usually points to the source texture.
return gl::Error(GL_OUT_OF_MEMORY, "Renderer11::readTextureData called with 3D Texture."); // For 2D multisampled textures, it points to the multisampled resolve texture.
} const TextureHelper11 *srcTexture = &textureHelper;
ID3D11Texture2D *srcTex = nullptr; if (textureHelper.getTextureType() == GL_TEXTURE_2D && textureHelper.getSampleCount() > 1)
if (textureHelper.getSampleCount() > 1)
{ {
D3D11_TEXTURE2D_DESC resolveDesc; D3D11_TEXTURE2D_DESC resolveDesc;
resolveDesc.Width = static_cast<UINT>(texSize.width); resolveDesc.Width = static_cast<UINT>(texSize.width);
...@@ -3677,21 +3664,22 @@ gl::Error Renderer11::readTextureData(const TextureHelper11 &textureHelper, ...@@ -3677,21 +3664,22 @@ gl::Error Renderer11::readTextureData(const TextureHelper11 &textureHelper,
resolveDesc.CPUAccessFlags = 0; resolveDesc.CPUAccessFlags = 0;
resolveDesc.MiscFlags = 0; resolveDesc.MiscFlags = 0;
result = mDevice->CreateTexture2D(&resolveDesc, nullptr, &srcTex); ID3D11Texture2D *resolveTex2D = nullptr;
HRESULT result = mDevice->CreateTexture2D(&resolveDesc, nullptr, &resolveTex2D);
if (FAILED(result)) if (FAILED(result))
{ {
SafeRelease(stagingTex); return gl::Error(GL_OUT_OF_MEMORY,
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal resolve texture for ReadPixels, HRESULT: 0x%X.", result); "Renderer11::readTextureData failed to create internal resolve "
"texture for ReadPixels, HRESULT: 0x%X.",
result);
} }
mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, mDeviceContext->ResolveSubresource(resolveTex2D, 0, textureHelper.getTexture2D(),
textureHelper.getFormat()); subResource, textureHelper.getFormat());
resolvedTextureHelper = TextureHelper11::MakeAndReference(resolveTex2D);
subResource = 0; subResource = 0;
} srcTexture = &resolvedTextureHelper;
else
{
srcTex = texture;
srcTex->AddRef();
} }
D3D11_BOX srcBox; D3D11_BOX srcBox;
...@@ -3702,33 +3690,21 @@ gl::Error Renderer11::readTextureData(const TextureHelper11 &textureHelper, ...@@ -3702,33 +3690,21 @@ gl::Error Renderer11::readTextureData(const TextureHelper11 &textureHelper,
srcBox.front = 0; srcBox.front = 0;
srcBox.back = 1; srcBox.back = 1;
mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0,
srcTexture->getResource(), subResource, &srcBox);
SafeRelease(srcTex);
PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0);
TextureHelper11 stagingHelper(stagingTex); return packPixels(stagingHelper, packParams, pixels);
gl::Error error = packPixels(stagingHelper, packParams, pixels);
SafeRelease(stagingTex);
return error;
} }
gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper, gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper,
const PackPixelsParams &params, const PackPixelsParams &params,
uint8_t *pixelsOut) uint8_t *pixelsOut)
{ {
ID3D11Texture2D *readTexture = textureHelper.getTexture2D(); ID3D11Resource *readResource = textureHelper.getResource();
if (readTexture == nullptr)
{
// TODO(jmadill): Implement packPixels for 3D textures.
return gl::Error(GL_OUT_OF_MEMORY, "Renderer11::packPixels called with 3D Texture.");
}
D3D11_MAPPED_SUBRESOURCE mapping; D3D11_MAPPED_SUBRESOURCE mapping;
HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); HRESULT hr = mDeviceContext->Map(readResource, 0, D3D11_MAP_READ, 0, &mapping);
if (FAILED(hr)) if (FAILED(hr))
{ {
ASSERT(hr == E_OUTOFMEMORY); ASSERT(hr == E_OUTOFMEMORY);
...@@ -3806,7 +3782,7 @@ gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper, ...@@ -3806,7 +3782,7 @@ gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper,
} }
} }
mDeviceContext->Unmap(readTexture, 0); mDeviceContext->Unmap(readResource, 0);
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
......
...@@ -1500,21 +1500,53 @@ TextureHelper11::TextureHelper11() ...@@ -1500,21 +1500,53 @@ TextureHelper11::TextureHelper11()
{ {
} }
TextureHelper11::TextureHelper11(ID3D11Resource *resource) TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy)
: mTextureType(GL_NONE), : mTextureType(toCopy.mTextureType),
mFormat(DXGI_FORMAT_UNKNOWN), mExtents(toCopy.mExtents),
mSampleCount(0), mFormat(toCopy.mFormat),
mTexture2D(nullptr), mSampleCount(toCopy.mSampleCount),
mTexture3D(nullptr) mTexture2D(toCopy.mTexture2D),
mTexture3D(toCopy.mTexture3D)
{ {
mTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource); toCopy.reset();
mTexture3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(resource); }
// static
TextureHelper11 TextureHelper11::MakeAndReference(ID3D11Resource *genericResource)
{
TextureHelper11 newHelper;
newHelper.mTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(genericResource);
newHelper.mTexture3D = d3d11::DynamicCastComObject<ID3D11Texture3D>(genericResource);
newHelper.mTextureType = newHelper.mTexture2D ? GL_TEXTURE_2D : GL_TEXTURE_3D;
newHelper.initDesc();
return newHelper;
}
// static
TextureHelper11 TextureHelper11::MakeAndPossess2D(ID3D11Texture2D *texToOwn)
{
TextureHelper11 newHelper;
newHelper.mTexture2D = texToOwn;
newHelper.mTextureType = GL_TEXTURE_2D;
newHelper.initDesc();
return newHelper;
}
// static
TextureHelper11 TextureHelper11::MakeAndPossess3D(ID3D11Texture3D *texToOwn)
{
TextureHelper11 newHelper;
newHelper.mTexture3D = texToOwn;
newHelper.mTextureType = GL_TEXTURE_3D;
newHelper.initDesc();
return newHelper;
}
if (mTexture2D) void TextureHelper11::initDesc()
{
if (mTextureType == GL_TEXTURE_2D)
{ {
ASSERT(!mTexture3D); ASSERT(!mTexture3D);
mTextureType = GL_TEXTURE_2D;
D3D11_TEXTURE2D_DESC desc2D; D3D11_TEXTURE2D_DESC desc2D;
mTexture2D->GetDesc(&desc2D); mTexture2D->GetDesc(&desc2D);
...@@ -1526,9 +1558,7 @@ TextureHelper11::TextureHelper11(ID3D11Resource *resource) ...@@ -1526,9 +1558,7 @@ TextureHelper11::TextureHelper11(ID3D11Resource *resource)
} }
else else
{ {
ASSERT(mTexture3D); ASSERT(mTexture3D && mTextureType == GL_TEXTURE_3D);
mTextureType = GL_TEXTURE_3D;
D3D11_TEXTURE3D_DESC desc3D; D3D11_TEXTURE3D_DESC desc3D;
mTexture3D->GetDesc(&desc3D); mTexture3D->GetDesc(&desc3D);
...@@ -1540,17 +1570,6 @@ TextureHelper11::TextureHelper11(ID3D11Resource *resource) ...@@ -1540,17 +1570,6 @@ TextureHelper11::TextureHelper11(ID3D11Resource *resource)
} }
} }
TextureHelper11::TextureHelper11(TextureHelper11 &&toCopy)
: mTextureType(toCopy.mTextureType),
mExtents(toCopy.mExtents),
mFormat(toCopy.mFormat),
mSampleCount(toCopy.mSampleCount),
mTexture2D(toCopy.mTexture2D),
mTexture3D(toCopy.mTexture3D)
{
toCopy.reset();
}
TextureHelper11::~TextureHelper11() TextureHelper11::~TextureHelper11()
{ {
SafeRelease(mTexture2D); SafeRelease(mTexture2D);
...@@ -1588,4 +1607,58 @@ void TextureHelper11::reset() ...@@ -1588,4 +1607,58 @@ void TextureHelper11::reset()
mTexture3D = nullptr; mTexture3D = nullptr;
} }
gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
DXGI_FORMAT dxgiFormat,
const gl::Extents &size,
ID3D11Device *device)
{
if (textureType == GL_TEXTURE_2D)
{
D3D11_TEXTURE2D_DESC stagingDesc;
stagingDesc.Width = size.width;
stagingDesc.Height = size.height;
stagingDesc.MipLevels = 1;
stagingDesc.ArraySize = 1;
stagingDesc.Format = dxgiFormat;
stagingDesc.SampleDesc.Count = 1;
stagingDesc.SampleDesc.Quality = 0;
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.BindFlags = 0;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.MiscFlags = 0;
ID3D11Texture2D *stagingTex = nullptr;
HRESULT result = device->CreateTexture2D(&stagingDesc, nullptr, &stagingTex);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.",
result);
}
return TextureHelper11::MakeAndPossess2D(stagingTex);
}
ASSERT(textureType == GL_TEXTURE_3D);
D3D11_TEXTURE3D_DESC stagingDesc;
stagingDesc.Width = size.width;
stagingDesc.Height = size.height;
stagingDesc.Depth = 1;
stagingDesc.MipLevels = 1;
stagingDesc.Format = dxgiFormat;
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.BindFlags = 0;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.MiscFlags = 0;
ID3D11Texture3D *stagingTex = nullptr;
HRESULT result = device->CreateTexture3D(&stagingDesc, nullptr, &stagingTex);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "CreateStagingTextureFor failed, HRESULT: 0x%X.",
result);
}
return TextureHelper11::MakeAndPossess3D(stagingTex);
}
} // namespace rx } // namespace rx
...@@ -341,11 +341,14 @@ class TextureHelper11 : angle::NonCopyable ...@@ -341,11 +341,14 @@ class TextureHelper11 : angle::NonCopyable
{ {
public: public:
TextureHelper11(); TextureHelper11();
explicit TextureHelper11(ID3D11Resource *resource);
TextureHelper11(TextureHelper11 &&toCopy); TextureHelper11(TextureHelper11 &&toCopy);
~TextureHelper11(); ~TextureHelper11();
TextureHelper11 &operator=(TextureHelper11 &&texture); TextureHelper11 &operator=(TextureHelper11 &&texture);
static TextureHelper11 MakeAndReference(ID3D11Resource *genericResource);
static TextureHelper11 MakeAndPossess2D(ID3D11Texture2D *texToOwn);
static TextureHelper11 MakeAndPossess3D(ID3D11Texture3D *texToOwn);
GLenum getTextureType() const { return mTextureType; } GLenum getTextureType() const { return mTextureType; }
gl::Extents getExtents() const { return mExtents; } gl::Extents getExtents() const { return mExtents; }
DXGI_FORMAT getFormat() const { return mFormat; } DXGI_FORMAT getFormat() const { return mFormat; }
...@@ -356,6 +359,7 @@ class TextureHelper11 : angle::NonCopyable ...@@ -356,6 +359,7 @@ class TextureHelper11 : angle::NonCopyable
private: private:
void reset(); void reset();
void initDesc();
GLenum mTextureType; GLenum mTextureType;
gl::Extents mExtents; gl::Extents mExtents;
...@@ -365,6 +369,11 @@ class TextureHelper11 : angle::NonCopyable ...@@ -365,6 +369,11 @@ class TextureHelper11 : angle::NonCopyable
ID3D11Texture3D *mTexture3D; ID3D11Texture3D *mTexture3D;
}; };
gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
DXGI_FORMAT dxgiFormat,
const gl::Extents &size,
ID3D11Device *device);
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
...@@ -549,7 +549,9 @@ gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) ...@@ -549,7 +549,9 @@ gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input)
} }
// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) gl::Error Image9::copyFromRTInternal(const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
RenderTargetD3D *source)
{ {
ASSERT(source); ASSERT(source);
...@@ -777,11 +779,35 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source ...@@ -777,11 +779,35 @@ gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &source
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Box &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage) gl::Error Image9::copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source)
{ {
// Currently unreachable, due to only being used in a D3D11-only workaround RenderTargetD3D *renderTarget = nullptr;
UNIMPLEMENTED(); gl::Error error = source->getRenderTarget(imageIndex, &renderTarget);
return gl::Error(GL_INVALID_OPERATION); if (error.isError())
{
return error;
}
gl::Rectangle sourceArea(0, 0, mWidth, mHeight);
return copyFromRTInternal(gl::Offset(), sourceArea, renderTarget);
} }
gl::Error Image9::copyFromFramebuffer(const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
const gl::Framebuffer *source)
{
const gl::FramebufferAttachment *srcAttachment = source->getReadColorbuffer();
ASSERT(srcAttachment);
RenderTargetD3D *renderTarget = NULL;
gl::Error error = srcAttachment->getRenderTarget(&renderTarget);
if (error.isError())
{
return error;
}
ASSERT(renderTarget);
return copyFromRTInternal(destOffset, sourceArea, renderTarget);
} }
} // namespace rx
...@@ -45,9 +45,10 @@ class Image9 : public ImageD3D ...@@ -45,9 +45,10 @@ class Image9 : public ImageD3D
virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input); virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input);
virtual gl::Error loadCompressedData(const gl::Box &area, const void *input); 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); gl::Error copyFromTexStorage(const gl::ImageIndex &imageIndex, TextureStorage *source) override;
virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, gl::Error copyFromFramebuffer(const gl::Offset &destOffset,
const gl::ImageIndex &sourceIndex, TextureStorage *source); const gl::Rectangle &sourceArea,
const gl::Framebuffer *source) override;
private: private:
gl::Error getSurface(IDirect3DSurface9 **outSurface); gl::Error getSurface(IDirect3DSurface9 **outSurface);
...@@ -59,6 +60,10 @@ class Image9 : public ImageD3D ...@@ -59,6 +60,10 @@ class Image9 : public ImageD3D
gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect); gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect);
void unlock(); void unlock();
gl::Error copyFromRTInternal(const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
RenderTargetD3D *source);
Renderer9 *mRenderer; Renderer9 *mRenderer;
D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable.
......
...@@ -409,6 +409,152 @@ TEST_P(ReadPixelsMultisampleTest, BasicClear) ...@@ -409,6 +409,152 @@ TEST_P(ReadPixelsMultisampleTest, BasicClear)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
class ReadPixelsTextureTest : public ANGLETest
{
public:
ReadPixelsTextureTest() : mFBO(0), mTexture(0)
{
setWindowWidth(32);
setWindowHeight(32);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
void SetUp() override
{
ANGLETest::SetUp();
glGenTextures(1, &mTexture);
glGenFramebuffers(1, &mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
}
void TearDown() override
{
glDeleteFramebuffers(1, &mFBO);
glDeleteTextures(1, &mTexture);
ANGLETest::TearDown();
}
void testRead(GLenum textureTarget, GLint levels, GLint attachmentLevel, GLint attachmentLayer)
{
glBindTexture(textureTarget, mTexture);
glTexStorage3D(textureTarget, levels, GL_RGBA8, 4, 4, 4);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture, attachmentLevel,
attachmentLayer);
initializeTextureData(textureTarget, levels);
verifyColor(attachmentLevel, attachmentLayer);
}
// Give each {level,layer} pair a (probably) unique color via random.
GLuint getColorValue(GLint level, GLint layer)
{
mRNG.reseed(level + layer * 32);
return mRNG.randomUInt();
}
void verifyColor(GLint level, GLint layer)
{
angle::GLColor colorValue(getColorValue(level, layer));
EXPECT_PIXEL_COLOR_EQ(0, 0, colorValue);
}
void initializeTextureData(GLenum textureTarget, GLint levels)
{
for (GLint level = 0; level < levels; ++level)
{
GLint mipSize = 4 >> level;
GLint layers = (textureTarget == GL_TEXTURE_3D ? mipSize : 4);
size_t layerSize = mipSize * mipSize;
std::vector<GLuint> textureData(layers * layerSize);
for (GLint layer = 0; layer < layers; ++layer)
{
GLuint colorValue = getColorValue(level, layer);
size_t offset = (layer * layerSize);
std::fill(textureData.begin() + offset, textureData.begin() + offset + layerSize,
colorValue);
}
glTexSubImage3D(textureTarget, level, 0, 0, 0, mipSize, mipSize, layers, GL_RGBA,
GL_UNSIGNED_BYTE, textureData.data());
}
}
angle::RNG mRNG;
GLuint mFBO;
GLuint mTexture;
};
// Test 3D attachment readback.
TEST_P(ReadPixelsTextureTest, BasicAttachment3D)
{
testRead(GL_TEXTURE_3D, 1, 0, 0);
}
// Test 3D attachment readback, non-zero mip.
TEST_P(ReadPixelsTextureTest, MipAttachment3D)
{
testRead(GL_TEXTURE_3D, 2, 1, 0);
}
// Test 3D attachment readback, non-zero layer.
TEST_P(ReadPixelsTextureTest, LayerAttachment3D)
{
if (isD3D11())
{
// TODO(jmadill): Fix ReadPixels from non-zero layer attachments.
std::cout << "Test disabled on D3D11." << std::endl;
return;
}
testRead(GL_TEXTURE_3D, 1, 0, 1);
}
// Test 3D attachment readback, non-zero mip and layer.
TEST_P(ReadPixelsTextureTest, MipLayerAttachment3D)
{
if (isD3D11())
{
// TODO(jmadill): Fix ReadPixels from non-zero layer attachments.
std::cout << "Test disabled on D3D11." << std::endl;
return;
}
testRead(GL_TEXTURE_3D, 2, 1, 1);
}
// Test 2D array attachment readback.
TEST_P(ReadPixelsTextureTest, BasicAttachment2DArray)
{
testRead(GL_TEXTURE_2D_ARRAY, 1, 0, 0);
}
// Test 3D attachment readback, non-zero mip.
TEST_P(ReadPixelsTextureTest, MipAttachment2DArray)
{
testRead(GL_TEXTURE_2D_ARRAY, 2, 1, 0);
}
// Test 3D attachment readback, non-zero layer.
TEST_P(ReadPixelsTextureTest, LayerAttachment2DArray)
{
testRead(GL_TEXTURE_2D_ARRAY, 1, 0, 1);
}
// Test 3D attachment readback, non-zero mip and layer.
TEST_P(ReadPixelsTextureTest, MipLayerAttachment2DArray)
{
testRead(GL_TEXTURE_2D_ARRAY, 2, 1, 1);
}
// TODO(jmadill): Tests for PBOs with 3D and layer attachments.
} // anonymous namespace } // anonymous namespace
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
...@@ -416,3 +562,4 @@ ANGLE_INSTANTIATE_TEST(ReadPixelsTest, ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES() ...@@ -416,3 +562,4 @@ ANGLE_INSTANTIATE_TEST(ReadPixelsTest, ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES()
ANGLE_INSTANTIATE_TEST(ReadPixelsPBOTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(ReadPixelsPBOTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(ReadPixelsPBODrawTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(ReadPixelsPBODrawTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(ReadPixelsMultisampleTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(ReadPixelsMultisampleTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(ReadPixelsTextureTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
...@@ -144,13 +144,6 @@ TEST_P(StateChangeTest, CopyTexSubImage2DSync) ...@@ -144,13 +144,6 @@ TEST_P(StateChangeTest, CopyTexSubImage2DSync)
// Ensure that CopyTexSubImage3D syncs framebuffer changes. // Ensure that CopyTexSubImage3D syncs framebuffer changes.
TEST_P(StateChangeTestES3, CopyTexSubImage3DSync) TEST_P(StateChangeTestES3, CopyTexSubImage3DSync)
{ {
if (isD3D11())
{
// TODO(jmadill): Fix the bug in the D3D11 back-end.
std::cout << "Test diabled on D3D11." << std::endl;
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
// Init first texture to red // Init first texture to red
......
...@@ -23,6 +23,11 @@ GLColor::GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) : R(r), G(g), B(b), ...@@ -23,6 +23,11 @@ GLColor::GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) : R(r), G(g), B(b),
{ {
} }
GLColor::GLColor(GLuint colorValue) : R(0), G(0), B(0), A(0)
{
memcpy(&R, &colorValue, sizeof(GLuint));
}
GLColor ReadColor(GLint x, GLint y) GLColor ReadColor(GLint x, GLint y)
{ {
GLColor actual; GLColor actual;
......
...@@ -45,6 +45,7 @@ struct GLColor ...@@ -45,6 +45,7 @@ struct GLColor
{ {
GLColor(); GLColor();
GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a); GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a);
GLColor(GLuint colorValue);
GLubyte R, G, B, A; GLubyte R, G, B, A;
}; };
...@@ -66,6 +67,8 @@ GLColor ReadColor(GLint x, GLint y); ...@@ -66,6 +67,8 @@ GLColor ReadColor(GLint x, GLint y);
#define EXPECT_PIXEL_EQ(x, y, r, g, b, a) \ #define EXPECT_PIXEL_EQ(x, y, r, g, b, a) \
EXPECT_EQ(angle::MakeGLColor(r, g, b, a), angle::ReadColor(x, y)) EXPECT_EQ(angle::MakeGLColor(r, g, b, a), angle::ReadColor(x, y))
#define EXPECT_PIXEL_COLOR_EQ(x, y, angleColor) EXPECT_EQ(angleColor, angle::ReadColor(x, y))
// TODO(jmadill): Figure out how we can use GLColor's nice printing with EXPECT_NEAR. // TODO(jmadill): Figure out how we can use GLColor's nice printing with EXPECT_NEAR.
#define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \ #define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \
{ \ { \
......
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