Commit 8b317ff2 authored by Eric Bruneton's avatar Eric Bruneton
Browse files

added support for subroutines, pipeline objects, multiple viewports

improved FrameBuffer to support up to 8 attachments
fixed bugs with transform feedback


git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/ork/trunk@10 28599a00-4e59-401b-b2d8-d34d4661a6c9
parent 9e8f2b81
......@@ -269,9 +269,9 @@ principles of object-oriented languages.
Ork solves theses problems by providing a minimal object-oriented
API on top of OpenGL. This means three things:
<ul>
<li>first, that Ork is based on OpenGL 3.3 core profile (with partial support
for 4.0 and 4.1). The compatibility profile is excluded by design, to keep
a minimal API.</li>
<li>first, that Ork is based on OpenGL 3.3 core profile (with full support
for 4.0 and 4.1 on compatible graphics cards). The compatibility profile is
excluded by design, to keep a minimal API.</li>
<li>second, that OpenGL framebuffers, programs, shaders, uniforms, textures,
samplers, buffers, queries, etc are represented with concrete C++ classes.</li>
<li>third, and most importantly, that these classes encapsulate the dirty
......@@ -339,11 +339,11 @@ automatically deleted when they are no longer used (for example when
a ork::Texture object is no longer referenced it is deleted,
which deletes the corresponding OpenGL texture in GPU memory).
The rendering API fully covers the OpenGL 3.3 core profile, and
partially covers the OpenGL 4.0 and 4.1 core profile APIs (tessellation
shaders and binary programs are supported, but uniform subroutines,
pipeline objects, separable shaders, and multiple viewports
are currently not supported).
The rendering API fully covers the OpenGL 4.1 core profile, but can be
used with an OpenGL 3.3 implementation (provided that the features
introduced in 4.0 and 4.1 are not used at runtime, such as tessellation
shaders, binary programs, uniform subroutines, pipeline objects,
separable shaders, and multiple viewports).
\subsection sec_meshes Meshes
......
......@@ -615,6 +615,10 @@
<Option target="Test" />
<Option target="Test_UNIX" />
</Unit>
<Unit filename="test/TestProgram.cpp">
<Option target="Test" />
<Option target="Test_UNIX" />
</Unit>
<Unit filename="test/TestResource.cpp">
<Option target="Test" />
<Option target="Test_UNIX" />
......
......@@ -156,7 +156,7 @@ void checkExtensions()
}
FrameBuffer::Parameters::Parameters() :
viewport(0, 0, 0, 0), depthRange(0.0f, 1.0f), clipDistances(0), transformId(0),
multiViewports(false), viewport(0, 0, 0, 0), depthRange(0.0f, 1.0f), clipDistances(0), transformId(0),
clearColor(0.0f, 0.0f, 0.0f, 0.0f), clearDepth(1.0f), clearStencil(0), clearId(0),
pointSize(1.0f), pointFadeThresholdSize(1.0f), pointLowerLeftOrigin(false), pointId(0),
lineWidth(1.0f), lineSmooth(false),
......@@ -165,7 +165,7 @@ FrameBuffer::Parameters::Parameters() :
multiSample(true), sampleAlphaToCoverage(false), sampleAlphaToOne(false),
sampleCoverage(1.0f), sampleMask(0xFFFFFFFF), multiSampleId(0),
occlusionQuery(NULL), occlusionMode(WAIT),
enableScissor(false), scissor(0, 0, 0, 0),
multiScissor(false),
enableStencil(false), ffunc(ALWAYS), fref(0), fmask(0xFFFFFFFF), ffail(KEEP), fdpfail(KEEP), fdppass(KEEP),
bfunc(ALWAYS), bref(0), bmask(0xFFFFFFFF), bfail(KEEP), bdpfail(KEEP), bdppass(KEEP), stencilId(0),
enableDepth(false), depth(LESS),
......@@ -174,6 +174,8 @@ FrameBuffer::Parameters::Parameters() :
enableLogic(false), logicOp(COPY),
multiColorMask(false), depthMask(true), stencilMaskFront(0xFFFFFFFF), stencilMaskBack(0xFFFFFFFF), maskId(0)
{
enableScissor[0] = false;
scissor[0] = vec4<GLint>(0, 0, 0, 0);
for (int i = 0; i < 4; ++i) {
enableBlend[i] = false;
rgb[i] = ADD;
......@@ -197,8 +199,15 @@ void FrameBuffer::Parameters::set(const Parameters &p)
// TRANSFORM -------------
if (transformId != p.transformId)
{
glViewport(p.viewport.x, p.viewport.y, p.viewport.z, p.viewport.w);
glDepthRange(p.depthRange.x, p.depthRange.y);
if (p.multiViewports) {
for (int i = 0; i < 16; ++i) {
glViewportIndexedf(i, p.viewports[i].x, p.viewports[i].y, p.viewports[i].z, p.viewports[i].w);
glDepthRangeIndexed(i, p.depthRanges[i].x, p.depthRanges[i].y);
}
} else {
glViewport(p.viewport.x, p.viewport.y, p.viewport.z, p.viewport.w);
glDepthRange(p.depthRange.x, p.depthRange.y);
}
for (int i = 0; i < 6; ++i) {
glEnable(GL_CLIP_DISTANCE0 + i, (p.clipDistances & (1 << i)) != 0);
}
......@@ -294,8 +303,19 @@ void FrameBuffer::Parameters::set(const Parameters &p)
if (enableScissor != p.enableScissor ||
scissor != p.scissor)
{
glEnable(GL_SCISSOR_TEST, p.enableScissor);
glScissor(p.scissor.x, p.scissor.y, p.scissor.z, p.scissor.w);
if (p.multiScissor) {
for (int i = 0; i < 16; ++i) {
if (p.enableScissor[i]) {
glEnablei(i, GL_SCISSOR_TEST);
} else {
glDisablei(i, GL_SCISSOR_TEST);
}
glScissorIndexed(i, p.scissor[i].x, p.scissor[i].y, p.scissor[i].z, p.scissor[i].w);
}
} else {
glEnable(GL_SCISSOR_TEST, p.enableScissor[0]);
glScissor(p.scissor[0].x, p.scissor[0].y, p.scissor[0].z, p.scissor[0].w);
}
}
// STENCIL TEST -------------
if (stencilId != p.stencilId)
......@@ -375,7 +395,7 @@ FrameBuffer::FrameBuffer() : Object("FrameBuffer"),
glGenFramebuffers(1, &framebufferId);
assert(getError() == 0);
for (int i = 0; i < 6; ++i) {
for (int i = 0; i < 10; ++i) {
textures[i] = NULL;
levels[i] = 0;
layers[i] = 0;
......@@ -574,6 +594,18 @@ void FrameBuffer::setDrawBuffers(BufferId b)
if ((b & COLOR3) != 0) {
drawBuffers[drawBufferCount++] = COLOR3;
}
if ((b & COLOR4) != 0) {
drawBuffers[drawBufferCount++] = COLOR4;
}
if ((b & COLOR5) != 0) {
drawBuffers[drawBufferCount++] = COLOR5;
}
if ((b & COLOR6) != 0) {
drawBuffers[drawBufferCount++] = COLOR6;
}
if ((b & COLOR7) != 0) {
drawBuffers[drawBufferCount++] = COLOR7;
}
readDrawChanged = true;
}
......@@ -587,11 +619,31 @@ vec4<GLint> FrameBuffer::getViewport()
return parameters.viewport;
}
vec4<GLfloat> FrameBuffer::getViewport(int index)
{
assert(index >= 0 && index < 16);
if (parameters.multiViewports) {
return parameters.viewports[index];
} else {
return parameters.viewport.cast<GLfloat>();
}
}
vec2<GLfloat> FrameBuffer::getDepthRange()
{
return parameters.depthRange;
}
vec2<GLdouble> FrameBuffer::getDepthRange(int index)
{
assert(index >= 0 && index < 16);
if (parameters.multiViewports) {
return parameters.depthRanges[index];
} else {
return parameters.depthRange.cast<GLdouble>();
}
}
GLint FrameBuffer::getClipDistances()
{
return parameters.clipDistances;
......@@ -696,13 +748,26 @@ ptr<Query> FrameBuffer::getOcclusionTest(QueryMode &occlusionMode)
bool FrameBuffer::getScissorTest()
{
return parameters.enableScissor;
return parameters.enableScissor[0];
}
bool FrameBuffer::getScissorTest(int index)
{
assert(index >=0 && index < 16);
return parameters.enableScissor[index];
}
bool FrameBuffer::getScissorTest(vec4<GLint> &scissor)
{
scissor = parameters.scissor;
return parameters.enableScissor;
scissor = parameters.scissor[0];
return parameters.enableScissor[0];
}
bool FrameBuffer::getScissorTest(int index, vec4<GLint> &scissor)
{
assert(index >=0 && index < 16);
scissor = parameters.scissor[index];
return parameters.enableScissor[index];
}
bool FrameBuffer::getStencilTest()
......@@ -824,18 +889,48 @@ void FrameBuffer::setParameters(const Parameters &p)
void FrameBuffer::setViewport(const vec4<GLint> &viewport)
{
parameters.multiViewports = false;
parameters.viewport = viewport;
parameters.transformId = ++PARAMETER_ID;
parametersChanged = true;
}
void FrameBuffer::setViewport(int index, const vec4<GLfloat> &viewport)
{
if (!parameters.multiViewports) {
for (int i = 0; i < 16; ++i) {
parameters.viewports[i] = parameters.viewport.cast<GLfloat>();
parameters.depthRanges[i] = parameters.depthRange.cast<GLdouble>();
}
parameters.multiViewports = true;
}
parameters.viewports[index] = viewport;
parameters.transformId = ++PARAMETER_ID;
parametersChanged = true;
}
void FrameBuffer::setDepthRange(GLfloat n, GLfloat f)
{
parameters.multiViewports = false;
parameters.depthRange = vec2<GLfloat>(n, f);
parameters.transformId = ++PARAMETER_ID;
parametersChanged = true;
}
void FrameBuffer::setDepthRange(int index, GLdouble n, GLdouble f)
{
if (!parameters.multiViewports) {
for (int i = 0; i < 16; ++i) {
parameters.viewports[i] = parameters.viewport.cast<GLfloat>();
parameters.depthRanges[i] = parameters.depthRange.cast<GLdouble>();
}
parameters.multiViewports = true;
}
parameters.depthRanges[index] = vec2<GLdouble>(n, f);
parameters.transformId = ++PARAMETER_ID;
parametersChanged = true;
}
void FrameBuffer::setClipDistances(int clipDistances)
{
parameters.clipDistances = clipDistances;
......@@ -982,14 +1077,43 @@ void FrameBuffer::setOcclusionTest(ptr<Query> occlusionQuery, QueryMode occlusio
void FrameBuffer::setScissorTest(bool enableScissor)
{
parameters.enableScissor = enableScissor;
parameters.multiScissor = false;
parameters.enableScissor[0] = enableScissor;
parametersChanged = true;
}
void FrameBuffer::setScissorTest(int index, bool enableScissor)
{
if (!parameters.multiScissor) {
for (int i = 1; i < 16; ++i) {
parameters.enableScissor[i] = parameters.enableScissor[0];
parameters.scissor[i] = parameters.scissor[0];
}
parameters.multiScissor = true;
}
parameters.enableScissor[index] = enableScissor;
parametersChanged = true;
}
void FrameBuffer::setScissorTest(bool enableScissor, const vec4<GLint> &scissor)
{
parameters.enableScissor = enableScissor;
parameters.scissor = scissor;
parameters.multiScissor = false;
parameters.enableScissor[0] = enableScissor;
parameters.scissor[0] = scissor;
parametersChanged = true;
}
void FrameBuffer::setScissorTest(int index, bool enableScissor, const vec4<GLint> &scissor)
{
if (!parameters.multiScissor) {
for (int i = 1; i < 16; ++i) {
parameters.enableScissor[i] = parameters.enableScissor[0];
parameters.scissor[i] = parameters.scissor[0];
}
parameters.multiScissor = true;
}
parameters.enableScissor[index] = enableScissor;
parameters.scissor[index] = scissor;
parametersChanged = true;
}
......@@ -1256,16 +1380,16 @@ void FrameBuffer::drawIndirect(ptr<Program> p, const MeshBuffers &mesh, MeshMode
endConditionalRender();
}
void FrameBuffer::drawFeedback(ptr<Program> p, MeshMode m, const TransformFeedback &tfb, int stream)
void FrameBuffer::drawFeedback(ptr<Program> p, const MeshBuffers &mesh, MeshMode m, const TransformFeedback &tfb, int stream)
{
assert(TransformFeedback::TRANSFORM == NULL);
assert(TransformFeedback::TRANSFORM == NULL && tfb.id != 0);
set();
p->set();
if (Logger::DEBUG_LOGGER != NULL) {
Logger::DEBUG_LOGGER->log("RENDER", "DrawFeedBack");
}
beginConditionalRender();
glDrawTransformFeedbackStream(getMeshMode(m), tfb.id, stream);
mesh.drawFeedback(m, tfb.id, stream);
endConditionalRender();
}
......@@ -1454,11 +1578,18 @@ void FrameBuffer::setAttachments()
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4,
GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6,
GL_COLOR_ATTACHMENT7,
GL_STENCIL_ATTACHMENT,
GL_DEPTH_ATTACHMENT
};
for (int i = 0; i < 6; ++i) {
for (int i = 0; i < 10; ++i) {
if (framebufferId == 0 && i >= 4 && i < 8) {
continue;
}
if (textures[i] == NULL) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, ATTACHMENTS[i], GL_RENDERBUFFER, 0);
continue;
......@@ -1570,7 +1701,7 @@ void FrameBuffer::endConditionalRender()
GLenum FrameBuffer::getBuffer(BufferId b) const
{
switch (b & (COLOR0 | COLOR1 | COLOR2 | COLOR3)) {
switch (b & (COLOR0 | COLOR1 | COLOR2 | COLOR3 | COLOR4 | COLOR5 | COLOR6 | COLOR7)) {
case 0:
return GL_NONE;
case COLOR0:
......@@ -1581,6 +1712,14 @@ GLenum FrameBuffer::getBuffer(BufferId b) const
return framebufferId == 0 ? GL_BACK_LEFT : GL_COLOR_ATTACHMENT2;
case COLOR3:
return framebufferId == 0 ? GL_BACK_RIGHT : GL_COLOR_ATTACHMENT3;
case COLOR4:
return framebufferId == 0 ? GL_NONE : GL_COLOR_ATTACHMENT4;
case COLOR5:
return framebufferId == 0 ? GL_NONE : GL_COLOR_ATTACHMENT5;
case COLOR6:
return framebufferId == 0 ? GL_NONE : GL_COLOR_ATTACHMENT6;
case COLOR7:
return framebufferId == 0 ? GL_NONE : GL_COLOR_ATTACHMENT7;
}
assert(false);
throw exception();
......
......@@ -78,6 +78,11 @@ public:
Parameters();
private:
/**
* True if several viewports are specified.
*/
bool multiViewports;
/**
* The viewport that defines the destination area for FrameBuffer#draw.
* This value is specific to this framebuffer instance and is
......@@ -87,12 +92,27 @@ public:
*/
vec4<GLint> viewport;
/**
* The viewports that define the destination areas for FrameBuffer#draw.
* This value is specific to this framebuffer instance and is
* automatically updated when the framebuffer is activated with
* FrameBuffer##set.
* (This corresponds to up, down, left and right planes).
*/
vec4<GLfloat> viewports[16];
/**
* The depth range that defines the destination area for #draw.
* Contains far and near planes.
*/
vec2<GLfloat> depthRange;
/**
* The depth ranges that define the destination areas for #draw.
* Contains far and near planes.
*/
vec2<GLdouble> depthRanges[16];
/**
* Defines which planes must be used for clipping tests.
* Each bit of clipDistances corresponds to a given plane.
......@@ -101,7 +121,8 @@ public:
int clipDistances;
/**
* A unique Id incremented each time viewport, depthrange or clipDistances change.
* A unique Id incremented each time multiViewports, viewport,
* viewports, depthRange depthRanges or clipDistances change.
*/
int transformId;
......@@ -282,16 +303,21 @@ public:
// -------------
/**
* True if separate scissor tests are used for each viewport.
*/
bool multiScissor;
/**
* If enabled, only the fragments inside #scissor will not be discarded.
* If disabled, the scissor test always passes.
*/
bool enableScissor;
bool enableScissor[16];
/**
* The viewport of the scissor test.
* The viewports of the scissor test.
*/
vec4<GLint> scissor;
vec4<GLint> scissor[16];
// -------------
......@@ -681,11 +707,21 @@ public:
*/
vec4<GLint> getViewport();
/**
* Returns the viewport of this framebuffer whose index is given.
*/
vec4<GLfloat> getViewport(int index);
/**
* Returns this framebuffer's depth range.
*/
vec2<GLfloat> getDepthRange();
/**
* Returns the depth range of this framebuffer whose index is given.
*/
vec2<GLdouble> getDepthRange(int index);
/**
* Returns this framebuffer's clip distances mask.
*/
......@@ -787,17 +823,30 @@ public:
ptr<Query> getOcclusionTest(QueryMode &occlusionMode);
/**
* Returns True if Scissor test is enabled.
* Returns True if the scissor test is enabled.
*/
bool getScissorTest();
/**
* Returns True if Scissor test is enabled.
* Returns True if the scissor test is enabled for the given viewport.
*/
bool getScissorTest(int index);
/**
* Returns true if the scissor test is enabled.
*
* @param[out] scissor the current scissor test viewport.
*/
bool getScissorTest(vec4<GLint> &scissor);
/**
* Returns true if the scissor test is enabled for the given viewport.
*
* @param index a viewport index.
* @param[out] scissor the current scissor test viewport.
*/
bool getScissorTest(int index, vec4<GLint> &scissor);
/**
* Returns true if stencil test is enabled.
*/
......@@ -931,6 +980,14 @@ public:
*/
void setViewport(const vec4<GLint> &viewport);
/**
* Sets a viewport for this framebuffer (up, down, left and right planes).
*
* @param index the viewport index.
* @param viewport the new viewport.
*/
void setViewport(int index, const vec4<GLfloat> &viewport);
/**
* Sets the depth range for this framebuffer (near and far planes).
*
......@@ -939,6 +996,15 @@ public:
*/
void setDepthRange(GLfloat n, GLfloat f);
/**
* Sets a depth range for this framebuffer (near and far planes).
*
* @param index the viewport index.
* @param n near plane.
* @param f far plane.
*/
void setDepthRange(int index, GLdouble n, GLdouble f);
/**
* Sets the clipping bit, used to determine which planes will be used for clipping.
*/
......@@ -1049,11 +1115,21 @@ public:
*/
void setScissorTest(bool enableScissor);
/**
* Enables or disables scissor test for the given viewport.
*/
void setScissorTest(int index, bool enableScissor);
/**
* Enables or disables scissor test.
*/
void setScissorTest(bool enableScissor, const vec4<GLint> &scissor);
/**
* Enables or disables scissor test for the given viewport.
*/
void setScissorTest(int index, bool enableScissor, const vec4<GLint> &scissor);
/**
* Enables or disables stencil test.
*
......@@ -1267,7 +1343,6 @@ public:
* Only available with OpenGL 4.0 or more.
*
* @param p the program to use to draw the mesh.
* @param mesh the mesh to draw.
* @param m how the mesh vertices must be interpreted.
* @param buf a CPU or GPU buffer containing the 'count', 'primCount',
* 'first' and 'base' parameters, in this order, followed by '0',
......@@ -1276,15 +1351,16 @@ public:
void drawIndirect(ptr<Program> p, const MeshBuffers &mesh, MeshMode m, const Buffer &buf);
/**
* Draws the mesh resulting from a transform feedback session.
* Draws a mesh with a vertex count resulting from a transform feedback session.
* Only available with OpenGL 4.0 or more.
*
* @param p the program to use to draw the mesh.
* @param mesh the mesh to draw.
* @param m how the mesh vertices must be interpreted.
* @param tfb a TransformFeedback containing the results of a transform feedback session.
* @param stream the stream to draw.
*/
void drawFeedback(ptr<Program> p, MeshMode m, const TransformFeedback &tfb, int stream = 0);
void drawFeedback(ptr<Program> p, const MeshBuffers &mesh, MeshMode m, const TransformFeedback &tfb, int stream = 0);
/**
* Draws a quad mesh. This mesh has a position attribute made of four
......@@ -1465,18 +1541,18 @@ private:
/**
* The attachments of this framebuffer.
*/
ptr<Object> textures[6];
ptr<Object> textures[10];
/**
* The levels specified for each attachments of this framebuffer.
*/
int levels[6];
int levels[10];
/**
* The layers specified for each attachments of this framebuffer. Only used for
* Texture arrays, Texture Cube, and Texture 3D.
*/
int layers[6];
int layers[10];
/**
* True if #textures, #levels or #layers has changed since the last call to #set().
......@@ -1496,7 +1572,7 @@ private:
/**
* The draw buffers.
*/
BufferId drawBuffers[4];
BufferId drawBuffers[8];
/**
* True if #readBuffer, #drawBufferCount or #drawBuffers has changed since
......
......@@ -116,7 +116,7 @@ public:
}
}
int findFreeUnit(int programId)
int findFreeUnit(const vector<GLuint> &programIds)
{
for (GLuint i = 0; i < maxUnits; ++i) {
if (units[i]->isFree()) {
......@@ -129,7 +129,7 @@ public:
for (GLuint i = 0; i < maxUnits; ++i) {
const GPUBuffer *buffer = units[i]->getCurrentBufferBinding();
if (!buffer->isUsedBy(programId)) {
if (!buffer->isUsedBy(programIds)) {
unsigned int bindingTime = units[i]->getLastBindingTime();
if (bestUnit == -1 || bindingTime < oldestBindingTime) {
bestUnit = i;
......@@ -254,7 +254,7 @@ void GPUBuffer::setData(int size, const void *data, BufferUsage u)
#endif
}
void GPUBuffer::setSubData(int target, int offset, int size, const void *data)
void GPUBuffer::setSubData(int offset, int size, const void *data)
{
assert(mappedData == NULL);
glBindBuffer(GL_COPY_WRITE_BUFFER, bufferId);
......@@ -267,7 +267,7 @@ void GPUBuffer::setSubData(int target, int offset, int size, const void *data)
}