Commit 73bd218e by Geoff Lang Committed by Commit Bot

Support virtualized contexts and transform feedback in Renderer11.

Track buffer offets in the transform feedback object and dirty them when a buffer is bound. This fixes problems when a buffer is rebound at the same offset and maintains tracking between context switches. BUG=angleproject:1447 BUG=angleproject:1298 Change-Id: I2f890e3ad5edacab47f624a95a502615c86cc0c8 Reviewed-on: https://chromium-review.googlesource.com/360910Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent e074f728
......@@ -16,31 +16,51 @@
namespace gl
{
TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps)
: RefCountObject(id),
mImplementation(implFactory->createTransformFeedback()),
mLabel(),
TransformFeedbackState::TransformFeedbackState(size_t maxIndexedBuffers)
: mLabel(),
mActive(false),
mPrimitiveMode(GL_NONE),
mPaused(false),
mProgram(nullptr),
mGenericBuffer(),
mIndexedBuffers(caps.maxTransformFeedbackSeparateAttributes)
mIndexedBuffers(maxIndexedBuffers)
{
}
const BindingPointer<Buffer> &TransformFeedbackState::getGenericBuffer() const
{
return mGenericBuffer;
}
const OffsetBindingPointer<Buffer> &TransformFeedbackState::getIndexedBuffer(size_t idx) const
{
return mIndexedBuffers[idx];
}
const std::vector<OffsetBindingPointer<Buffer>> &TransformFeedbackState::getIndexedBuffers() const
{
return mIndexedBuffers;
}
TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps)
: RefCountObject(id),
mState(caps.maxTransformFeedbackSeparateAttributes),
mImplementation(implFactory->createTransformFeedback(mState))
{
ASSERT(mImplementation != nullptr);
}
TransformFeedback::~TransformFeedback()
{
if (mProgram)
if (mState.mProgram)
{
mProgram->release();
mProgram = nullptr;
mState.mProgram->release();
mState.mProgram = nullptr;
}
mGenericBuffer.set(nullptr);
for (size_t i = 0; i < mIndexedBuffers.size(); i++)
mState.mGenericBuffer.set(nullptr);
for (size_t i = 0; i < mState.mIndexedBuffers.size(); i++)
{
mIndexedBuffers[i].set(nullptr);
mState.mIndexedBuffers[i].set(nullptr);
}
SafeDelete(mImplementation);
......@@ -48,129 +68,129 @@ TransformFeedback::~TransformFeedback()
void TransformFeedback::setLabel(const std::string &label)
{
mLabel = label;
mState.mLabel = label;
}
const std::string &TransformFeedback::getLabel() const
{
return mLabel;
return mState.mLabel;
}
void TransformFeedback::begin(GLenum primitiveMode, Program *program)
{
mActive = true;
mPrimitiveMode = primitiveMode;
mPaused = false;
mState.mActive = true;
mState.mPrimitiveMode = primitiveMode;
mState.mPaused = false;
mImplementation->begin(primitiveMode);
bindProgram(program);
}
void TransformFeedback::end()
{
mActive = false;
mPrimitiveMode = GL_NONE;
mPaused = false;
mState.mActive = false;
mState.mPrimitiveMode = GL_NONE;
mState.mPaused = false;
mImplementation->end();
if (mProgram)
if (mState.mProgram)
{
mProgram->release();
mProgram = nullptr;
mState.mProgram->release();
mState.mProgram = nullptr;
}
}
void TransformFeedback::pause()
{
mPaused = true;
mState.mPaused = true;
mImplementation->pause();
}
void TransformFeedback::resume()
{
mPaused = false;
mState.mPaused = false;
mImplementation->resume();
}
bool TransformFeedback::isActive() const
{
return mActive;
return mState.mActive;
}
bool TransformFeedback::isPaused() const
{
return mPaused;
return mState.mPaused;
}
GLenum TransformFeedback::getPrimitiveMode() const
{
return mPrimitiveMode;
return mState.mPrimitiveMode;
}
void TransformFeedback::bindProgram(Program *program)
{
if (mProgram != program)
if (mState.mProgram != program)
{
if (mProgram != nullptr)
if (mState.mProgram != nullptr)
{
mProgram->release();
mState.mProgram->release();
}
mProgram = program;
if (mProgram != nullptr)
mState.mProgram = program;
if (mState.mProgram != nullptr)
{
mProgram->addRef();
mState.mProgram->addRef();
}
}
}
bool TransformFeedback::hasBoundProgram(GLuint program) const
{
return mProgram != nullptr && mProgram->id() == program;
return mState.mProgram != nullptr && mState.mProgram->id() == program;
}
void TransformFeedback::bindGenericBuffer(Buffer *buffer)
{
mGenericBuffer.set(buffer);
mImplementation->bindGenericBuffer(mGenericBuffer);
mState.mGenericBuffer.set(buffer);
mImplementation->bindGenericBuffer(mState.mGenericBuffer);
}
void TransformFeedback::detachBuffer(GLuint bufferName)
{
for (size_t index = 0; index < mIndexedBuffers.size(); index++)
for (size_t index = 0; index < mState.mIndexedBuffers.size(); index++)
{
if (mIndexedBuffers[index].id() == bufferName)
if (mState.mIndexedBuffers[index].id() == bufferName)
{
mIndexedBuffers[index].set(nullptr);
mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]);
mState.mIndexedBuffers[index].set(nullptr);
mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]);
}
}
if (mGenericBuffer.id() == bufferName)
if (mState.mGenericBuffer.id() == bufferName)
{
mGenericBuffer.set(nullptr);
mImplementation->bindGenericBuffer(mGenericBuffer);
mState.mGenericBuffer.set(nullptr);
mImplementation->bindGenericBuffer(mState.mGenericBuffer);
}
}
const BindingPointer<Buffer> &TransformFeedback::getGenericBuffer() const
{
return mGenericBuffer;
return mState.mGenericBuffer;
}
void TransformFeedback::bindIndexedBuffer(size_t index, Buffer *buffer, size_t offset, size_t size)
{
ASSERT(index < mIndexedBuffers.size());
mIndexedBuffers[index].set(buffer, offset, size);
mImplementation->bindIndexedBuffer(index, mIndexedBuffers[index]);
ASSERT(index < mState.mIndexedBuffers.size());
mState.mIndexedBuffers[index].set(buffer, offset, size);
mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]);
}
const OffsetBindingPointer<Buffer> &TransformFeedback::getIndexedBuffer(size_t index) const
{
ASSERT(index < mIndexedBuffers.size());
return mIndexedBuffers[index];
ASSERT(index < mState.mIndexedBuffers.size());
return mState.mIndexedBuffers[index];
}
size_t TransformFeedback::getIndexedBufferCount() const
{
return mIndexedBuffers.size();
return mState.mIndexedBuffers.size();
}
rx::TransformFeedbackImpl *TransformFeedback::getImplementation()
......
......@@ -26,6 +26,30 @@ class Buffer;
struct Caps;
class Program;
class TransformFeedbackState final : public angle::NonCopyable
{
public:
TransformFeedbackState(size_t maxIndexedBuffers);
const BindingPointer<Buffer> &getGenericBuffer() const;
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t idx) const;
const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const;
private:
friend class TransformFeedback;
std::string mLabel;
bool mActive;
GLenum mPrimitiveMode;
bool mPaused;
Program *mProgram;
BindingPointer<Buffer> mGenericBuffer;
std::vector<OffsetBindingPointer<Buffer>> mIndexedBuffers;
};
class TransformFeedback final : public RefCountObject, public LabeledObject
{
public:
......@@ -61,18 +85,8 @@ class TransformFeedback final : public RefCountObject, public LabeledObject
private:
void bindProgram(Program *program);
TransformFeedbackState mState;
rx::TransformFeedbackImpl* mImplementation;
std::string mLabel;
bool mActive;
GLenum mPrimitiveMode;
bool mPaused;
Program *mProgram;
BindingPointer<Buffer> mGenericBuffer;
std::vector<OffsetBindingPointer<Buffer>> mIndexedBuffers;
};
}
......
......@@ -14,12 +14,18 @@
#include "tests/angle_unittests_utils.h"
using ::testing::_;
using ::testing::get;
using ::testing::Return;
using ::testing::SetArgumentPointee;
namespace
{
ACTION(CreateMockTransformFeedbackImpl)
{
return new rx::MockTransformFeedbackImpl(arg0);
}
class TransformFeedbackTest : public testing::Test
{
protected:
......@@ -27,17 +33,18 @@ class TransformFeedbackTest : public testing::Test
void SetUp() override
{
mImpl = new rx::MockTransformFeedbackImpl;
EXPECT_CALL(mMockFactory, createTransformFeedback())
.WillOnce(Return(mImpl))
EXPECT_CALL(mMockFactory, createTransformFeedback(_))
.WillOnce(CreateMockTransformFeedbackImpl())
.RetiresOnSaturation();
// Set a reasonable number of tf attributes
mCaps.maxTransformFeedbackSeparateAttributes = 8;
EXPECT_CALL(*mImpl, destructor());
mFeedback = new gl::TransformFeedback(&mMockFactory, 1, mCaps);
mFeedback->addRef();
mImpl = rx::GetImplAs<rx::MockTransformFeedbackImpl>(mFeedback);
EXPECT_CALL(*mImpl, destructor());
}
void TearDown() override
......
......@@ -16,6 +16,7 @@
#include "libANGLE/Framebuffer.h"
#include "libANGLE/Program.h"
#include "libANGLE/Shader.h"
#include "libANGLE/TransformFeedback.h"
#include "libANGLE/VertexArray.h"
namespace gl
......@@ -73,7 +74,8 @@ class GLImplFactory : angle::NonCopyable
virtual FenceSyncImpl *createFenceSync() = 0;
// Transform Feedback creation
virtual TransformFeedbackImpl *createTransformFeedback() = 0;
virtual TransformFeedbackImpl *createTransformFeedback(
const gl::TransformFeedbackState &state) = 0;
// Sampler object creation
virtual SamplerImpl *createSampler() = 0;
......
......@@ -18,6 +18,7 @@ namespace rx
class TransformFeedbackImpl : angle::NonCopyable
{
public:
TransformFeedbackImpl(const gl::TransformFeedbackState &state) : mState(state) {}
virtual ~TransformFeedbackImpl() { }
virtual void begin(GLenum primitiveMode) = 0;
......@@ -27,6 +28,9 @@ class TransformFeedbackImpl : angle::NonCopyable
virtual void bindGenericBuffer(const BindingPointer<gl::Buffer> &binding) = 0;
virtual void bindIndexedBuffer(size_t index, const OffsetBindingPointer<gl::Buffer> &binding) = 0;
protected:
const gl::TransformFeedbackState &mState;
};
}
......
......@@ -19,6 +19,10 @@ namespace rx
class MockTransformFeedbackImpl : public TransformFeedbackImpl
{
public:
MockTransformFeedbackImpl(const gl::TransformFeedbackState &state)
: TransformFeedbackImpl(state)
{
}
~MockTransformFeedbackImpl() { destructor(); }
MOCK_METHOD1(begin, void(GLenum primitiveMode));
......
//
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers.
#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
namespace rx
{
TransformFeedbackD3D::TransformFeedbackD3D()
{
}
TransformFeedbackD3D::~TransformFeedbackD3D()
{
}
void TransformFeedbackD3D::begin(GLenum primitiveMode)
{
}
void TransformFeedbackD3D::end()
{
}
void TransformFeedbackD3D::pause()
{
}
void TransformFeedbackD3D::resume()
{
}
void TransformFeedbackD3D::bindGenericBuffer(const BindingPointer<gl::Buffer> &binding)
{
}
void TransformFeedbackD3D::bindIndexedBuffer(size_t index, const OffsetBindingPointer<gl::Buffer> &binding)
{
}
}
......@@ -16,12 +16,12 @@
#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
#include "libANGLE/renderer/d3d/SamplerD3D.h"
#include "libANGLE/renderer/d3d/TextureD3D.h"
#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Fence11.h"
#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
namespace rx
......@@ -121,9 +121,9 @@ FenceSyncImpl *Context11::createFenceSync()
return new FenceSync11(mRenderer);
}
TransformFeedbackImpl *Context11::createTransformFeedback()
TransformFeedbackImpl *Context11::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedbackD3D();
return new TransformFeedback11(state);
}
SamplerImpl *Context11::createSampler()
......
......@@ -50,7 +50,8 @@ class Context11 : public ContextImpl
FenceSyncImpl *createFenceSync() override;
// Transform Feedback creation
TransformFeedbackImpl *createTransformFeedback() override;
TransformFeedbackImpl *createTransformFeedback(
const gl::TransformFeedbackState &state) override;
// Sampler object creation
SamplerImpl *createSampler() override;
......
......@@ -42,6 +42,7 @@
#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
#include "libANGLE/renderer/d3d/d3d11/Trim11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
......@@ -54,7 +55,6 @@
#include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "libANGLE/renderer/d3d/SurfaceD3D.h"
#include "libANGLE/renderer/d3d/TextureD3D.h"
#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/State.h"
#include "libANGLE/Surface.h"
......@@ -444,7 +444,7 @@ Renderer11::Renderer11(egl::Display *display)
mAppliedGeometryShader = NULL;
mAppliedPixelShader = NULL;
mAppliedNumXFBBindings = static_cast<size_t>(-1);
mAppliedTFObject = angle::DirtyPointer;
ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription));
......@@ -1668,76 +1668,40 @@ gl::Error Renderer11::applyIndexBuffer(const gl::ContextState &data,
return gl::NoError();
}
gl::Error Renderer11::applyTransformFeedbackBuffers(const gl::State &state)
gl::Error Renderer11::applyTransformFeedbackBuffers(const gl::ContextState &data)
{
size_t numXFBBindings = 0;
bool requiresUpdate = false;
const auto &state = data.getState();
if (state.isTransformFeedbackActiveUnpaused())
// If transform feedback is not active, unbind all buffers
if (!state.isTransformFeedbackActiveUnpaused())
{
const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback();
numXFBBindings = transformFeedback->getIndexedBufferCount();
ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
for (size_t i = 0; i < numXFBBindings; i++)
if (mAppliedTFObject != 0)
{
const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i);
ID3D11Buffer *d3dBuffer = nullptr;
if (binding.get() != nullptr)
{
Buffer11 *storage = GetImplAs<Buffer11>(binding.get());
auto bufferOrError = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
if (bufferOrError.isError())
{
return bufferOrError.getError();
}
d3dBuffer = bufferOrError.getResult();
}
// TODO: mAppliedTFBuffers and friends should also be kept in a vector.
if (d3dBuffer != mAppliedTFBuffers[i] || binding.getOffset() != mAppliedTFOffsets[i])
{
requiresUpdate = true;
}
mDeviceContext->SOSetTargets(0, nullptr, nullptr);
mAppliedTFObject = 0;
}
return gl::NoError();
}
if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings)
gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback();
TransformFeedback11 *transformFeedback11 = GetImplAs<TransformFeedback11>(transformFeedback);
uintptr_t transformFeedbackId = reinterpret_cast<uintptr_t>(transformFeedback11);
if (mAppliedTFObject == transformFeedbackId && !transformFeedback11->isDirty())
{
const gl::TransformFeedback *transformFeedback = state.getCurrentTransformFeedback();
for (size_t i = 0; i < numXFBBindings; ++i)
{
const OffsetBindingPointer<gl::Buffer> &binding = transformFeedback->getIndexedBuffer(i);
if (binding.get() != nullptr)
{
Buffer11 *storage = GetImplAs<Buffer11>(binding.get());
auto bufferOrError = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
if (bufferOrError.isError())
{
return bufferOrError.getError();
}
ID3D11Buffer *d3dBuffer = bufferOrError.getResult();
return gl::NoError();
}
mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != binding.getOffset()) ?
static_cast<UINT>(binding.getOffset()) : -1;
mAppliedTFBuffers[i] = d3dBuffer;
}
else
{
mAppliedTFBuffers[i] = nullptr;
mCurrentD3DOffsets[i] = 0;
}
mAppliedTFOffsets[i] = binding.getOffset();
}
const std::vector<ID3D11Buffer *> *soBuffers = nullptr;
ANGLE_TRY_RESULT(transformFeedback11->getSOBuffers(), soBuffers);
const std::vector<UINT> &soOffsets = transformFeedback11->getSOBufferOffsets();
mAppliedNumXFBBindings = numXFBBindings;
mDeviceContext->SOSetTargets(transformFeedback11->getNumSOBuffers(), soBuffers->data(),
soOffsets.data());
mDeviceContext->SOSetTargets(static_cast<unsigned int>(numXFBBindings), mAppliedTFBuffers,
mCurrentD3DOffsets);
}
mAppliedTFObject = transformFeedbackId;
transformFeedback11->onApply();
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
gl::Error Renderer11::drawArraysImpl(const gl::ContextState &data,
......@@ -2549,13 +2513,7 @@ void Renderer11::markAllStateDirty()
mAppliedGeometryShader = angle::DirtyPointer;
mAppliedPixelShader = angle::DirtyPointer;
mAppliedNumXFBBindings = static_cast<size_t>(-1);
for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
{
mAppliedTFBuffers[i] = NULL;
mAppliedTFOffsets[i] = 0;
}
mAppliedTFObject = angle::DirtyPointer;
memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants11));
memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants11));
......@@ -4235,7 +4193,7 @@ gl::Error Renderer11::genericDrawElements(Context11 *context,
ANGLE_TRY(applyIndexBuffer(data, indices, count, mode, type, &indexInfo));
applyTransformFeedbackBuffers(glState);
applyTransformFeedbackBuffers(data);
// Transform feedback is not allowed for DrawElements, this error should have been caught at the
// API validation layer.
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
......@@ -4277,7 +4235,7 @@ gl::Error Renderer11::genericDrawArrays(Context11 *context,
}
ANGLE_TRY(updateState(data, mode));
ANGLE_TRY(applyTransformFeedbackBuffers(glState));
ANGLE_TRY(applyTransformFeedbackBuffers(data));
ANGLE_TRY(applyVertexBuffer(glState, mode, first, count, instances, nullptr));
ANGLE_TRY(applyTextures(context, data));
ANGLE_TRY(applyShaders(data, mode));
......
......@@ -152,7 +152,7 @@ class Renderer11 : public RendererD3D
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo);
gl::Error applyTransformFeedbackBuffers(const gl::State &state);
gl::Error applyTransformFeedbackBuffers(const gl::ContextState &data);
// lost device
bool testDeviceLost() override;
......@@ -470,15 +470,7 @@ class Renderer11 : public RendererD3D
bool mAppliedIBChanged;
// Currently applied transform feedback buffers
size_t mAppliedNumXFBBindings;
ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers
// in use for streamout
GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified
// buffer offsets to transform feedback
// buffers
UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets,
// which may differ from GLs, due
// to different append behavior
uintptr_t mAppliedTFObject;
// Currently applied shaders
uintptr_t mAppliedVertexShader;
......
//
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers.
#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
namespace rx
{
TransformFeedback11::TransformFeedback11(const gl::TransformFeedbackState &state)
: TransformFeedbackImpl(state),
mIsDirty(true),
mBuffers(state.getIndexedBuffers().size(), nullptr),
mBufferOffsets(state.getIndexedBuffers().size(), 0)
{
}
TransformFeedback11::~TransformFeedback11()
{
}
void TransformFeedback11::begin(GLenum primitiveMode)
{
}
void TransformFeedback11::end()
{
}
void TransformFeedback11::pause()
{
}
void TransformFeedback11::resume()
{
}
void TransformFeedback11::bindGenericBuffer(const BindingPointer<gl::Buffer> &binding)
{
}
void TransformFeedback11::bindIndexedBuffer(size_t index,
const OffsetBindingPointer<gl::Buffer> &binding)
{
mIsDirty = true;
mBufferOffsets[index] = static_cast<UINT>(binding.getOffset());
}
void TransformFeedback11::onApply()
{
mIsDirty = false;
// Change all buffer offsets to -1 so that if any of them need to be re-applied, the are set to
// append
std::fill(mBufferOffsets.begin(), mBufferOffsets.end(), -1);
}
bool TransformFeedback11::isDirty() const
{
return mIsDirty;
}
UINT TransformFeedback11::getNumSOBuffers() const
{
return static_cast<UINT>(mBuffers.size());
}
gl::ErrorOrResult<const std::vector<ID3D11Buffer *> *> TransformFeedback11::getSOBuffers()
{
for (size_t bindingIdx = 0; bindingIdx < mBuffers.size(); bindingIdx++)
{
const auto &binding = mState.getIndexedBuffer(bindingIdx);
if (binding.get() != nullptr)
{
Buffer11 *storage = GetImplAs<Buffer11>(binding.get());
ANGLE_TRY_RESULT(storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK),
mBuffers[bindingIdx]);
}
}
return &mBuffers;
}
const std::vector<UINT> &TransformFeedback11::getSOBufferOffsets() const
{
return mBufferOffsets;
}
} // namespace rx
......@@ -4,22 +4,25 @@
// found in the LICENSE file.
//
// TransformFeedbackD3D.h: Implements the abstract rx::TransformFeedbackImpl class.
// TransformFeedback11.h: Implements the abstract rx::TransformFeedbackImpl class.
#ifndef LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_
#define LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_
#ifndef LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_
#define LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_
#include "common/platform.h"
#include "libANGLE/renderer/TransformFeedbackImpl.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Error.h"
#include "libANGLE/renderer/TransformFeedbackImpl.h"
namespace rx
{
class TransformFeedbackD3D : public TransformFeedbackImpl
class TransformFeedback11 : public TransformFeedbackImpl
{
public:
TransformFeedbackD3D();
virtual ~TransformFeedbackD3D();
TransformFeedback11(const gl::TransformFeedbackState &state);
~TransformFeedback11() override;
void begin(GLenum primitiveMode) override;
void end() override;
......@@ -28,8 +31,20 @@ class TransformFeedbackD3D : public TransformFeedbackImpl
void bindGenericBuffer(const BindingPointer<gl::Buffer> &binding) override;
void bindIndexedBuffer(size_t index, const OffsetBindingPointer<gl::Buffer> &binding) override;
};
}
void onApply();
bool isDirty() const;
UINT getNumSOBuffers() const;
gl::ErrorOrResult<const std::vector<ID3D11Buffer *> *> getSOBuffers();
const std::vector<UINT> &getSOBufferOffsets() const;
private:
bool mIsDirty;
std::vector<ID3D11Buffer *> mBuffers;
std::vector<UINT> mBufferOffsets;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_
#endif // LIBANGLE_RENDERER_D3D_D3D11_TRANSFORMFEEDBACK11_H_
......@@ -16,7 +16,6 @@
#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
#include "libANGLE/renderer/d3d/SamplerD3D.h"
#include "libANGLE/renderer/d3d/TextureD3D.h"
#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
#include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
#include "libANGLE/renderer/d3d/d3d9/Fence9.h"
#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
......@@ -110,9 +109,10 @@ FenceSyncImpl *Context9::createFenceSync()
return nullptr;
}
TransformFeedbackImpl *Context9::createTransformFeedback()
TransformFeedbackImpl *Context9::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedbackD3D();
UNREACHABLE();
return nullptr;
}
SamplerImpl *Context9::createSampler()
......
......@@ -50,7 +50,8 @@ class Context9 : public ContextImpl
FenceSyncImpl *createFenceSync() override;
// Transform Feedback creation
TransformFeedbackImpl *createTransformFeedback() override;
TransformFeedbackImpl *createTransformFeedback(
const gl::TransformFeedbackState &state) override;
// Sampler object creation
SamplerImpl *createSampler() override;
......
......@@ -47,7 +47,6 @@
#include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "libANGLE/renderer/d3d/SurfaceD3D.h"
#include "libANGLE/renderer/d3d/TextureD3D.h"
#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h"
#include "libANGLE/State.h"
#include "libANGLE/Surface.h"
#include "libANGLE/Texture.h"
......
......@@ -102,10 +102,9 @@ FenceSyncImpl *ContextGL::createFenceSync()
return new FenceSyncGL(getFunctions());
}
TransformFeedbackImpl *ContextGL::createTransformFeedback()
TransformFeedbackImpl *ContextGL::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedbackGL(getFunctions(), getStateManager(),
getNativeCaps().maxTransformFeedbackSeparateComponents);
return new TransformFeedbackGL(state, getFunctions(), getStateManager());
}
SamplerImpl *ContextGL::createSampler()
......
......@@ -58,7 +58,8 @@ class ContextGL : public ContextImpl
FenceSyncImpl *createFenceSync() override;
// Transform Feedback creation
TransformFeedbackImpl *createTransformFeedback() override;
TransformFeedbackImpl *createTransformFeedback(
const gl::TransformFeedbackState &state) override;
// Sampler object creation
SamplerImpl *createSampler() override;
......
......@@ -17,16 +17,15 @@
namespace rx
{
TransformFeedbackGL::TransformFeedbackGL(const FunctionsGL *functions,
StateManagerGL *stateManager,
size_t maxTransformFeedbackBufferBindings)
: TransformFeedbackImpl(),
TransformFeedbackGL::TransformFeedbackGL(const gl::TransformFeedbackState &state,
const FunctionsGL *functions,
StateManagerGL *stateManager)
: TransformFeedbackImpl(state),
mFunctions(functions),
mStateManager(stateManager),
mTransformFeedbackID(0),
mIsActive(false),
mIsPaused(false),
mCurrentIndexedBuffers(maxTransformFeedbackBufferBindings)
mIsPaused(false)
{
mFunctions->genTransformFeedbacks(1, &mTransformFeedbackID);
}
......@@ -35,11 +34,6 @@ TransformFeedbackGL::~TransformFeedbackGL()
{
mStateManager->deleteTransformFeedback(mTransformFeedbackID);
mTransformFeedbackID = 0;
for (auto &bufferBinding : mCurrentIndexedBuffers)
{
bufferBinding.set(nullptr);
}
}
void TransformFeedbackGL::begin(GLenum primitiveMode)
......@@ -70,30 +64,25 @@ void TransformFeedbackGL::bindIndexedBuffer(size_t index, const OffsetBindingPoi
{
// Directly bind buffer (not through the StateManager methods) because the buffer bindings are
// tracked per transform feedback object
if (binding != mCurrentIndexedBuffers[index])
mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
if (binding.get() != nullptr)
{
mStateManager->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedbackID);
if (binding.get() != nullptr)
const BufferGL *bufferGL = GetImplAs<BufferGL>(binding.get());
if (binding.getSize() != 0)
{
const BufferGL *bufferGL = GetImplAs<BufferGL>(binding.get());
if (binding.getSize() != 0)
{
mFunctions->bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER,
static_cast<GLuint>(index), bufferGL->getBufferID(),
binding.getOffset(), binding.getSize());
}
else
{
mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
bufferGL->getBufferID());
}
mFunctions->bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
bufferGL->getBufferID(), binding.getOffset(),
binding.getSize());
}
else
{
mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index), 0);
mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index),
bufferGL->getBufferID());
}
mCurrentIndexedBuffers[index] = binding;
}
else
{
mFunctions->bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(index), 0);
}
}
......
......@@ -20,9 +20,9 @@ class StateManagerGL;
class TransformFeedbackGL : public TransformFeedbackImpl
{
public:
TransformFeedbackGL(const FunctionsGL *functions,
StateManagerGL *stateManager,
size_t maxTransformFeedbackBufferBindings);
TransformFeedbackGL(const gl::TransformFeedbackState &state,
const FunctionsGL *functions,
StateManagerGL *stateManager);
~TransformFeedbackGL() override;
void begin(GLenum primitiveMode) override;
......@@ -46,8 +46,6 @@ class TransformFeedbackGL : public TransformFeedbackImpl
mutable bool mIsActive;
mutable bool mIsPaused;
std::vector<OffsetBindingPointer<gl::Buffer>> mCurrentIndexedBuffers;
};
}
......
......@@ -253,9 +253,9 @@ FenceSyncImpl *ContextVk::createFenceSync()
return new FenceSyncVk();
}
TransformFeedbackImpl *ContextVk::createTransformFeedback()
TransformFeedbackImpl *ContextVk::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedbackVk();
return new TransformFeedbackVk(state);
}
SamplerImpl *ContextVk::createSampler()
......
......@@ -111,7 +111,8 @@ class ContextVk : public ContextImpl
FenceSyncImpl *createFenceSync() override;
// Transform Feedback creation
TransformFeedbackImpl *createTransformFeedback() override;
TransformFeedbackImpl *createTransformFeedback(
const gl::TransformFeedbackState &state) override;
// Sampler object creation
SamplerImpl *createSampler() override;
......
......@@ -14,7 +14,8 @@
namespace rx
{
TransformFeedbackVk::TransformFeedbackVk() : TransformFeedbackImpl()
TransformFeedbackVk::TransformFeedbackVk(const gl::TransformFeedbackState &state)
: TransformFeedbackImpl(state)
{
}
......
......@@ -18,7 +18,7 @@ namespace rx
class TransformFeedbackVk : public TransformFeedbackImpl
{
public:
TransformFeedbackVk();
TransformFeedbackVk(const gl::TransformFeedbackState &state);
~TransformFeedbackVk() override;
void begin(GLenum primitiveMode) override;
......
......@@ -247,8 +247,6 @@
'libANGLE/renderer/d3d/TextureD3D.cpp',
'libANGLE/renderer/d3d/TextureD3D.h',
'libANGLE/renderer/d3d/TextureStorage.h',
'libANGLE/renderer/d3d/TransformFeedbackD3D.cpp',
'libANGLE/renderer/d3d/TransformFeedbackD3D.h',
'libANGLE/renderer/d3d/VaryingPacking.cpp',
'libANGLE/renderer/d3d/VaryingPacking.h',
'libANGLE/renderer/d3d/VertexBuffer.cpp',
......@@ -413,6 +411,8 @@
'libANGLE/renderer/d3d/d3d11/SwapChain11.h',
'libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp',
'libANGLE/renderer/d3d/d3d11/TextureStorage11.h',
'libANGLE/renderer/d3d/d3d11/TransformFeedback11.cpp',
'libANGLE/renderer/d3d/d3d11/TransformFeedback11.h',
'libANGLE/renderer/d3d/d3d11/Trim11.cpp',
'libANGLE/renderer/d3d/d3d11/Trim11.h',
'libANGLE/renderer/d3d/d3d11/texture_format_table_autogen.cpp',
......
......@@ -55,7 +55,10 @@ class NullFactory : public GLImplFactory
FenceSyncImpl *createFenceSync() override { return nullptr; }
// Transform Feedback creation
TransformFeedbackImpl *createTransformFeedback() override { return nullptr; }
TransformFeedbackImpl *createTransformFeedback(const gl::TransformFeedbackState &state) override
{
return nullptr;
}
// Sampler object creation
SamplerImpl *createSampler() override { return nullptr; }
......@@ -82,7 +85,8 @@ class MockGLFactory : public GLImplFactory
MOCK_METHOD1(createQuery, QueryImpl *(GLenum type));
MOCK_METHOD0(createFenceNV, FenceNVImpl *());
MOCK_METHOD0(createFenceSync, FenceSyncImpl *());
MOCK_METHOD0(createTransformFeedback, TransformFeedbackImpl *());
MOCK_METHOD1(createTransformFeedback,
TransformFeedbackImpl *(const gl::TransformFeedbackState &));
MOCK_METHOD0(createSampler, SamplerImpl *());
MOCK_METHOD1(createPaths, std::vector<PathImpl *>(GLsizei));
};
......
......@@ -17,7 +17,6 @@ class TransformFeedbackTest : public ANGLETest
protected:
TransformFeedbackTest()
: mProgram(0),
mTransformFeedbackBufferSize(0),
mTransformFeedbackBuffer(0),
mTransformFeedback(0)
{
......@@ -34,7 +33,6 @@ class TransformFeedbackTest : public ANGLETest
ANGLETest::SetUp();
glGenBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBufferSize = 1 << 24; // ~16MB
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, NULL,
GL_STATIC_DRAW);
......@@ -99,7 +97,7 @@ class TransformFeedbackTest : public ANGLETest
GLuint mProgram;
size_t mTransformFeedbackBufferSize;
static const size_t mTransformFeedbackBufferSize = 1 << 24;
GLuint mTransformFeedbackBuffer;
GLuint mTransformFeedback;
};
......@@ -143,6 +141,80 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport)
EXPECT_EQ(2u, primitivesWritten);
}
// Test that rebinding a buffer with the same offset resets the offset (no longer appending from the
// old position)
TEST_P(TransformFeedbackTest, BufferRebinding)
{
glDisable(GL_DEPTH_TEST);
// 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);
// Make sure the buffer has zero'd data
std::vector<float> data(mTransformFeedbackBufferSize / sizeof(float), 0.0f);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, data.data(),
GL_STATIC_DRAW);
// Bind the buffer for transform feedback output and start transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_TRIANGLES);
// Create a query to check how many primitives were written
GLuint primitivesWrittenQuery = 0;
glGenQueries(1, &primitivesWrittenQuery);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesWrittenQuery);
float originalZ = 0.5f;
drawQuad(mProgram, "position", originalZ);
// stop, reset the buffer and resume
glEndTransformFeedback();
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_TRIANGLES);
float updatedZ = 0.75f;
drawQuad(mProgram, "position", updatedZ);
// End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
glUseProgram(0);
// Check how many primitives were written and verify that some were written even if
// no pixels were rendered
GLuint primitivesWritten = 0;
glGetQueryObjectuiv(primitivesWrittenQuery, GL_QUERY_RESULT_EXT, &primitivesWritten);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(4u, primitivesWritten);
// Check the buffer data
const float *bufferData = static_cast<float *>(glMapBufferRange(
GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBufferSize, GL_MAP_READ_BIT));
for (size_t vertexIdx = 0; vertexIdx < 6; vertexIdx++)
{
// Check the third (Z) component of each vertex written and make sure it has the updated
// value
EXPECT_NEAR(updatedZ, bufferData[vertexIdx * 4 + 2], 0.0001);
}
for (size_t dataIdx = 24; dataIdx < mTransformFeedbackBufferSize / sizeof(float); dataIdx++)
{
EXPECT_EQ(data[dataIdx], bufferData[dataIdx]) << "Buffer overrun detected.";
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
EXPECT_GL_NO_ERROR();
}
// Test that XFB can write back vertices to a buffer and that we can draw from this buffer afterward.
TEST_P(TransformFeedbackTest, RecordAndDraw)
{
......@@ -441,14 +513,6 @@ TEST_P(TransformFeedbackTest, MultiplePaused)
// contexts returns the correct results. Helps expose bugs in ANGLE's virtual contexts.
TEST_P(TransformFeedbackTest, MultiContext)
{
if (GetParam() == ES3_D3D11())
{
std::cout << "Test skipped because the D3D backends cannot support simultaneous transform "
"feedback or queries on multiple contexts yet."
<< std::endl;
return;
}
#if defined(ANGLE_PLATFORM_APPLE)
if ((IsNVIDIA() || IsAMD()) && GetParam() == ES3_OPENGL())
{
......@@ -773,7 +837,6 @@ class TransformFeedbackLifetimeTest : public TransformFeedbackTest
compileDefaultProgram(tfVaryings, GL_SEPARATE_ATTRIBS);
glGenBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBufferSize = 1 << 24; // ~16MB
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, NULL,
GL_DYNAMIC_DRAW);
......
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