mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Feat] (MG_Backend/DirectVulkan): move demo pipeline creation to gl side
This commit is contained in:
@@ -83,6 +83,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
payload.drawArray.mode = mode;
|
payload.drawArray.mode = mode;
|
||||||
payload.drawArray.first = 0;
|
payload.drawArray.first = 0;
|
||||||
payload.drawArray.count = count;
|
payload.drawArray.count = count;
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
payload.drawArray.vertexArray = vao.get();
|
payload.drawArray.vertexArray = vao.get();
|
||||||
payload.indexType = type;
|
payload.indexType = type;
|
||||||
payload.indexData = indexData->data() + byteOffset;
|
payload.indexData = indexData->data() + byteOffset;
|
||||||
@@ -142,6 +144,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
payload.mode = mode;
|
payload.mode = mode;
|
||||||
payload.first = first;
|
payload.first = first;
|
||||||
payload.count = count;
|
payload.count = count;
|
||||||
|
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||||
|
payload.program = currentProgram ? currentProgram.get() : nullptr;
|
||||||
|
|
||||||
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||||
payload.vertexArray = vao ? vao.get() : nullptr;
|
payload.vertexArray = vao ? vao.get() : nullptr;
|
||||||
|
|||||||
@@ -59,27 +59,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* demoFS = R"(#version 460
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
|
||||||
layout(location = 0) out vec4 outColor;
|
|
||||||
void main() {
|
|
||||||
outColor = vec4(fragColor, 1.0);
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
const char* demoVS = R"(#version 460
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
|
||||||
vec2 positions[3] = vec2[](vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5));
|
|
||||||
vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
|
|
||||||
void main() {
|
|
||||||
gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);
|
|
||||||
fragColor = colors[gl_VertexID];
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
VkPipeline VulkanRenderer::GetOrCreatePipeline(
|
VkPipeline VulkanRenderer::GetOrCreatePipeline(
|
||||||
Uint64 programHash, Uint64 vertexInputHash, const VkPipelineVertexInputStateCreateInfo& vertexInputState) {
|
const MG_State::GLState::ProgramObject& program, Uint64 vertexInputHash,
|
||||||
|
const VkPipelineVertexInputStateCreateInfo& vertexInputState) {
|
||||||
MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory is not initialized");
|
MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory is not initialized");
|
||||||
MOBILEGL_ASSERT(!m_demoPipelineStages.empty(), "GetOrCreatePipeline requires shader stages");
|
MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory is not initialized");
|
||||||
|
auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(program, ProgramFactory::CompileOptionBit::None);
|
||||||
|
if (stages.empty()) {
|
||||||
|
MGLOG_W("GetOrCreatePipeline skipped: program has no shader stages");
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
const Uint64 programHash = m_programFactory->ComputeHash(program, ProgramFactory::CompileOptionBit::None);
|
||||||
|
|
||||||
PipelineFactory::PipelineCreatePayload payload{};
|
PipelineFactory::PipelineCreatePayload payload{};
|
||||||
payload.programHash = programHash;
|
payload.programHash = programHash;
|
||||||
@@ -88,52 +78,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
payload.renderPass = m_renderPassLoad;
|
payload.renderPass = m_renderPassLoad;
|
||||||
payload.subpass = 0;
|
payload.subpass = 0;
|
||||||
payload.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
payload.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
payload.stages = &m_demoPipelineStages;
|
payload.stages = &stages;
|
||||||
payload.vertexInputState = &vertexInputState;
|
payload.vertexInputState = &vertexInputState;
|
||||||
return m_pipelineFactory->GetOrCreatePipeline(payload);
|
return m_pipelineFactory->GetOrCreatePipeline(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::PrepareDemoPipeline() {
|
void VulkanRenderer::PrepareDemoPipeline() {
|
||||||
MGLOG_D("PrepareDemoRes called");
|
MGLOG_D("PrepareDemoPipeline called");
|
||||||
|
|
||||||
// Create shader&program object
|
|
||||||
auto programObject = MG_State::GLState::ProgramObject(0);
|
|
||||||
auto vsObject = MakeShared<MG_State::GLState::ShaderObject>(ShaderStage::Vertex, 0);
|
|
||||||
vsObject->SetShaderSource(demoVS);
|
|
||||||
vsObject->Compile();
|
|
||||||
if (!vsObject->GetCompileStatus()) {
|
|
||||||
MGLOG_E("Vertex shader compilation failed: %s", vsObject->GetInfoLog().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto fsObject = MakeShared<MG_State::GLState::ShaderObject>(ShaderStage::Fragment, 1);
|
|
||||||
fsObject->SetShaderSource(demoFS);
|
|
||||||
fsObject->Compile();
|
|
||||||
if (!fsObject->GetCompileStatus()) {
|
|
||||||
MGLOG_E("Fragment shader compilation failed: %s", fsObject->GetInfoLog().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
programObject.AttachShader(vsObject);
|
|
||||||
programObject.AttachShader(fsObject);
|
|
||||||
programObject.Link();
|
|
||||||
if (!programObject.GetLinkStatus()) {
|
|
||||||
MGLOG_E("Program linking failed: %s", programObject.GetInfoLog().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(programObject, ProgramFactory::CompileOptionBit::None);
|
|
||||||
m_demoProgramHash = m_programFactory->ComputeHash(programObject, ProgramFactory::CompileOptionBit::None);
|
|
||||||
m_demoPipelineStages = stages;
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo plci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
VkPipelineLayoutCreateInfo plci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||||
VK_VERIFY(vkCreatePipelineLayout(m_device, &plci, nullptr, &m_pipelineLayout), "vkCreatePipelineLayout");
|
VK_VERIFY(vkCreatePipelineLayout(m_device, &plci, nullptr, &m_pipelineLayout), "vkCreatePipelineLayout");
|
||||||
|
|
||||||
VertexInputStateBuilder vertexInputBuilder;
|
|
||||||
const auto& vertexInput = vertexInputBuilder.Build();
|
|
||||||
m_pipeline = GetOrCreatePipeline(m_demoProgramHash, 0, vertexInput);
|
|
||||||
|
|
||||||
// vkDestroyShaderModule(m_device, vs, nullptr);
|
|
||||||
// vkDestroyShaderModule(m_device, fs, nullptr);
|
|
||||||
|
|
||||||
MGLOG_I("PrepareDemoPipeline completed");
|
MGLOG_I("PrepareDemoPipeline completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,10 +134,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
m_frameContext.Destroy(m_device, m_commandPool);
|
m_frameContext.Destroy(m_device, m_commandPool);
|
||||||
|
|
||||||
m_pipeline = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
if (m_pipelineLayout != VK_NULL_HANDLE) {
|
if (m_pipelineLayout != VK_NULL_HANDLE) {
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
||||||
|
m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownSwapchain();
|
ShutdownSwapchain();
|
||||||
@@ -422,13 +376,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
||||||
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
||||||
|
|
||||||
VkPipeline pipelineToBind = m_pipeline;
|
if (payload.program == nullptr) {
|
||||||
if (vertexInputState) {
|
MGLOG_W("DrawArrays skipped: no current program is bound");
|
||||||
pipelineToBind = GetOrCreatePipeline(m_demoProgramHash, vertexInputState->hash, vertexInputState->state);
|
|
||||||
if (pipelineToBind == VK_NULL_HANDLE) {
|
|
||||||
MGLOG_W("DrawArrays skipped: failed to create/get pipeline variant");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Uint64 vertexInputHash = vertexInputState ? vertexInputState->hash : 0;
|
||||||
|
const VkPipelineVertexInputStateCreateInfo* vertexInputInfo =
|
||||||
|
vertexInputState ? &vertexInputState->state : nullptr;
|
||||||
|
if (!vertexInputInfo) {
|
||||||
|
VertexInputStateBuilder emptyVertexInputBuilder;
|
||||||
|
vertexInputInfo = &emptyVertexInputBuilder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline pipelineToBind = GetOrCreatePipeline(*payload.program, vertexInputHash, *vertexInputInfo);
|
||||||
|
if (pipelineToBind == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_W("DrawArrays skipped: failed to create/get pipeline");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexInputState && !vertexInputState->bindings.empty()) {
|
if (vertexInputState && !vertexInputState->bindings.empty()) {
|
||||||
@@ -526,13 +490,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
vertexInputState = &m_vertexInputStateFactory->GetOrCreateVertexInputState(*payload.drawArray.vertexArray);
|
vertexInputState = &m_vertexInputStateFactory->GetOrCreateVertexInputState(*payload.drawArray.vertexArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline pipelineToBind = m_pipeline;
|
if (payload.drawArray.program == nullptr) {
|
||||||
if (vertexInputState) {
|
MGLOG_W("DrawElements skipped: no current program is bound");
|
||||||
pipelineToBind = GetOrCreatePipeline(m_demoProgramHash, vertexInputState->hash, vertexInputState->state);
|
|
||||||
if (pipelineToBind == VK_NULL_HANDLE) {
|
|
||||||
MGLOG_W("DrawElements skipped: failed to create/get pipeline variant");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Uint64 vertexInputHash = vertexInputState ? vertexInputState->hash : 0;
|
||||||
|
const VkPipelineVertexInputStateCreateInfo* vertexInputInfo =
|
||||||
|
vertexInputState ? &vertexInputState->state : nullptr;
|
||||||
|
if (!vertexInputInfo) {
|
||||||
|
VertexInputStateBuilder emptyVertexInputBuilder;
|
||||||
|
vertexInputInfo = &emptyVertexInputBuilder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline pipelineToBind = GetOrCreatePipeline(*payload.drawArray.program, vertexInputHash, *vertexInputInfo);
|
||||||
|
if (pipelineToBind == VK_NULL_HANDLE) {
|
||||||
|
MGLOG_W("DrawElements skipped: failed to create/get pipeline");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexInputState && !vertexInputState->bindings.empty()) {
|
if (vertexInputState && !vertexInputState->bindings.empty()) {
|
||||||
@@ -633,24 +607,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
VkCommandBuffer& commandBuffer = frame.commandBuffer;
|
||||||
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
const auto swapchainExtent = m_swapchainObject.GetExtent();
|
||||||
|
|
||||||
// Render commands
|
(void)commandBuffer;
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
|
(void)swapchainExtent;
|
||||||
|
|
||||||
VkViewport viewport{};
|
|
||||||
viewport.x = 0.0f;
|
|
||||||
viewport.y = 0.0f;
|
|
||||||
viewport.width = static_cast<float>(swapchainExtent.width);
|
|
||||||
viewport.height = static_cast<float>(swapchainExtent.height);
|
|
||||||
viewport.minDepth = 0.0f;
|
|
||||||
viewport.maxDepth = 1.0f;
|
|
||||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
|
||||||
|
|
||||||
VkRect2D scissor{};
|
|
||||||
scissor.offset = {0, 0};
|
|
||||||
scissor.extent = swapchainExtent;
|
|
||||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
|
||||||
|
|
||||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::Present() {
|
void VulkanRenderer::Present() {
|
||||||
@@ -1392,12 +1350,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (m_pipelineFactory) {
|
if (m_pipelineFactory) {
|
||||||
m_pipelineFactory->DestroyAll();
|
m_pipelineFactory->DestroyAll();
|
||||||
}
|
}
|
||||||
m_pipeline = VK_NULL_HANDLE;
|
|
||||||
if (!m_demoPipelineStages.empty() && m_pipelineLayout != VK_NULL_HANDLE && m_pipelineFactory) {
|
|
||||||
VertexInputStateBuilder vertexInputBuilder;
|
|
||||||
const auto& vertexInput = vertexInputBuilder.Build();
|
|
||||||
m_pipeline = GetOrCreatePipeline(m_demoProgramHash, 0, vertexInput);
|
|
||||||
}
|
|
||||||
if (m_frameContext.GetFrameCount() > 0) {
|
if (m_frameContext.GetFrameCount() > 0) {
|
||||||
m_frameContext.GetCurrent().isCommandRecording = false;
|
m_frameContext.GetCurrent().isCommandRecording = false;
|
||||||
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "../VkIncludes.h"
|
#include "../VkIncludes.h"
|
||||||
|
|
||||||
namespace MobileGL::MG_State::GLState {
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class ProgramObject;
|
||||||
class VertexArrayObject;
|
class VertexArrayObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
GLenum mode = GL_TRIANGLES;
|
GLenum mode = GL_TRIANGLES;
|
||||||
GLint first = 0;
|
GLint first = 0;
|
||||||
GLsizei count = 0;
|
GLsizei count = 0;
|
||||||
|
const MG_State::GLState::ProgramObject* program = nullptr;
|
||||||
const MG_State::GLState::VertexArrayObject* vertexArray = nullptr;
|
const MG_State::GLState::VertexArrayObject* vertexArray = nullptr;
|
||||||
Bool hasPositionStream = false;
|
Bool hasPositionStream = false;
|
||||||
const void* positionData = nullptr;
|
const void* positionData = nullptr;
|
||||||
@@ -117,9 +119,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Vector<VkImageLayout> m_depthStencilImageLayouts;
|
Vector<VkImageLayout> m_depthStencilImageLayouts;
|
||||||
|
|
||||||
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
|
||||||
Uint64 m_demoProgramHash = 0;
|
|
||||||
Vector<VkPipelineShaderStageCreateInfo> m_demoPipelineStages;
|
|
||||||
VkBufferObject m_vertexBuffer;
|
VkBufferObject m_vertexBuffer;
|
||||||
VkBufferObject m_indexBuffer;
|
VkBufferObject m_indexBuffer;
|
||||||
|
|
||||||
@@ -153,7 +152,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp loadOp);
|
VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp loadOp);
|
||||||
void CreateDefaultFramebuffers();
|
void CreateDefaultFramebuffers();
|
||||||
void PrepareDemoPipeline();
|
void PrepareDemoPipeline();
|
||||||
VkPipeline GetOrCreatePipeline(Uint64 programHash, Uint64 vertexInputHash,
|
VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, Uint64 vertexInputHash,
|
||||||
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
|
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
|
||||||
void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
||||||
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#define GLFW_INCLUDE_NONE
|
#define GLFW_INCLUDE_NONE
|
||||||
@@ -40,6 +41,50 @@ namespace MobileGL {
|
|||||||
void MG_Initialize();
|
void MG_Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool CheckShaderCompile(GLuint shader, const char* label) {
|
||||||
|
GLint status = GL_FALSE;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status == GL_TRUE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint logLength = 0;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
|
||||||
|
std::string log;
|
||||||
|
if (logLength > 0) {
|
||||||
|
log.resize(static_cast<size_t>(logLength));
|
||||||
|
GLsizei written = 0;
|
||||||
|
glGetShaderInfoLog(shader, logLength, &written, log.data());
|
||||||
|
if (written >= 0 && static_cast<size_t>(written) < log.size()) {
|
||||||
|
log.resize(static_cast<size_t>(written));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << label << " compile failed: " << log << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CheckProgramLink(GLuint program) {
|
||||||
|
GLint status = GL_FALSE;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||||
|
if (status == GL_TRUE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint logLength = 0;
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
|
||||||
|
std::string log;
|
||||||
|
if (logLength > 0) {
|
||||||
|
log.resize(static_cast<size_t>(logLength));
|
||||||
|
GLsizei written = 0;
|
||||||
|
glGetProgramInfoLog(program, logLength, &written, log.data());
|
||||||
|
if (written >= 0 && static_cast<size_t>(written) < log.size()) {
|
||||||
|
log.resize(static_cast<size_t>(written));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << "Program link failed: " << log << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
glfwInit();
|
glfwInit();
|
||||||
|
|
||||||
@@ -89,11 +134,52 @@ int main() {
|
|||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
static constexpr GLushort kTriangleIndices[] = {0, 1, 2};
|
static constexpr GLushort kQuadIndices[] = {0, 1, 2, 2, 3, 0};
|
||||||
GLuint ebo = 0;
|
GLuint ebo = 0;
|
||||||
glGenBuffers(1, &ebo);
|
glGenBuffers(1, &ebo);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kTriangleIndices), kTriangleIndices, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kQuadIndices), kQuadIndices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
static constexpr const char* kVertexShaderSource = R"(#version 330 core
|
||||||
|
void main() {
|
||||||
|
const vec2 kPositions[4] = vec2[](
|
||||||
|
vec2(-0.6, -0.6),
|
||||||
|
vec2( 0.6, -0.6),
|
||||||
|
vec2( 0.6, 0.6),
|
||||||
|
vec2(-0.6, 0.6)
|
||||||
|
);
|
||||||
|
gl_Position = vec4(kPositions[gl_VertexID], 0.0, 1.0);
|
||||||
|
})";
|
||||||
|
static constexpr const char* kFragmentShaderSource = R"(#version 330 core
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(0.95, 0.85, 0.2, 1.0);
|
||||||
|
})";
|
||||||
|
|
||||||
|
const GLuint vs = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(vs, 1, &kVertexShaderSource, nullptr);
|
||||||
|
glCompileShader(vs);
|
||||||
|
if (!CheckShaderCompile(vs, "Vertex shader")) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(fs, 1, &kFragmentShaderSource, nullptr);
|
||||||
|
glCompileShader(fs);
|
||||||
|
if (!CheckShaderCompile(fs, "Fragment shader")) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLuint program = glCreateProgram();
|
||||||
|
glAttachShader(program, vs);
|
||||||
|
glAttachShader(program, fs);
|
||||||
|
glLinkProgram(program);
|
||||||
|
if (!CheckProgramLink(program)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
glUseProgram(program);
|
||||||
|
glDeleteShader(vs);
|
||||||
|
glDeleteShader(fs);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(!glfwWindowShouldClose(window)) {
|
while(!glfwWindowShouldClose(window)) {
|
||||||
@@ -104,12 +190,18 @@ int main() {
|
|||||||
else
|
else
|
||||||
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
if (i % 500 > 250)
|
if (i % 500 > 250) {
|
||||||
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr);
|
glUseProgram(program);
|
||||||
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
|
||||||
|
}
|
||||||
eglSwapBuffers(display, surface);
|
eglSwapBuffers(display, surface);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glDeleteProgram(program);
|
||||||
|
glDeleteBuffers(1, &ebo);
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
|
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
|
|||||||
Reference in New Issue
Block a user