Commit 56375021 by jchen10 Committed by Commit Bot

D3D11: Fix Buffer11 for GPU-to-CPU storage copy.

When copying from a non-mappable NativeStorage to a system memory based storage, a staging buffer storage should be used. Currently this is only done for PackStorage. This covers the missed SystemMemoryStorage and EmulatedIndexedStorage. Also it adds a triggering test case to expose the bug. BUG=angleproject:2076 Change-Id: I278a0eef85751e966c1c48ddd71010092a14a3f7 Reviewed-on: https://chromium-review.googlesource.com/542595 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent fcadd08a
...@@ -111,7 +111,9 @@ class Buffer11::BufferStorage : angle::NonCopyable ...@@ -111,7 +111,9 @@ class Buffer11::BufferStorage : angle::NonCopyable
size_t getSize() const { return mBufferSize; } size_t getSize() const { return mBufferSize; }
void setDataRevision(DataRevision rev) { mRevision = rev; } void setDataRevision(DataRevision rev) { mRevision = rev; }
virtual bool isMappable(GLbitfield access) const = 0; virtual bool isCPUAccessible(GLbitfield access) const = 0;
virtual bool isGPUAccessible() const = 0;
virtual gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source, virtual gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source,
size_t sourceOffset, size_t sourceOffset,
...@@ -146,7 +148,9 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage ...@@ -146,7 +148,9 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
const OnBufferDataDirtyChannel *onStorageChanged); const OnBufferDataDirtyChannel *onStorageChanged);
~NativeStorage() override; ~NativeStorage() override;
bool isMappable(GLbitfield access) const override; bool isCPUAccessible(GLbitfield access) const override;
bool isGPUAccessible() const override { return true; }
const d3d11::Buffer &getBuffer() const { return mBuffer; } const d3d11::Buffer &getBuffer() const { return mBuffer; }
gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source, gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source,
...@@ -184,7 +188,9 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage ...@@ -184,7 +188,9 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
EmulatedIndexedStorage(Renderer11 *renderer); EmulatedIndexedStorage(Renderer11 *renderer);
~EmulatedIndexedStorage() override; ~EmulatedIndexedStorage() override;
bool isMappable(GLbitfield access) const override { return true; } bool isCPUAccessible(GLbitfield access) const override { return true; }
bool isGPUAccessible() const override { return false; }
gl::ErrorOrResult<const d3d11::Buffer *> getBuffer(SourceIndexData *indexInfo, gl::ErrorOrResult<const d3d11::Buffer *> getBuffer(SourceIndexData *indexInfo,
const TranslatedAttribute &attribute, const TranslatedAttribute &attribute,
...@@ -217,7 +223,10 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage ...@@ -217,7 +223,10 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage
explicit PackStorage(Renderer11 *renderer); explicit PackStorage(Renderer11 *renderer);
~PackStorage() override; ~PackStorage() override;
bool isMappable(GLbitfield access) const override { return true; } bool isCPUAccessible(GLbitfield access) const override { return true; }
bool isGPUAccessible() const override { return false; }
gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source, gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source,
size_t sourceOffset, size_t sourceOffset,
size_t size, size_t size,
...@@ -253,7 +262,10 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage ...@@ -253,7 +262,10 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
explicit SystemMemoryStorage(Renderer11 *renderer); explicit SystemMemoryStorage(Renderer11 *renderer);
~SystemMemoryStorage() override {} ~SystemMemoryStorage() override {}
bool isMappable(GLbitfield access) const override { return true; } bool isCPUAccessible(GLbitfield access) const override { return true; }
bool isGPUAccessible() const override { return false; }
gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source, gl::ErrorOrResult<CopyResult> copyFromStorage(BufferStorage *source,
size_t sourceOffset, size_t sourceOffset,
size_t size, size_t size,
...@@ -414,14 +426,12 @@ gl::Error Buffer11::copySubData(const gl::Context *context, ...@@ -414,14 +426,12 @@ gl::Error Buffer11::copySubData(const gl::Context *context,
return gl::OutOfMemory() << "Failed to allocate internal staging buffer."; return gl::OutOfMemory() << "Failed to allocate internal staging buffer.";
} }
// If copying to/from a pixel pack buffer, we must have a staging or // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable.
// pack buffer partner, because other native buffers can't be mapped if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT))
if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable(GL_MAP_READ_BIT))
{ {
ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(), copySource); ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(), copySource);
} }
else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT))
!copyDest->isMappable(GL_MAP_WRITE_BIT))
{ {
ANGLE_TRY_RESULT(getStagingStorage(), copyDest); ANGLE_TRY_RESULT(getStagingStorage(), copyDest);
} }
...@@ -813,7 +823,8 @@ gl::Error Buffer11::updateBufferStorage(BufferStorage *storage, ...@@ -813,7 +823,8 @@ gl::Error Buffer11::updateBufferStorage(BufferStorage *storage,
// data directly. If we're already using a staging buffer we're fine. // data directly. If we're already using a staging buffer we're fine.
if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING &&
storage->getUsage() != BUFFER_USAGE_STAGING && storage->getUsage() != BUFFER_USAGE_STAGING &&
(!latestBuffer->isMappable(GL_MAP_READ_BIT) || !storage->isMappable(GL_MAP_WRITE_BIT))) (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) ||
!storage->isCPUAccessible(GL_MAP_WRITE_BIT)))
{ {
NativeStorage *stagingBuffer = nullptr; NativeStorage *stagingBuffer = nullptr;
ANGLE_TRY_RESULT(getStagingStorage(), stagingBuffer); ANGLE_TRY_RESULT(getStagingStorage(), stagingBuffer);
...@@ -921,7 +932,7 @@ Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) ...@@ -921,7 +932,7 @@ Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size) gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size)
{ {
ASSERT(isMappable(GL_MAP_WRITE_BIT)); ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT));
// Uniform storage can have a different internal size than the buffer size. Ensure we don't // Uniform storage can have a different internal size than the buffer size. Ensure we don't
// overflow. // overflow.
...@@ -951,7 +962,7 @@ Buffer11::NativeStorage::~NativeStorage() ...@@ -951,7 +962,7 @@ Buffer11::NativeStorage::~NativeStorage()
clearSRVs(); clearSRVs();
} }
bool Buffer11::NativeStorage::isMappable(GLbitfield access) const bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const
{ {
if ((access & GL_MAP_READ_BIT) != 0) if ((access & GL_MAP_READ_BIT) != 0)
{ {
...@@ -989,7 +1000,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::NativeStorage::copyFromStorage(BufferSto ...@@ -989,7 +1000,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::NativeStorage::copyFromStorage(BufferSto
if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY)
{ {
ASSERT(source->isMappable(GL_MAP_READ_BIT) && isMappable(GL_MAP_WRITE_BIT)); ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT));
// Uniform buffers must be mapped with write/discard. // Uniform buffers must be mapped with write/discard.
ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM)); ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM));
...@@ -1139,7 +1150,7 @@ gl::Error Buffer11::NativeStorage::map(size_t offset, ...@@ -1139,7 +1150,7 @@ gl::Error Buffer11::NativeStorage::map(size_t offset,
GLbitfield access, GLbitfield access,
uint8_t **mapPointerOut) uint8_t **mapPointerOut)
{ {
ASSERT(isMappable(access)); ASSERT(isCPUAccessible(access));
D3D11_MAPPED_SUBRESOURCE mappedResource; D3D11_MAPPED_SUBRESOURCE mappedResource;
ID3D11DeviceContext *context = mRenderer->getDeviceContext(); ID3D11DeviceContext *context = mRenderer->getDeviceContext();
...@@ -1159,7 +1170,7 @@ gl::Error Buffer11::NativeStorage::map(size_t offset, ...@@ -1159,7 +1170,7 @@ gl::Error Buffer11::NativeStorage::map(size_t offset,
void Buffer11::NativeStorage::unmap() void Buffer11::NativeStorage::unmap()
{ {
ASSERT(isMappable(GL_MAP_WRITE_BIT) || isMappable(GL_MAP_READ_BIT)); ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT));
ID3D11DeviceContext *context = mRenderer->getDeviceContext(); ID3D11DeviceContext *context = mRenderer->getDeviceContext();
context->Unmap(mBuffer.get(), 0); context->Unmap(mBuffer.get(), 0);
} }
...@@ -1319,7 +1330,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::EmulatedIndexedStorage::copyFromStorage( ...@@ -1319,7 +1330,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::EmulatedIndexedStorage::copyFromStorage(
size_t size, size_t size,
size_t destOffset) size_t destOffset)
{ {
ASSERT(source->isMappable(GL_MAP_READ_BIT)); ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
uint8_t *sourceData = nullptr; uint8_t *sourceData = nullptr;
ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
ASSERT(destOffset + size <= mMemoryBuffer.size()); ASSERT(destOffset + size <= mMemoryBuffer.size());
...@@ -1376,7 +1387,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::PackStorage::copyFromStorage(BufferStora ...@@ -1376,7 +1387,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::PackStorage::copyFromStorage(BufferStora
ANGLE_TRY(flushQueuedPackCommand()); ANGLE_TRY(flushQueuedPackCommand());
// For all use cases of pack buffers, we must copy through a readable buffer. // For all use cases of pack buffers, we must copy through a readable buffer.
ASSERT(source->isMappable(GL_MAP_READ_BIT)); ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
uint8_t *sourceData = nullptr; uint8_t *sourceData = nullptr;
ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
ASSERT(destOffset + size <= mMemoryBuffer.size()); ASSERT(destOffset + size <= mMemoryBuffer.size());
...@@ -1499,7 +1510,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::SystemMemoryStorage::copyFromStorage(Buf ...@@ -1499,7 +1510,7 @@ gl::ErrorOrResult<CopyResult> Buffer11::SystemMemoryStorage::copyFromStorage(Buf
size_t size, size_t size,
size_t destOffset) size_t destOffset)
{ {
ASSERT(source->isMappable(GL_MAP_READ_BIT)); ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
uint8_t *sourceData = nullptr; uint8_t *sourceData = nullptr;
ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
ASSERT(destOffset + size <= mSystemCopy.size()); ASSERT(destOffset + size <= mSystemCopy.size());
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "random_utils.h" #include "random_utils.h"
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle; using namespace angle;
...@@ -968,6 +969,57 @@ TEST_P(TransformFeedbackTest, OffsetResetOnBeginTransformFeedback) ...@@ -968,6 +969,57 @@ TEST_P(TransformFeedbackTest, OffsetResetOnBeginTransformFeedback)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Test that the captured buffer can be copied to other buffers.
TEST_P(TransformFeedbackTest, CaptureAndCopy)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Set the program's transform feedback varyings (just gl_Position)
std::vector<std::string> tfVaryings;
tfVaryings.push_back("gl_Position");
compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(mProgram, "position");
glEnable(GL_RASTERIZER_DISCARD);
const GLfloat vertices[] = {
-1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
-1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
};
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(positionLocation);
// Bind the buffer for transform feedback output and start transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 6);
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
glEndTransformFeedback();
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
glDisable(GL_RASTERIZER_DISCARD);
// Allocate a buffer with one byte
uint8_t singleByte[] = {0xaa};
// Create a new buffer and copy the first byte of captured data to it
GLBuffer copyBuffer;
glBindBuffer(GL_COPY_WRITE_BUFFER, copyBuffer);
glBufferData(GL_COPY_WRITE_BUFFER, 1, singleByte, GL_DYNAMIC_DRAW);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glCopyBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 1);
EXPECT_GL_NO_ERROR();
}
class TransformFeedbackLifetimeTest : public TransformFeedbackTest class TransformFeedbackLifetimeTest : public TransformFeedbackTest
{ {
protected: protected:
......
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