Commit 90a96efc by Geoff Lang Committed by Commit Bot

Allow BufferGL to function without being able to map buffers for read.

Reading back buffer data is required for index range validation but without glMapBufferRange it is not possible to read back buffer data on OpenGL ES. To work around this, keep a shadow copy of the buffer data when this function is not available. BUG=angleproject:1145 Change-Id: I8e9b3b174574316d3af0022bd29c7d9c96d168c3 Reviewed-on: https://chromium-review.googlesource.com/324092Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent 356f5165
...@@ -11,8 +11,10 @@ ...@@ -11,8 +11,10 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
namespace rx namespace rx
{ {
...@@ -30,6 +32,11 @@ static const GLenum DestBufferOperationTarget = GL_ARRAY_BUFFER; ...@@ -30,6 +32,11 @@ static const GLenum DestBufferOperationTarget = GL_ARRAY_BUFFER;
BufferGL::BufferGL(const FunctionsGL *functions, StateManagerGL *stateManager) BufferGL::BufferGL(const FunctionsGL *functions, StateManagerGL *stateManager)
: BufferImpl(), : BufferImpl(),
mIsMapped(false), mIsMapped(false),
mMapOffset(0),
mMapSize(0),
mShadowBufferData(!CanMapBufferForRead(functions)),
mShadowCopy(),
mBufferSize(0),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
mBufferID(0) mBufferID(0)
...@@ -50,6 +57,22 @@ gl::Error BufferGL::setData(const void* data, size_t size, GLenum usage) ...@@ -50,6 +57,22 @@ gl::Error BufferGL::setData(const void* data, size_t size, GLenum usage)
{ {
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID); mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
mFunctions->bufferData(DestBufferOperationTarget, size, data, usage); mFunctions->bufferData(DestBufferOperationTarget, size, data, usage);
if (mShadowBufferData)
{
if (!mShadowCopy.resize(size))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize buffer data shadow copy.");
}
if (size > 0 && data != nullptr)
{
memcpy(mShadowCopy.data(), data, size);
}
}
mBufferSize = size;
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -57,6 +80,12 @@ gl::Error BufferGL::setSubData(const void* data, size_t size, size_t offset) ...@@ -57,6 +80,12 @@ gl::Error BufferGL::setSubData(const void* data, size_t size, size_t offset)
{ {
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID); mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
mFunctions->bufferSubData(DestBufferOperationTarget, offset, size, data); mFunctions->bufferSubData(DestBufferOperationTarget, offset, size, data);
if (mShadowBufferData && size > 0)
{
memcpy(mShadowCopy.data() + offset, data, size);
}
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
...@@ -69,33 +98,70 @@ gl::Error BufferGL::copySubData(BufferImpl* source, GLintptr sourceOffset, GLint ...@@ -69,33 +98,70 @@ gl::Error BufferGL::copySubData(BufferImpl* source, GLintptr sourceOffset, GLint
mFunctions->copyBufferSubData(SourceBufferOperationTarget, DestBufferOperationTarget, sourceOffset, destOffset, size); mFunctions->copyBufferSubData(SourceBufferOperationTarget, DestBufferOperationTarget, sourceOffset, destOffset, size);
if (mShadowBufferData && size > 0)
{
ASSERT(sourceGL->mShadowBufferData);
memcpy(mShadowCopy.data() + destOffset, sourceGL->mShadowCopy.data() + sourceOffset, size);
}
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error BufferGL::map(GLenum access, GLvoid **mapPtr) gl::Error BufferGL::map(GLenum access, GLvoid **mapPtr)
{ {
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID); if (mShadowBufferData)
*mapPtr = mFunctions->mapBuffer(DestBufferOperationTarget, access); {
*mapPtr = mShadowCopy.data();
}
else
{
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
*mapPtr = mFunctions->mapBuffer(DestBufferOperationTarget, access);
}
mIsMapped = true; mIsMapped = true;
mMapOffset = 0;
mMapSize = mBufferSize;
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error BufferGL::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) gl::Error BufferGL::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
{ {
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID); if (mShadowBufferData)
*mapPtr = mFunctions->mapBufferRange(DestBufferOperationTarget, offset, length, access); {
*mapPtr = mShadowCopy.data() + offset;
}
else
{
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
*mapPtr = mFunctions->mapBufferRange(DestBufferOperationTarget, offset, length, access);
}
mIsMapped = true; mIsMapped = true;
mMapOffset = offset;
mMapSize = length;
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error BufferGL::unmap(GLboolean *result) gl::Error BufferGL::unmap(GLboolean *result)
{ {
ASSERT(result); ASSERT(result);
ASSERT(mIsMapped);
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
*result = mFunctions->unmapBuffer(DestBufferOperationTarget); if (mShadowBufferData)
{
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
mFunctions->bufferSubData(DestBufferOperationTarget, mMapOffset, mMapSize,
mShadowCopy.data() + mMapOffset);
*result = GL_TRUE;
}
else
{
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
*result = mFunctions->unmapBuffer(DestBufferOperationTarget);
}
mIsMapped = false; mIsMapped = false;
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
...@@ -109,10 +175,21 @@ gl::Error BufferGL::getIndexRange(GLenum type, ...@@ -109,10 +175,21 @@ gl::Error BufferGL::getIndexRange(GLenum type,
{ {
ASSERT(!mIsMapped); ASSERT(!mIsMapped);
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID); if (mShadowBufferData)
const uint8_t *bufferData = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(DestBufferOperationTarget, GL_READ_ONLY)); {
*outRange = gl::ComputeIndexRange(type, bufferData + offset, count, primitiveRestartEnabled); *outRange = gl::ComputeIndexRange(type, mShadowCopy.data() + offset, count,
mFunctions->unmapBuffer(DestBufferOperationTarget); primitiveRestartEnabled);
}
else
{
mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
const gl::Type &typeInfo = gl::GetTypeInfo(type);
const uint8_t *bufferData = MapBufferRangeWithFallback(
mFunctions, DestBufferOperationTarget, offset, count * typeInfo.bytes, GL_MAP_READ_BIT);
*outRange = gl::ComputeIndexRange(type, bufferData, count, primitiveRestartEnabled);
mFunctions->unmapBuffer(DestBufferOperationTarget);
}
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#ifndef LIBANGLE_RENDERER_GL_BUFFERGL_H_ #ifndef LIBANGLE_RENDERER_GL_BUFFERGL_H_
#define LIBANGLE_RENDERER_GL_BUFFERGL_H_ #define LIBANGLE_RENDERER_GL_BUFFERGL_H_
#include "common/MemoryBuffer.h"
#include "libANGLE/renderer/BufferImpl.h" #include "libANGLE/renderer/BufferImpl.h"
namespace rx namespace rx
...@@ -40,6 +41,13 @@ class BufferGL : public BufferImpl ...@@ -40,6 +41,13 @@ class BufferGL : public BufferImpl
private: private:
bool mIsMapped; bool mIsMapped;
size_t mMapOffset;
size_t mMapSize;
bool mShadowBufferData;
MemoryBuffer mShadowCopy;
size_t mBufferSize;
const FunctionsGL *mFunctions; const FunctionsGL *mFunctions;
StateManagerGL *mStateManager; StateManagerGL *mStateManager;
......
...@@ -569,6 +569,14 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM ...@@ -569,6 +569,14 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
caps->maxFragmentUniformComponents = caps->maxFragmentUniformComponents =
std::min(caps->maxFragmentUniformVectors / 4, caps->maxFragmentUniformComponents); std::min(caps->maxFragmentUniformVectors / 4, caps->maxFragmentUniformComponents);
// If it is not possible to support reading buffer data back, a shadow copy of the buffers must
// be held. This disallows writing to buffers indirectly through transform feedback, thus
// disallowing ES3.
if (!CanMapBufferForRead(functions))
{
LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
}
// Extension support // Extension support
extensions->setTextureExtensionSupport(*textureCapsMap); extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->elementIndexUint = functions->standard == STANDARD_GL_DESKTOP || extensions->elementIndexUint = functions->standard == STANDARD_GL_DESKTOP ||
...@@ -662,4 +670,55 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround ...@@ -662,4 +670,55 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
} }
bool CanMapBufferForRead(const FunctionsGL *functions)
{
return (functions->mapBufferRange != nullptr) ||
(functions->mapBuffer != nullptr && functions->standard == STANDARD_GL_DESKTOP);
}
uint8_t *MapBufferRangeWithFallback(const FunctionsGL *functions,
GLenum target,
size_t offset,
size_t length,
GLbitfield access)
{
if (functions->mapBufferRange != nullptr)
{
return reinterpret_cast<uint8_t *>(
functions->mapBufferRange(target, offset, length, access));
}
else if (functions->mapBuffer != nullptr &&
(functions->standard == STANDARD_GL_DESKTOP || access == GL_MAP_WRITE_BIT))
{
// Only the read and write bits are supported
ASSERT((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) != 0);
GLenum accessEnum = 0;
if (access == (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))
{
accessEnum = GL_READ_WRITE;
}
else if (access == GL_MAP_READ_BIT)
{
accessEnum = GL_READ_ONLY;
}
else if (access == GL_MAP_WRITE_BIT)
{
accessEnum = GL_WRITE_ONLY;
}
else
{
UNREACHABLE();
return nullptr;
}
return reinterpret_cast<uint8_t *>(functions->mapBuffer(target, accessEnum)) + offset;
}
else
{
// No options available
UNREACHABLE();
return nullptr;
}
}
} }
...@@ -40,6 +40,12 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM ...@@ -40,6 +40,12 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds); void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds);
} }
bool CanMapBufferForRead(const FunctionsGL *functions);
uint8_t *MapBufferRangeWithFallback(const FunctionsGL *functions,
GLenum target,
size_t offset,
size_t length,
GLbitfield access);
} }
#endif // LIBANGLE_RENDERER_GL_RENDERERGLUTILS_H_ #endif // LIBANGLE_RENDERER_GL_RENDERERGLUTILS_H_
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