So, apparently Vulkan is a thing now ... looks interesting. Too interesting for my tinkering hands to ignore. After reading tutorials / spec managed to make my own Hello Triangle ( (
) ) - ie. validation layer finally shuts up and the darn triangle shows up.
So far the wrapper-lib i am making (Vulkan is a GIGANTIC [!] unreadable / unmanageable mess without one) looks promising. Has quite a few things the tutorials do not touch or implement in a non-scaleable/extendable way. Still much to do: most importantly - memory management which is very tricky, but i think i figured out a way to do it.
Can not think of any sane reason (besides curiosity) why anyone would write Vulkan code - but it does not hurt to ask. Anyone else trying out Vulkan?
Code:
GlwPipeline g_pipe;
GlwRenderPass g_pass;
GlwShaderModule g_fragment, g_vertex;
GlwLayout g_layout;
GlwSemaphore g_imageavailable, g_renderfinished;
void vk_init() {
win.init();
//GlwCore::reqFeatures.geometryShader = true;
win.resize();
// shaders
g_fragment.init(R"BLOCK(
#version 450
#pragma shader_stage(fragment)
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor, 1.0);
}
)BLOCK");
g_vertex.init(R"BLOCK(
#version 450
#pragma shader_stage(vertex)
#extension GL_ARB_separate_shader_objects : enable
out gl_PerVertex { vec4 gl_Position; };
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_VertexIndex], 0.0, 1.0);
fragColor = colors[gl_VertexIndex];
}
)BLOCK");
// create renderpass
GlwRenderPass::Desc i_pass;
i_pass.attach(GlwContext::swapchainFormat).color(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE).layout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
i_pass.subpass().bindColor(0);
i_pass.dependency(VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0
,0 , VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
g_pass.init(i_pass);
// create pipeline layout
GlwLayout::Desc i_layout;
g_layout.init(i_layout);
// create pipeline
GlwPipeline::Desc i_pipe;
i_pipe.bind(&g_fragment).bind(&g_vertex).bind(&g_layout, &g_pass, 0);
i_pipe.viewport(GlwContext::scrWidth, GlwContext::scrHeight); //.dynamic(VK_DYNAMIC_STATE_VIEWPORT);
i_pipe.disableBlend(0);
g_pipe.init(i_pipe);
// create framebuffers
GlwFramebuffer::Desc i_fbuf;
i_fbuf.bind(&g_pass, GlwContext::scrWidth, GlwContext::scrHeight).bindSwapchain();
GlwFramebuffer::initSwapchain(i_fbuf);
// create semaphores
g_imageavailable.init();
g_renderfinished.init();
}
void vk_loop() {
// start a new frame
auto frame = GlwContext::getNextFrame(g_imageavailable);
// new command buffer (always rerecording just to test buffer cache and reclamation code)
GlwCommandBuffer *cmd = GlwCommandPool::getBuffer(); // default params: buffer is for graphics queue, resettable and transient
GlwCommandBuffer::Clear clear; clear.setColor(0, 0.0f, 0.0f, 0.0f, 1.0f);
cmd->begin().beginPass(false, &g_pass, frame.frame, GlwRect(), &clear);
cmd->bind(&g_pipe).draw(0, 3);
cmd->endPass().end();
// populate queue
GlwQueue::Work work;
work.patch().wait(&g_imageavailable, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT).commands(cmd).signal(&g_renderfinished); // default param: 'cmd' will be automatically reclaimed when done using it
// render
GlwQueue::submitPrimary(work);
// present
frame.present(g_renderfinished); // currently does vkQueueWaitIdle also ... probably should get rid of it or something :/
// check for callbacks
GlwFence::checkAll();
}