|
@@ -5,6 +5,8 @@
|
|
|
|
|
|
|
|
#include "anki/gr/gl/PipelineImpl.h"
|
|
#include "anki/gr/gl/PipelineImpl.h"
|
|
|
#include "anki/gr/gl/ShaderImpl.h"
|
|
#include "anki/gr/gl/ShaderImpl.h"
|
|
|
|
|
+#include "anki/gr/gl/GrManagerImpl.h"
|
|
|
|
|
+#include "anki/gr/gl/RenderingThread.h"
|
|
|
#include "anki/util/Logger.h"
|
|
#include "anki/util/Logger.h"
|
|
|
|
|
|
|
|
namespace anki {
|
|
namespace anki {
|
|
@@ -29,12 +31,155 @@ static GLenum computeGlShaderType(const ShaderType idx, GLbitfield* bit)
|
|
|
return gltype[enumToType(idx)];
|
|
return gltype[enumToType(idx)];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+static GLenum convertBlendMethod(BlendMethod in)
|
|
|
|
|
+{
|
|
|
|
|
+ GLenum out = 0;
|
|
|
|
|
+
|
|
|
|
|
+ switch(in)
|
|
|
|
|
+ {
|
|
|
|
|
+ case BlendMethod::ZERO:
|
|
|
|
|
+ out = GL_ZERO;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE:
|
|
|
|
|
+ out = GL_ONE;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::SRC_COLOR:
|
|
|
|
|
+ out = GL_SRC_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_SRC_COLOR:
|
|
|
|
|
+ out = GL_ONE_MINUS_SRC_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::DST_COLOR:
|
|
|
|
|
+ out = GL_DST_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_DST_COLOR:
|
|
|
|
|
+ out = GL_ONE_MINUS_DST_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::SRC_ALPHA:
|
|
|
|
|
+ out = GL_SRC_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_SRC_ALPHA:
|
|
|
|
|
+ out = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::DST_ALPHA:
|
|
|
|
|
+ out = GL_DST_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_DST_ALPHA:
|
|
|
|
|
+ out = GL_ONE_MINUS_DST_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::CONSTANT_COLOR:
|
|
|
|
|
+ out = GL_CONSTANT_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_CONSTANT_COLOR:
|
|
|
|
|
+ out = GL_ONE_MINUS_CONSTANT_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::CONSTANT_ALPHA:
|
|
|
|
|
+ out = GL_CONSTANT_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_CONSTANT_ALPHA:
|
|
|
|
|
+ out = GL_ONE_MINUS_CONSTANT_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::SRC_ALPHA_SATURATE:
|
|
|
|
|
+ out = GL_SRC_ALPHA_SATURATE;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::SRC1_COLOR:
|
|
|
|
|
+ out = GL_SRC1_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_SRC1_COLOR:
|
|
|
|
|
+ out = GL_ONE_MINUS_SRC1_COLOR;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::SRC1_ALPHA:
|
|
|
|
|
+ out = GL_SRC1_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendMethod::ONE_MINUS_SRC1_ALPHA:
|
|
|
|
|
+ out = GL_ONE_MINUS_SRC1_ALPHA;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ ANKI_ASSERT(0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return out;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
Error PipelineImpl::create(const Initializer& init)
|
|
Error PipelineImpl::create(const Initializer& init)
|
|
|
|
|
+{
|
|
|
|
|
+ static_cast<Initializer&>(*this) = init;
|
|
|
|
|
+
|
|
|
|
|
+ // Check if complete
|
|
|
|
|
+ m_complete = true;
|
|
|
|
|
+
|
|
|
|
|
+ if(m_templatePipeline.isCreated())
|
|
|
|
|
+ {
|
|
|
|
|
+ // If there is a template it should always be complete
|
|
|
|
|
+ SubStateBit mask =
|
|
|
|
|
+ m_definedState | m_templatePipeline.get().m_definedState;
|
|
|
|
|
+ ANKI_ASSERT(mask == SubStateBit::ALL);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if(m_definedState != SubStateBit::ALL)
|
|
|
|
|
+ {
|
|
|
|
|
+ m_complete = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ANKI_CHECK(createGlPipeline());
|
|
|
|
|
+ initVertexState();
|
|
|
|
|
+ initInputAssemblerState();
|
|
|
|
|
+ initRasterizerState();
|
|
|
|
|
+ initDepthStencilState();
|
|
|
|
|
+ initColorState();
|
|
|
|
|
+
|
|
|
|
|
+ return ErrorCode::NONE;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::destroy()
|
|
|
|
|
+{
|
|
|
|
|
+ if(m_glName)
|
|
|
|
|
+ {
|
|
|
|
|
+ glDeleteProgramPipelines(1, &m_glName);
|
|
|
|
|
+ m_glName = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Error PipelineImpl::createGlPipeline()
|
|
|
{
|
|
{
|
|
|
Error err = ErrorCode::NONE;
|
|
Error err = ErrorCode::NONE;
|
|
|
|
|
|
|
|
- attachProgramsInternal(init);
|
|
|
|
|
|
|
+ // Do checks
|
|
|
|
|
+ U mask = 0;
|
|
|
|
|
+ U count = 6;
|
|
|
|
|
+ while(count-- != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ const ShaderHandle& shader = m_shaders[count];
|
|
|
|
|
+ if(shader.isCreated())
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(count == enumToType(shader.get().getType()));
|
|
|
|
|
+ mask |= 1 << count;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(mask & (1 << 5))
|
|
|
|
|
+ {
|
|
|
|
|
+ // Is compute
|
|
|
|
|
+
|
|
|
|
|
+ ANKI_ASSERT((mask & (1 << 5)) == (1 << 5)
|
|
|
|
|
+ && "Compute should be alone in the pipeline");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ const U fragVert = (1 << 0) | (1 << 4);
|
|
|
|
|
+ ANKI_ASSERT((mask & fragVert) && "Should contain vert and frag");
|
|
|
|
|
+ (void)fragVert;
|
|
|
|
|
+
|
|
|
|
|
+ const U tess = (1 << 1) | (1 << 2);
|
|
|
|
|
+ if((mask & tess) != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(((mask & tess) == 0x6)
|
|
|
|
|
+ && "Should set both the tessellation shaders");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// Create and attach programs
|
|
// Create and attach programs
|
|
|
glGenProgramPipelines(1, &m_glName);
|
|
glGenProgramPipelines(1, &m_glName);
|
|
@@ -83,60 +228,336 @@ Error PipelineImpl::create(const Initializer& init)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void PipelineImpl::destroy()
|
|
|
|
|
|
|
+void PipelineImpl::bind()
|
|
|
{
|
|
{
|
|
|
- if(m_glName)
|
|
|
|
|
|
|
+#if 1
|
|
|
|
|
+ ANKI_ASSERT(isCreated());
|
|
|
|
|
+ glBindProgramPipeline(m_glName);
|
|
|
|
|
+#else
|
|
|
|
|
+ ANKI_ASSERT(m_complete && "Should be complete");
|
|
|
|
|
+
|
|
|
|
|
+ // Get last pipeline
|
|
|
|
|
+ auto& state =
|
|
|
|
|
+ getManager().getImplementation().getRenderingThread().getState();
|
|
|
|
|
+
|
|
|
|
|
+ const PipelineImpl* last = nullptr;
|
|
|
|
|
+ const PipelineImpl* lastTempl = nullptr;
|
|
|
|
|
+ if(state.m_lastPipeline.isCreated())
|
|
|
{
|
|
{
|
|
|
- glDeleteProgramPipelines(1, &m_glName);
|
|
|
|
|
- m_glName = 0;
|
|
|
|
|
|
|
+ last = &state.m_lastPipeline.get();
|
|
|
|
|
+
|
|
|
|
|
+ if(last->m_templatePipeline.isCreated())
|
|
|
|
|
+ {
|
|
|
|
|
+ lastTempl = &last->m_templatePipeline.get();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /*if(!lastPpline.isCreated() || !templPpline.isCreated())
|
|
|
|
|
+ {
|
|
|
|
|
+ // Bind state
|
|
|
|
|
+ }*/
|
|
|
|
|
+#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void PipelineImpl::attachProgramsInternal(const Initializer& init)
|
|
|
|
|
|
|
+void PipelineImpl::initVertexState()
|
|
|
{
|
|
{
|
|
|
- U mask = 0;
|
|
|
|
|
- U count = 6;
|
|
|
|
|
- while(count-- != 0)
|
|
|
|
|
|
|
+ for(U i = 0; i < m_vertex.m_attributeCount; ++i)
|
|
|
{
|
|
{
|
|
|
- const ShaderHandle& shader = init.m_shaders[count];
|
|
|
|
|
- if(shader.isCreated())
|
|
|
|
|
|
|
+ const VertexAttributeBinding& binding = m_vertex.m_attributes[i];
|
|
|
|
|
+ ANKI_ASSERT(binding.m_format.m_srgb == false);
|
|
|
|
|
+ Attribute& cache = m_attribs[i];
|
|
|
|
|
+
|
|
|
|
|
+ // Component count
|
|
|
|
|
+ if(binding.m_format == PixelFormat(
|
|
|
|
|
+ ComponentFormat::R32G32, TransformFormat::FLOAT))
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(count == enumToType(shader.get().getType()));
|
|
|
|
|
- m_shaders[count] = shader;
|
|
|
|
|
- mask |= 1 << count;
|
|
|
|
|
|
|
+ cache.m_compCount = 2;
|
|
|
|
|
+ cache.m_type = GL_FLOAT;
|
|
|
|
|
+ cache.m_normalized = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if(binding.m_format == PixelFormat(
|
|
|
|
|
+ ComponentFormat::R32G32B32, TransformFormat::FLOAT))
|
|
|
|
|
+ {
|
|
|
|
|
+ cache.m_compCount = 3;
|
|
|
|
|
+ cache.m_type = GL_FLOAT;
|
|
|
|
|
+ cache.m_normalized = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if(binding.m_format == PixelFormat(
|
|
|
|
|
+ ComponentFormat::R10G10B10A2, TransformFormat::SNORM))
|
|
|
|
|
+ {
|
|
|
|
|
+ cache.m_compCount = 4;
|
|
|
|
|
+ cache.m_type = GL_INT_2_10_10_10_REV;
|
|
|
|
|
+ cache.m_normalized = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(0 && "TODO");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Check what we attached
|
|
|
|
|
- //
|
|
|
|
|
- if(mask & (1 << 5))
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::initInputAssemblerState()
|
|
|
|
|
+{
|
|
|
|
|
+ switch(m_inputAssembler.m_topology)
|
|
|
{
|
|
{
|
|
|
- // Is compute
|
|
|
|
|
|
|
+ case POINTS:
|
|
|
|
|
+ m_topology = GL_POINTS;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case LINES:
|
|
|
|
|
+ m_topology = GL_LINES;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case LINE_STIP:
|
|
|
|
|
+ m_topology = GL_LINE_STRIP;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case TRIANGLES:
|
|
|
|
|
+ m_topology = GL_TRIANGLES;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case TRIANGLE_STRIP:
|
|
|
|
|
+ m_topology = GL_TRIANGLE_STRIP;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case PATCHES:
|
|
|
|
|
+ m_topology = GL_PATCHES;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ ANKI_ASSERT(0);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- ANKI_ASSERT((mask & (1 << 5)) == (1 << 5)
|
|
|
|
|
- && "Compute should be alone in the pipeline");
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::initRasterizerState()
|
|
|
|
|
+{
|
|
|
|
|
+ switch(m_rasterizer.m_fillMode)
|
|
|
|
|
+ {
|
|
|
|
|
+ case FillMode::POINTS:
|
|
|
|
|
+ m_fillMode = GL_POINT;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case FillMode::WIREFRAME:
|
|
|
|
|
+ m_fillMode = GL_LINE;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case FillMode::SOLID:
|
|
|
|
|
+ m_fillMode = GL_FILL;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ ANKI_ASSERT(0);
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+
|
|
|
|
|
+ switch(m_rasterizer.m_cullMode)
|
|
|
{
|
|
{
|
|
|
- const U fragVert = (1 << 0) | (1 << 4);
|
|
|
|
|
- ANKI_ASSERT((mask & fragVert) && "Should contain vert and frag");
|
|
|
|
|
- (void)fragVert;
|
|
|
|
|
|
|
+ case CullMode::FRONT:
|
|
|
|
|
+ m_cullMode = GL_FRONT;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case CullMode::BACK:
|
|
|
|
|
+ m_cullMode = GL_BACK;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case CullMode::FRONT_AND_BACK:
|
|
|
|
|
+ m_cullMode = GL_FRONT_AND_BACK;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ ANKI_ASSERT(0);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- const U tess = (1 << 1) | (1 << 2);
|
|
|
|
|
- if((mask & tess) != 0)
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::initDepthStencilState()
|
|
|
|
|
+{
|
|
|
|
|
+ switch(m_depthStencil.m_depthCompareFunction)
|
|
|
|
|
+ {
|
|
|
|
|
+ case DepthCompareFunction::ALWAYS:
|
|
|
|
|
+ m_depthCompareFunction = GL_ALWAYS;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DepthCompareFunction::LESS:
|
|
|
|
|
+ m_depthCompareFunction = GL_LESS;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DepthCompareFunction::LESS_EQUAL:
|
|
|
|
|
+ m_depthCompareFunction = GL_LEQUAL;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DepthCompareFunction::GREATER:
|
|
|
|
|
+ m_depthCompareFunction = GL_GREATER;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DepthCompareFunction::GREATER_EQUAL:
|
|
|
|
|
+ m_depthCompareFunction = GL_GEQUAL;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DepthCompareFunction::NOT_EQUAL:
|
|
|
|
|
+ m_depthCompareFunction = GL_NOTEQUAL;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DepthCompareFunction::NEVER:
|
|
|
|
|
+ m_depthCompareFunction = GL_NEVER;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ ANKI_ASSERT(0);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::initColorState()
|
|
|
|
|
+{
|
|
|
|
|
+ for(U i = 0; i < m_color.m_colorAttachmentsCount; ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ Attachment& out = m_attachments[i];
|
|
|
|
|
+ const ColorAttachmentStateInfo& in = m_color.m_attachments[i];
|
|
|
|
|
+
|
|
|
|
|
+ out.m_srcBlendMethod = convertBlendMethod(in.m_srcBlendMethod);
|
|
|
|
|
+ out.m_dstBlendMethod = convertBlendMethod(in.m_dstBlendMethod);
|
|
|
|
|
+
|
|
|
|
|
+ switch(in.m_blendFunction)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(((mask & tess) == 0x6)
|
|
|
|
|
- && "Should set both the tessellation shaders");
|
|
|
|
|
|
|
+ case BlendFunction::ADD:
|
|
|
|
|
+ out.m_blendFunction = GL_FUNC_ADD;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendFunction::SUBTRACT:
|
|
|
|
|
+ out.m_blendFunction = GL_FUNC_SUBTRACT;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendFunction::REVERSE_SUBTRACT:
|
|
|
|
|
+ out.m_blendFunction = GL_FUNC_REVERSE_SUBTRACT;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendFunction::MIN:
|
|
|
|
|
+ out.m_blendFunction = GL_MIN;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case BlendFunction::MAX:
|
|
|
|
|
+ out.m_blendFunction = GL_MAX;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ ANKI_ASSERT(0);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ out.m_channelWriteMask[0] = in.m_channelWriteMask | ColorBit::RED;
|
|
|
|
|
+ out.m_channelWriteMask[1] = in.m_channelWriteMask | ColorBit::GREEN;
|
|
|
|
|
+ out.m_channelWriteMask[2] = in.m_channelWriteMask | ColorBit::BLUE;
|
|
|
|
|
+ out.m_channelWriteMask[3] = in.m_channelWriteMask | ColorBit::ALPHA;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void PipelineImpl::bind()
|
|
|
|
|
|
|
+void PipelineImpl::setVertexState(GlState&)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(isCreated());
|
|
|
|
|
- glBindProgramPipeline(m_glName);
|
|
|
|
|
|
|
+ for(U i = 0; i < m_vertex.m_attributeCount; ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ const Attribute& attrib = m_attribs[i];
|
|
|
|
|
+ ANKI_ASSERT(attrib.m_type);
|
|
|
|
|
+ glVertexAttribFormat(i, attrib.m_compCount, attrib.m_type,
|
|
|
|
|
+ attrib.m_normalized, m_vertex.m_attributes[i].m_offset);
|
|
|
|
|
+
|
|
|
|
|
+ glVertexAttribBinding(i, m_vertex.m_attributes[i].m_binding);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::setInputAssemblerState(GlState& state)
|
|
|
|
|
+{
|
|
|
|
|
+ if(m_inputAssembler.m_primitiveRestartEnabled
|
|
|
|
|
+ != state.m_primitiveRestartEnabled)
|
|
|
|
|
+ {
|
|
|
|
|
+ if(m_inputAssembler.m_primitiveRestartEnabled)
|
|
|
|
|
+ {
|
|
|
|
|
+ glEnable(GL_PRIMITIVE_RESTART);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ glDisable(GL_PRIMITIVE_RESTART);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ state.m_primitiveRestartEnabled =
|
|
|
|
|
+ m_inputAssembler.m_primitiveRestartEnabled;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ state.m_topology = m_topology;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::setTessellationState(GlState& state)
|
|
|
|
|
+{
|
|
|
|
|
+ if(m_tessellation.m_patchControlPointsCount
|
|
|
|
|
+ != state.m_patchControlPointsCount)
|
|
|
|
|
+ {
|
|
|
|
|
+ glPatchParameteri(GL_PATCH_VERTICES,
|
|
|
|
|
+ m_tessellation.m_patchControlPointsCount);
|
|
|
|
|
+
|
|
|
|
|
+ state.m_patchControlPointsCount =
|
|
|
|
|
+ m_tessellation.m_patchControlPointsCount;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::setRasterizerState(GlState& state)
|
|
|
|
|
+{
|
|
|
|
|
+ if(m_fillMode != state.m_fillMode)
|
|
|
|
|
+ {
|
|
|
|
|
+ glPolygonMode(GL_FRONT_AND_BACK, m_fillMode);
|
|
|
|
|
+ state.m_fillMode = m_fillMode;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(m_cullMode != state.m_cullMode)
|
|
|
|
|
+ {
|
|
|
|
|
+ glCullFace(m_cullMode);
|
|
|
|
|
+ state.m_cullMode = m_cullMode;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::setDepthStencilState(GlState& state)
|
|
|
|
|
+{
|
|
|
|
|
+ if(m_depthCompareFunction != state.m_depthCompareFunction)
|
|
|
|
|
+ {
|
|
|
|
|
+ if(m_depthCompareFunction == GL_ALWAYS)
|
|
|
|
|
+ {
|
|
|
|
|
+ glDisable(GL_DEPTH_TEST);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ glEnable(GL_DEPTH_TEST);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ glDepthFunc(m_depthCompareFunction);
|
|
|
|
|
+
|
|
|
|
|
+ state.m_depthCompareFunction = m_depthCompareFunction;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void PipelineImpl::setColorState(GlState&)
|
|
|
|
|
+{
|
|
|
|
|
+ for(U i = 0; i < m_color.m_colorAttachmentsCount; ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ const Attachment& att = m_attachments[i];
|
|
|
|
|
+
|
|
|
|
|
+ glBlendFunci(i, att.m_srcBlendMethod, att.m_dstBlendMethod);
|
|
|
|
|
+ glBlendEquationi(i, att.m_blendFunction);
|
|
|
|
|
+ glColorMaski(i, att.m_channelWriteMask[0], att.m_channelWriteMask[1],
|
|
|
|
|
+ att.m_channelWriteMask[2], att.m_channelWriteMask[3]);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+const PipelineImpl* getPipelineForState(const SubStateBit bit) const
|
|
|
|
|
+{
|
|
|
|
|
+ PipelineImpl* out = this;
|
|
|
|
|
+
|
|
|
|
|
+ if(m_templatePipeline.isCreated() && !(m_definedState | bit))
|
|
|
|
|
+ {
|
|
|
|
|
+ // Template pipeline has the defined state
|
|
|
|
|
+ out = &m_templatePipeline.get();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return out;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+const PipelineImpl* PipelineImpl::chosePipelineForState(
|
|
|
|
|
+ const SubStateBit bit, const PipelineImpl& crntBoundPipeline) const
|
|
|
|
|
+{
|
|
|
|
|
+ const PipelineImpl* out = nullptr;
|
|
|
|
|
+
|
|
|
|
|
+ // Get previously bound pipeline template
|
|
|
|
|
+ const PipelineImpl* last = nullptr;
|
|
|
|
|
+ if(crntBoundPipeline.m_templatePipeline.isCreated()
|
|
|
|
|
+ && !(crntBoundPipeline.m_definedState | bit))
|
|
|
|
|
+ {
|
|
|
|
|
+ last = &crntBoundPipeline.m_templatePipeline.get();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(last)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // end namespace anki
|
|
} // end namespace anki
|