mirror of
https://github.com/libretro/Play-.git
synced 2024-12-11 18:54:11 +00:00
Added CopyToFb function.
Replaces glBlitFramebuffer for multisampled framebuffers.
This commit is contained in:
parent
bb2dcf45c0
commit
f065965d4f
@ -8,6 +8,7 @@
|
|||||||
#include "GSH_OpenGL.h"
|
#include "GSH_OpenGL.h"
|
||||||
|
|
||||||
#define NUM_SAMPLES 8
|
#define NUM_SAMPLES 8
|
||||||
|
//#define USE_COPYTOFB
|
||||||
|
|
||||||
GLenum CGSH_OpenGL::g_nativeClampModes[CGSHandler::CLAMP_MODE_MAX] =
|
GLenum CGSH_OpenGL::g_nativeClampModes[CGSHandler::CLAMP_MODE_MAX] =
|
||||||
{
|
{
|
||||||
@ -78,10 +79,13 @@ void CGSH_OpenGL::ReleaseImpl()
|
|||||||
m_presentProgram.reset();
|
m_presentProgram.reset();
|
||||||
m_presentVertexBuffer.Reset();
|
m_presentVertexBuffer.Reset();
|
||||||
m_presentVertexArray.Reset();
|
m_presentVertexArray.Reset();
|
||||||
|
m_copyToFbProgram.reset();
|
||||||
|
m_copyToFbFramebuffer.Reset();
|
||||||
|
m_copyToFbTexture.Reset();
|
||||||
|
m_copyToFbVertexBuffer.Reset();
|
||||||
|
m_copyToFbVertexArray.Reset();
|
||||||
m_primBuffer.Reset();
|
m_primBuffer.Reset();
|
||||||
m_primVertexArray.Reset();
|
m_primVertexArray.Reset();
|
||||||
m_copyToFbTexture.Reset();
|
|
||||||
m_copyToFbFramebuffer.Reset();
|
|
||||||
m_vertexParamsBuffer.Reset();
|
m_vertexParamsBuffer.Reset();
|
||||||
m_fragmentParamsBuffer.Reset();
|
m_fragmentParamsBuffer.Reset();
|
||||||
}
|
}
|
||||||
@ -312,8 +316,13 @@ void CGSH_OpenGL::InitializeRC()
|
|||||||
m_presentTextureUniform = glGetUniformLocation(*m_presentProgram, "g_texture");
|
m_presentTextureUniform = glGetUniformLocation(*m_presentProgram, "g_texture");
|
||||||
m_presentTexCoordScaleUniform = glGetUniformLocation(*m_presentProgram, "g_texCoordScale");
|
m_presentTexCoordScaleUniform = glGetUniformLocation(*m_presentProgram, "g_texCoordScale");
|
||||||
|
|
||||||
|
m_copyToFbProgram = GenerateCopyToFbProgram();
|
||||||
m_copyToFbTexture = Framework::OpenGl::CTexture::Create();
|
m_copyToFbTexture = Framework::OpenGl::CTexture::Create();
|
||||||
m_copyToFbFramebuffer = Framework::OpenGl::CFramebuffer::Create();
|
m_copyToFbFramebuffer = Framework::OpenGl::CFramebuffer::Create();
|
||||||
|
m_copyToFbVertexBuffer = GenerateCopyToFbVertexBuffer();
|
||||||
|
m_copyToFbVertexArray = GenerateCopyToFbVertexArray();
|
||||||
|
m_copyToFbSrcPositionUniform = glGetUniformLocation(*m_copyToFbProgram, "g_srcPosition");
|
||||||
|
m_copyToFbSrcSizeUniform = glGetUniformLocation(*m_copyToFbProgram, "g_srcSize");
|
||||||
|
|
||||||
m_primBuffer = Framework::OpenGl::CBuffer::Create();
|
m_primBuffer = Framework::OpenGl::CBuffer::Create();
|
||||||
m_primVertexArray = GeneratePrimVertexArray();
|
m_primVertexArray = GeneratePrimVertexArray();
|
||||||
@ -371,6 +380,52 @@ Framework::OpenGl::CVertexArray CGSH_OpenGL::GeneratePresentVertexArray()
|
|||||||
return vertexArray;
|
return vertexArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Framework::OpenGl::CBuffer CGSH_OpenGL::GenerateCopyToFbVertexBuffer()
|
||||||
|
{
|
||||||
|
auto buffer = Framework::OpenGl::CBuffer::Create();
|
||||||
|
|
||||||
|
static const float bufferContents[] =
|
||||||
|
{
|
||||||
|
//Pos UV
|
||||||
|
-1.0f, -1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, -1.0f, 1.0f, 0.0f,
|
||||||
|
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||||
|
1.0f, 1.0f, 1.0f, 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(bufferContents), bufferContents, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
CHECKGLERROR();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Framework::OpenGl::CVertexArray CGSH_OpenGL::GenerateCopyToFbVertexArray()
|
||||||
|
{
|
||||||
|
auto vertexArray = Framework::OpenGl::CVertexArray::Create();
|
||||||
|
|
||||||
|
glBindVertexArray(vertexArray);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_copyToFbVertexBuffer);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(static_cast<GLuint>(PRIM_VERTEX_ATTRIB::POSITION));
|
||||||
|
glVertexAttribPointer(static_cast<GLuint>(PRIM_VERTEX_ATTRIB::POSITION), 2, GL_FLOAT,
|
||||||
|
GL_FALSE, sizeof(float) * 4, reinterpret_cast<const GLvoid*>(0));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(static_cast<GLuint>(PRIM_VERTEX_ATTRIB::TEXCOORD));
|
||||||
|
glVertexAttribPointer(static_cast<GLuint>(PRIM_VERTEX_ATTRIB::TEXCOORD), 2, GL_FLOAT,
|
||||||
|
GL_FALSE, sizeof(float) * 4, reinterpret_cast<const GLvoid*>(8));
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
CHECKGLERROR();
|
||||||
|
|
||||||
|
return vertexArray;
|
||||||
|
}
|
||||||
|
|
||||||
Framework::OpenGl::CVertexArray CGSH_OpenGL::GeneratePrimVertexArray()
|
Framework::OpenGl::CVertexArray CGSH_OpenGL::GeneratePrimVertexArray()
|
||||||
{
|
{
|
||||||
auto vertexArray = Framework::OpenGl::CVertexArray::Create();
|
auto vertexArray = Framework::OpenGl::CVertexArray::Create();
|
||||||
@ -1647,6 +1702,47 @@ void CGSH_OpenGL::DrawToDepth(unsigned int primitiveType, uint64 primReg)
|
|||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGSH_OpenGL::CopyToFb(
|
||||||
|
int32 srcX0, int32 srcY0, int32 srcX1, int32 srcY1,
|
||||||
|
int32 srcWidth, int32 srcHeight,
|
||||||
|
int32 dstX0, int32 dstY0, int32 dstX1, int32 dstY1)
|
||||||
|
{
|
||||||
|
m_validGlState &= ~(GLSTATE_BLEND | GLSTATE_COLORMASK | GLSTATE_SCISSOR | GLSTATE_PROGRAM);
|
||||||
|
m_validGlState &= ~(GLSTATE_VIEWPORT);
|
||||||
|
|
||||||
|
assert(srcX1 >= srcX0);
|
||||||
|
assert(srcY1 >= srcY0);
|
||||||
|
assert(dstX1 >= dstX0);
|
||||||
|
assert(dstY1 >= dstY0);
|
||||||
|
|
||||||
|
float positionX = static_cast<float>(srcX0) / static_cast<float>(srcWidth);
|
||||||
|
float positionY = static_cast<float>(srcY0) / static_cast<float>(srcHeight);
|
||||||
|
float sizeX = static_cast<float>(srcX1 - srcX0) / static_cast<float>(srcWidth);
|
||||||
|
float sizeY = static_cast<float>(srcY1 - srcY0) / static_cast<float>(srcHeight);
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
|
||||||
|
glUseProgram(*m_copyToFbProgram);
|
||||||
|
|
||||||
|
glUniform2f(m_copyToFbSrcPositionUniform, positionX, positionY);
|
||||||
|
glUniform2f(m_copyToFbSrcSizeUniform, sizeX, sizeY);
|
||||||
|
glViewport(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_copyToFbVertexBuffer);
|
||||||
|
glBindVertexArray(m_copyToFbVertexArray);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
m_copyToFbProgram->Validate();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
CHECKGLERROR();
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
||||||
// Other Functions
|
// Other Functions
|
||||||
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
||||||
@ -2004,6 +2100,10 @@ void CGSH_OpenGL::PopulateFramebuffer(const FramebufferPtr& framebuffer)
|
|||||||
{
|
{
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, m_copyToFbTexture);
|
glBindTexture(GL_TEXTURE_2D, m_copyToFbTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
((this)->*(m_textureUploader[framebuffer->m_psm]))(framebuffer->m_basePtr,
|
((this)->*(m_textureUploader[framebuffer->m_psm]))(framebuffer->m_basePtr,
|
||||||
framebuffer->m_width / 64, framebuffer->m_width, framebuffer->m_height);
|
framebuffer->m_width / 64, framebuffer->m_width, framebuffer->m_height);
|
||||||
CHECKGLERROR();
|
CHECKGLERROR();
|
||||||
@ -2015,6 +2115,8 @@ void CGSH_OpenGL::PopulateFramebuffer(const FramebufferPtr& framebuffer)
|
|||||||
CHECKGLERROR();
|
CHECKGLERROR();
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->m_framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->m_framebuffer);
|
||||||
|
|
||||||
|
#ifndef USE_COPYTOFB
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_copyToFbFramebuffer);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_copyToFbFramebuffer);
|
||||||
|
|
||||||
//Copy buffers
|
//Copy buffers
|
||||||
@ -2022,9 +2124,16 @@ void CGSH_OpenGL::PopulateFramebuffer(const FramebufferPtr& framebuffer)
|
|||||||
0, 0, framebuffer->m_width, framebuffer->m_height,
|
0, 0, framebuffer->m_width, framebuffer->m_height,
|
||||||
0, 0, framebuffer->m_width * m_fbScale, framebuffer->m_height * m_fbScale,
|
0, 0, framebuffer->m_width * m_fbScale, framebuffer->m_height * m_fbScale,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
CHECKGLERROR();
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
#else
|
||||||
|
CopyToFb(
|
||||||
|
0, 0, framebuffer->m_width, framebuffer->m_height,
|
||||||
|
framebuffer->m_width, framebuffer->m_height,
|
||||||
|
0, 0, framebuffer->m_width, framebuffer->m_height);
|
||||||
|
framebuffer->m_resolveNeeded = true;
|
||||||
|
#endif
|
||||||
|
CHECKGLERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGSH_OpenGL::CommitFramebufferDirtyPages(const FramebufferPtr& framebuffer, unsigned int minY, unsigned int maxY)
|
void CGSH_OpenGL::CommitFramebufferDirtyPages(const FramebufferPtr& framebuffer, unsigned int minY, unsigned int maxY)
|
||||||
@ -2047,6 +2156,10 @@ void CGSH_OpenGL::CommitFramebufferDirtyPages(const FramebufferPtr& framebuffer,
|
|||||||
glBindTexture(GL_TEXTURE_2D, copyToFbTexture);
|
glBindTexture(GL_TEXTURE_2D, copyToFbTexture);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, framebuffer->m_width, framebuffer->m_height,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, framebuffer->m_width, framebuffer->m_height,
|
||||||
0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, copyToFbFramebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, copyToFbFramebuffer);
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyToFbTexture, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyToFbTexture, 0);
|
||||||
@ -2104,10 +2217,18 @@ void CGSH_OpenGL::CommitFramebufferDirtyPages(const FramebufferPtr& framebuffer,
|
|||||||
((this)->*(m_textureUpdater[framebuffer->m_psm]))(framebuffer->m_basePtr, framebuffer->m_width / 64,
|
((this)->*(m_textureUpdater[framebuffer->m_psm]))(framebuffer->m_basePtr, framebuffer->m_width / 64,
|
||||||
texX, texY, texWidth, texHeight);
|
texX, texY, texWidth, texHeight);
|
||||||
|
|
||||||
|
#ifndef USE_COPYTOFB
|
||||||
glBlitFramebuffer(
|
glBlitFramebuffer(
|
||||||
texX, texY, (texX + texWidth), (texY + texHeight),
|
texX, texY, (texX + texWidth), (texY + texHeight),
|
||||||
texX * m_fbScale, texY * m_fbScale, (texX + texWidth) * m_fbScale, (texY + texHeight) * m_fbScale,
|
texX * m_fbScale, texY * m_fbScale, (texX + texWidth) * m_fbScale, (texY + texHeight) * m_fbScale,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
|
#else
|
||||||
|
CopyToFb(
|
||||||
|
texX, texY, (texX + texWidth), (texY + texHeight),
|
||||||
|
framebuffer->m_width, framebuffer->m_height,
|
||||||
|
texX * m_fbScale, texY * m_fbScale, (texX + texWidth) * m_fbScale, (texY + texHeight) * m_fbScale);
|
||||||
|
framebuffer->m_resolveNeeded = true;
|
||||||
|
#endif
|
||||||
CHECKGLERROR();
|
CHECKGLERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +288,11 @@ private:
|
|||||||
Framework::OpenGl::ProgramPtr GeneratePresentProgram();
|
Framework::OpenGl::ProgramPtr GeneratePresentProgram();
|
||||||
Framework::OpenGl::CBuffer GeneratePresentVertexBuffer();
|
Framework::OpenGl::CBuffer GeneratePresentVertexBuffer();
|
||||||
Framework::OpenGl::CVertexArray GeneratePresentVertexArray();
|
Framework::OpenGl::CVertexArray GeneratePresentVertexArray();
|
||||||
|
|
||||||
|
Framework::OpenGl::ProgramPtr GenerateCopyToFbProgram();
|
||||||
|
Framework::OpenGl::CBuffer GenerateCopyToFbVertexBuffer();
|
||||||
|
Framework::OpenGl::CVertexArray GenerateCopyToFbVertexArray();
|
||||||
|
|
||||||
Framework::OpenGl::CVertexArray GeneratePrimVertexArray();
|
Framework::OpenGl::CVertexArray GeneratePrimVertexArray();
|
||||||
Framework::OpenGl::CBuffer GenerateUniformBlockBuffer(size_t);
|
Framework::OpenGl::CBuffer GenerateUniformBlockBuffer(size_t);
|
||||||
|
|
||||||
@ -298,6 +303,7 @@ private:
|
|||||||
|
|
||||||
void FlushVertexBuffer();
|
void FlushVertexBuffer();
|
||||||
|
|
||||||
|
void CopyToFb(int32, int32, int32, int32, int32, int32, int32, int32, int32, int32);
|
||||||
void DrawToDepth(unsigned int, uint64);
|
void DrawToDepth(unsigned int, uint64);
|
||||||
|
|
||||||
void SetRenderingContext(uint64);
|
void SetRenderingContext(uint64);
|
||||||
@ -369,8 +375,13 @@ private:
|
|||||||
GLint m_presentTextureUniform = -1;
|
GLint m_presentTextureUniform = -1;
|
||||||
GLint m_presentTexCoordScaleUniform = -1;
|
GLint m_presentTexCoordScaleUniform = -1;
|
||||||
|
|
||||||
|
Framework::OpenGl::ProgramPtr m_copyToFbProgram;
|
||||||
Framework::OpenGl::CFramebuffer m_copyToFbFramebuffer;
|
Framework::OpenGl::CFramebuffer m_copyToFbFramebuffer;
|
||||||
Framework::OpenGl::CTexture m_copyToFbTexture;
|
Framework::OpenGl::CTexture m_copyToFbTexture;
|
||||||
|
Framework::OpenGl::CBuffer m_copyToFbVertexBuffer;
|
||||||
|
Framework::OpenGl::CVertexArray m_copyToFbVertexArray;
|
||||||
|
GLint m_copyToFbSrcPositionUniform = -1;
|
||||||
|
GLint m_copyToFbSrcSizeUniform = -1;
|
||||||
|
|
||||||
TextureList m_textureCache;
|
TextureList m_textureCache;
|
||||||
PaletteList m_paletteCache;
|
PaletteList m_paletteCache;
|
||||||
|
@ -446,3 +446,60 @@ Framework::OpenGl::ProgramPtr CGSH_OpenGL::GeneratePresentProgram()
|
|||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Framework::OpenGl::ProgramPtr CGSH_OpenGL::GenerateCopyToFbProgram()
|
||||||
|
{
|
||||||
|
Framework::OpenGl::CShader vertexShader(GL_VERTEX_SHADER);
|
||||||
|
Framework::OpenGl::CShader pixelShader(GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::stringstream shaderBuilder;
|
||||||
|
shaderBuilder << GLSL_VERSION << std::endl;
|
||||||
|
shaderBuilder << "in vec2 a_position;" << std::endl;
|
||||||
|
shaderBuilder << "in vec2 a_texCoord;" << std::endl;
|
||||||
|
shaderBuilder << "out vec2 v_texCoord;" << std::endl;
|
||||||
|
shaderBuilder << "uniform vec2 g_srcPosition;" << std::endl;
|
||||||
|
shaderBuilder << "uniform vec2 g_srcSize;" << std::endl;
|
||||||
|
shaderBuilder << "void main()" << std::endl;
|
||||||
|
shaderBuilder << "{" << std::endl;
|
||||||
|
shaderBuilder << " v_texCoord = (a_texCoord * g_srcSize) + g_srcPosition;" << std::endl;
|
||||||
|
shaderBuilder << " gl_Position = vec4(a_position, 0, 1);" << std::endl;
|
||||||
|
shaderBuilder << "}" << std::endl;
|
||||||
|
|
||||||
|
vertexShader.SetSource(shaderBuilder.str().c_str());
|
||||||
|
bool result = vertexShader.Compile();
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::stringstream shaderBuilder;
|
||||||
|
shaderBuilder << GLSL_VERSION << std::endl;
|
||||||
|
shaderBuilder << "precision mediump float;" << std::endl;
|
||||||
|
shaderBuilder << "in vec2 v_texCoord;" << std::endl;
|
||||||
|
shaderBuilder << "out vec4 fragColor;" << std::endl;
|
||||||
|
shaderBuilder << "uniform sampler2D g_texture;" << std::endl;
|
||||||
|
shaderBuilder << "void main()" << std::endl;
|
||||||
|
shaderBuilder << "{" << std::endl;
|
||||||
|
shaderBuilder << " fragColor = texture(g_texture, v_texCoord);" << std::endl;
|
||||||
|
shaderBuilder << "}" << std::endl;
|
||||||
|
|
||||||
|
pixelShader.SetSource(shaderBuilder.str().c_str());
|
||||||
|
bool result = pixelShader.Compile();
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto program = std::make_shared<Framework::OpenGl::CProgram>();
|
||||||
|
|
||||||
|
{
|
||||||
|
program->AttachShader(vertexShader);
|
||||||
|
program->AttachShader(pixelShader);
|
||||||
|
|
||||||
|
glBindAttribLocation(*program, static_cast<GLuint>(PRIM_VERTEX_ATTRIB::POSITION), "a_position");
|
||||||
|
glBindAttribLocation(*program, static_cast<GLuint>(PRIM_VERTEX_ATTRIB::TEXCOORD), "a_texCoord");
|
||||||
|
|
||||||
|
bool result = program->Link();
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user