上一篇文章中,我们浅析了Vulkan对传统图形API的优势,主要就是在其性能和精细化操控GPU上,具体可参考Vulkan-性能及精细化
今天我们就来用个简单的例子,亲身感受下Vulkan的开发“魅力”。
- #include <iostream>
- #include <chrono>
- #include <cstring>
- #include <glm/mat4x4.hpp>
- #include <glm/gtx/transform.hpp>
- #include "VK_UniformBuffer.h"
- #include "VK_Context.h"
- #include "VK_Pipeline.h"
- #include "VK_DynamicState.h"
-
- using namespace std;
-
- const std::vector<uint32_t> indices = {
- 0, 1, 2
- };
-
- const std::vector<float> vertices = {
- 0.0f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f,
- 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f,
- -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5
- };
-
-
- VK_Context *context = nullptr;
- VK_Pipeline *pipeline = nullptr;
-
- // 窗口大小改变时通过onFrameSizeChanged更新窗口大小
- void onFrameSizeChanged(int width, int height)
- {
- pipeline->getDynamicState()->applyDynamicViewport({0, 0, (float)width, (float)height, 0, 1});
- }
-
- //实时更新uniform值
- uint32_t updateUniformBufferData(char *&data, uint32_t size)
- {
- static auto start = std::chrono::high_resolution_clock::now();
- auto current = std::chrono::high_resolution_clock::now();
- float time = std::chrono::duration<float, std::chrono::seconds::period>
- (current - start).count();
- glm::mat4 model = glm::rotate(glm::mat4(1.0f), time * glm::radians(30.0f), glm::vec3(0.0f, 0.0f,
- 1.0f));
- memcpy(data, &model[0][0], size);
- return sizeof(model);
- }
-
-
- int main()
- {
- VK_ContextConfig config;
- config.debug = true;
- config.name = "Uniform Demo";
-
- context = createVkContext(config);
- context->createWindow(640, 640, true);
- context->setOnFrameSizeChanged(onFrameSizeChanged);
-
- VK_Context::VK_Config vkConfig;
- context->initVulkanDevice(vkConfig);
-
- auto shaderSet = context->createShaderSet();
- shaderSet->addShader("../jianghuxiuxing/shader/mvp/vertex.spv", VK_SHADER_STAGE_VERTEX_BIT);
- shaderSet->addShader("../jianghuxiuxing/shader/mvp/fragmeng.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
-
- shaderSet->appendAttributeDescription(0, sizeof (float) * 3, VK_FORMAT_R32G32B32_SFLOAT, 0);
- shaderSet->appendAttributeDescription(1, sizeof (float) * 4, VK_FORMAT_R32G32B32A32_SFLOAT,
- sizeof(float) * 3);
-
- shaderSet->appendVertexInputBindingDescription(7 * sizeof(float), 0, VK_VERTEX_INPUT_RATE_VERTEX);
-
- VkDescriptorSetLayoutBinding uniformBinding = VK_ShaderSet::createDescriptorSetLayoutBinding(0,
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
- shaderSet->addDescriptorSetLayoutBinding(uniformBinding);
-
- if (!shaderSet->isValid()) {
- std::cerr << "invalid shaderSet" << std::endl;
- shaderSet->release();
- context->release();
- return -1;
- }
-
- auto ubo = shaderSet->addUniformBuffer(0, sizeof(float) * 16);
- ubo->setWriteDataCallback(updateUniformBufferData);
-
- context->initVulkanContext();
- pipeline = context->createPipeline(shaderSet);
- pipeline->getDynamicState()->addDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
- pipeline->create();
- pipeline->getDynamicState()->applyDynamicViewport({0, 0, 480, 480, 0, 1});
-
- auto buffer = context->createVertexBuffer(vertices, 3 + 4, indices);
- pipeline->addRenderBuffer(buffer);
-
- context->createCommandBuffers();
-
- context->run();
- context->release();
-
- return 0;
- }
- #version 450
- layout(location = 0) in vec3 position;
- layout(location = 1) in vec4 color;
- layout(location = 0) out vec4 fragColor;
-
- layout(binding = 0) uniform UniformBufferObject {
- mat4 model;
- } mvp;
-
- void main() {
- gl_Position = mvp.model * vec4(position, 1.0);
- fragColor = color;
- }
- #version 450
- layout(location = 0) in vec4 fragColor;
- layout(location = 0) out vec4 outColor;
-
- void main() {
- outColor = fragColor;
- }
效果:
从上面的代码实现可以看出Vulkan在加载spv字节码,显示指定shader各属性方面都做了更繁琐的限制,开发者需要关注的程序控制和执行时机也变的更多了,这也印证了我们上一篇文章里说的Vulkan摒弃了传统图形API的大包大揽,而将更多的校验和权利下放给了程序设计者。