Transform feedback buffer assignment
This cl adds a utility function that assigns the correct buffer
for each linked transform feedback variable. All the information
about location and size is sent to the VertexProcessor for use
during rendering.
Change-Id: I942805250804f56805de1fc117024c20976e83a0
Reviewed-on: https://swiftshader-review.googlesource.com/5174
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index 9bfee2b..6a790f4 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -17,6 +17,7 @@
#include "main.h"
#include "Buffer.h"
#include "Shader.h"
+#include "TransformFeedback.h"
#include "utilities.h"
#include "common/debug.h"
#include "Shader/PixelShader.hpp"
@@ -1182,6 +1183,90 @@
}
}
+ void Program::applyTransformFeedback(TransformFeedback* transformFeedback)
+ {
+ // Make sure the flags will fit in a 64 bit unsigned int variable
+ ASSERT(sw::max<int>(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) <= 64);
+
+ BufferBinding* transformFeedbackBuffers = (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused()) ? transformFeedback->getBuffers() : nullptr;
+
+ uint64_t enableTransformFeedback = 0;
+ if(!transformFeedbackBuffers)
+ {
+ for(unsigned int index = 0; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
+ {
+ device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
+ }
+ device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
+ return;
+ }
+
+ unsigned int maxVaryings = transformFeedbackLinkedVaryings.size();
+ switch(transformFeedbackBufferMode)
+ {
+ case GL_SEPARATE_ATTRIBS:
+ {
+ maxVaryings = sw::min(maxVaryings, (unsigned int)MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
+ // Attribs go to separate buffers
+ for(unsigned int index = 0; index < maxVaryings; ++index)
+ {
+ int size = transformFeedbackLinkedVaryings[index].size;
+ int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
+ int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
+ int nbRegs = rowCount > 1 ? colCount * size : size;
+ int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
+ int componentStride = rowCount * colCount * size;
+ int baseOffset = transformFeedback->vertexOffset() * componentStride * sizeof(float);
+ device->VertexProcessor::setTransformFeedbackBuffer(index,
+ transformFeedbackBuffers[index].get()->getResource(),
+ transformFeedbackBuffers[index].getOffset() + baseOffset,
+ transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
+ nbRegs, nbComponentsPerReg, componentStride);
+ enableTransformFeedback |= 1ULL << index;
+ }
+ }
+ break;
+ case GL_INTERLEAVED_ATTRIBS:
+ {
+ // OpenGL ES 3.0.4 spec, section 2.15.2:
+ // In INTERLEAVED_ATTRIBS mode, the values of one or more output variables
+ // written by a vertex shader are written, interleaved, into the buffer object
+ // bound to the first transform feedback binding point (index = 0).
+ sw::Resource* resource = transformFeedbackBuffers[0].get()->getResource();
+ int componentStride = totalLinkedVaryingsComponents;
+ int baseOffset = transformFeedbackBuffers[0].getOffset() + (transformFeedback->vertexOffset() * componentStride * sizeof(float));
+ maxVaryings = sw::min(maxVaryings, (unsigned int)sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
+ size_t totalComponents = 0;
+ for(unsigned int index = 0; index < maxVaryings; ++index)
+ {
+ int size = transformFeedbackLinkedVaryings[index].size;
+ int rowCount = VariableRowCount(transformFeedbackLinkedVaryings[index].type);
+ int colCount = VariableColumnCount(transformFeedbackLinkedVaryings[index].type);
+ int nbRegs = rowCount > 1 ? colCount * size : size;
+ int nbComponentsPerReg = rowCount > 1 ? rowCount : colCount;
+ device->VertexProcessor::setTransformFeedbackBuffer(index, resource,
+ baseOffset + (totalComponents * sizeof(float)),
+ transformFeedbackLinkedVaryings[index].reg * 4 + transformFeedbackLinkedVaryings[index].col,
+ nbRegs, nbComponentsPerReg, componentStride);
+ totalComponents += rowCount * colCount * size;
+ enableTransformFeedback |= 1ULL << index;
+ }
+ }
+ break;
+ default:
+ UNREACHABLE(transformFeedbackBufferMode);
+ break;
+ }
+
+ // Unset all other transform feedback buffers
+ for(unsigned int index = maxVaryings; index < sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++index)
+ {
+ device->VertexProcessor::setTransformFeedbackBuffer(index, nullptr, 0, 0, 0, 0, 0);
+ }
+
+ device->VertexProcessor::enableTransformFeedback(enableTransformFeedback);
+ }
+
bool Program::linkVaryings()
{
for(glsl::VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); ++input)
diff --git a/src/OpenGL/libGLESv2/Program.h b/src/OpenGL/libGLESv2/Program.h
index 1ff8f05..2d08d89 100644
--- a/src/OpenGL/libGLESv2/Program.h
+++ b/src/OpenGL/libGLESv2/Program.h
@@ -171,6 +171,7 @@
void dirtyAllUniforms();
void applyUniforms();
void applyUniformBuffers(BufferBinding* uniformBuffers);
+ void applyTransformFeedback(TransformFeedback* transformFeedback);
void link();
bool isLinked() const;
diff --git a/src/OpenGL/libGLESv2/TransformFeedback.cpp b/src/OpenGL/libGLESv2/TransformFeedback.cpp
index 3d5e2b3..44df63e 100644
--- a/src/OpenGL/libGLESv2/TransformFeedback.cpp
+++ b/src/OpenGL/libGLESv2/TransformFeedback.cpp
@@ -16,7 +16,7 @@
namespace es2
{
-TransformFeedback::TransformFeedback(GLuint name) : NamedObject(name), mActive(false), mPaused(false)
+TransformFeedback::TransformFeedback(GLuint name) : NamedObject(name), mActive(false), mPaused(false), mVertexOffset(0)
{
mGenericBuffer = NULL;
}
@@ -60,6 +60,19 @@
return mBuffer[index].getSize();
}
+void TransformFeedback::addVertexOffset(int count)
+{
+ if(isActive() && !isPaused())
+ {
+ mVertexOffset += count;
+ }
+}
+
+int TransformFeedback::vertexOffset() const
+{
+ return mVertexOffset;
+}
+
bool TransformFeedback::isActive() const
{
return mActive;
@@ -84,6 +97,7 @@
{
mActive = false;
mPaused = false;
+ mVertexOffset = 0;
}
void TransformFeedback::setPaused(bool paused)
diff --git a/src/OpenGL/libGLESv2/TransformFeedback.h b/src/OpenGL/libGLESv2/TransformFeedback.h
index 4871ee1..0bc11b6 100644
--- a/src/OpenGL/libGLESv2/TransformFeedback.h
+++ b/src/OpenGL/libGLESv2/TransformFeedback.h
@@ -27,10 +27,11 @@
class TransformFeedback : public gl::NamedObject
{
public:
- // FIXME: Change this when implementing transform feedback
TransformFeedback(GLuint name);
~TransformFeedback();
+ BufferBinding* getBuffers() { return mBuffer; }
+
Buffer* getGenericBuffer() const;
Buffer* getBuffer(GLuint index) const;
GLuint getGenericBufferName() const;
@@ -40,6 +41,7 @@
bool isActive() const;
bool isPaused() const;
GLenum primitiveMode() const;
+ int vertexOffset() const;
void setGenericBuffer(Buffer* buffer);
void setBuffer(GLuint index, Buffer* buffer);
@@ -48,6 +50,7 @@
void begin(GLenum primitiveMode);
void end();
void setPaused(bool paused);
+ void addVertexOffset(int count);
private:
gl::BindingPointer<Buffer> mGenericBuffer;
@@ -56,6 +59,7 @@
bool mActive;
bool mPaused;
GLenum mPrimitiveMode;
+ int mVertexOffset;
};
}