Skip to content

Instantly share code, notes, and snippets.

@volcanoauthors
Last active December 22, 2018 20:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save volcanoauthors/bcb31e07f46023a6b95acf7e16283aab to your computer and use it in GitHub Desktop.
Save volcanoauthors/bcb31e07f46023a6b95acf7e16283aab to your computer and use it in GitHub Desktop.
Cheat sheet: triangle.cpp and BUILD.gn patch
diff --git a/BUILD.gn b/BUILD.gn
index a095b4c..102246d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,6 +1,22 @@
# Copyright (c) 2017-2018 the Volcano Authors. Licensed under GPLv3.
import("//src/gn/vendor/glslangValidator.gni")
+glslangVulkanToHeader("triangle_shaders") {
+ sources = [
+ "triangle.vert", # compile to bytecode available at "triangle.vert.h"
+ "triangle.frag", # compile to bytecode available at "triangle.frag.h"
+ ]
+}
+
+executable("triangle") {
+ sources = [ "triangle.cpp" ]
+ deps = [
+ ":triangle_shaders", # Tells the compiler where to find triangle.vert.h
+ "//src/gn/vendor/glfw",
+ "//vendor/volcano",
+ ]
+}
+
# If these samples build ok, then assume all samples will build ok.
group("build_first") {
deps = [
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>
#endif /* _WIN32 */
#include <src/language/language.h>
#include <src/science/science.h>
#include "triangle.frag.h"
#include "triangle.vert.h"
// pipe0 is the Vulkan Pipeline.
std::shared_ptr<command::Pipeline> pipe0;
// cmdBuffers are a vector because there is one per framebuffer.
std::vector<command::CommandBuffer> cmdBuffers;
static void handleGlfwErrors(int error, const char* description) {
printf("glfw error %d: %s\n", error, description);
}
// Wrap the function glfwCreateWindowSurface for Instance::ctorError():
static VkResult handleCreateSurface(language::Instance& inst, void* window)
{
return glfwCreateWindowSurface(inst.vk, (GLFWwindow*) window, nullptr,
&inst.surface);
}
const int WIDTH = 800, HEIGHT = 600;
int buildFramebuf(void* containerPtr, language::Framebuf& framebuf,
size_t framebuf_i, size_t /*poolQindex*/) {
science::CommandPoolContainer& cpoolContainer(
*static_cast<science::CommandPoolContainer*>(containerPtr));
if (framebuf_i == 0) { // Do this only for the first frame buffer.
if (cpoolContainer.cpool.updateBuffersAndPass(cmdBuffers,
cpoolContainer.pass)) {
return 1;
}
}
// Write drawing commands for each framebuf_i.
auto& cmdBuffer = cmdBuffers.at(framebuf_i);
if (cmdBuffer.beginSimultaneousUse() ||
// Begin RenderPass.
cmdBuffer.beginPrimaryPass(cpoolContainer.pass, framebuf) ||
cmdBuffer.bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipe0) ||
cmdBuffer.draw(3, 1, 0, 0) ||
// End RenderPass.
cmdBuffer.endRenderPass() || cmdBuffer.end()) {
logE("buildFramebuf: cmdBuffer [%zu] failed\n", framebuf_i);
return 1;
}
return 0;
}
int mainLoop(GLFWwindow* window) {
unsigned int extCount = 0;
const char** exts = glfwGetRequiredInstanceExtensions(&extCount);
language::Instance inst;
for (unsigned int i = 0; i < extCount; i++) {
inst.requiredExtensions.push_back(exts[i]);
}
if (inst.ctorError(handleCreateSurface, window)) {
return 1;
}
if (inst.open({WIDTH, HEIGHT})) {
return 1;
}
// inst has the logical device after inst.open().
language::Device& dev = *inst.devs.at(0);
// CommandPoolContainer can allocate command pools from dev.
science::CommandPoolContainer cpoolContainer(dev);
cpoolContainer.resizeFramebufListeners.emplace_back(
std::make_pair(buildFramebuf, &cpoolContainer));
pipe0 = cpoolContainer.pass.addPipeline();
// Set viewport.
auto& extent = dev.swapChainInfo.imageExtent;
VkViewport& viewport = pipe0->info.viewports.at(0);
viewport.width = (float)extent.width;
viewport.height = (float)extent.height;
// Set scissors.
pipe0->info.scissors.at(0).extent = extent;
auto vshader = std::shared_ptr<command::Shader>(new command::Shader{dev});
auto fshader = std::shared_ptr<command::Shader>(new command::Shader{dev});
science::PresentSemaphore renderSemaphore(cpoolContainer);
command::Semaphore imageAvailableSemaphore(dev);
if (cpoolContainer.cpool.ctorError() || imageAvailableSemaphore.ctorError() ||
renderSemaphore.ctorError() ||
// Read compiled-in shaders from app into Vulkan.
vshader->loadSPV(spv_triangle_vert, sizeof(spv_triangle_vert)) ||
fshader->loadSPV(spv_triangle_frag, sizeof(spv_triangle_frag)) ||
// Add shader objects to pipeline.
pipe0->info.addShader(vshader, VK_SHADER_STAGE_VERTEX_BIT) ||
pipe0->info.addShader(fshader, VK_SHADER_STAGE_FRAGMENT_BIT)) {
return 1;
}
// onResized will call buildFramebuf for each element of cmdBuffers.
// This is not fully set up for resizing yet, but has most of the pieces.
glfwSetWindowAttrib(window, GLFW_RESIZABLE, false);
if (cpoolContainer.onResized(dev.swapChainInfo.imageExtent,
memory::ASSUME_POOL_QINDEX)) {
return 1;
}
// Begin main loop.
unsigned frameCount = 0;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
frameCount++;
// https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#vkAcquireNextImageKHR
// Acquire an image index that can be rendered as soon as
// imageAvailableSemaphore is signaled.
uint32_t next_image_i;
if (cpoolContainer.acquireNextImage(frameCount, &next_image_i,
imageAvailableSemaphore)) {
return 1;
}
if (next_image_i != (uint32_t)-1) {
if (cmdBuffers.at(next_image_i)
.submit(memory::ASSUME_POOL_QINDEX,
{imageAvailableSemaphore.vk},
{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
{renderSemaphore.vk}) ||
renderSemaphore.present(&next_image_i)) {
return 1;
}
}
// renderSemaphore.present() can set next_image_i == (uint32_t)-1
if (next_image_i != (uint32_t)-1) {
// waitIdle() here is only to let any validation layers
// clean up resources that might otherwise leak.
if ((frameCount % 64) == 63 && renderSemaphore.waitIdle()) {
return 1;
}
}
}
if (cpoolContainer.cpool.deviceWaitIdle()) {
return 1;
}
// Destroy Pipeline before other objects that it depends on.
pipe0.reset();
return 0;
}
int crossPlatformMain() {
glfwSetErrorCallback(handleGlfwErrors);
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "My Title",
nullptr /*monitor for fullscreen*/, nullptr /*context object sharing*/);
if (!window) {
return 1;
}
int r = mainLoop(window);
glfwDestroyWindow(window);
glfwTerminate();
return r;
}
#ifdef _WIN32
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
return crossPlatformMain();
}
#elif defined(__ANDROID__)
void android_main(android_app* app) {
(void)crossPlatformMain();
}
#else
int main() {
return crossPlatformMain();
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment