Added tessellation evaluation shader frustum culling and pipeline stats for dynamic terrain tessellation example
This commit is contained in:
parent
dbf80b217c
commit
a9de176d12
7 changed files with 147 additions and 27 deletions
|
|
@ -14,10 +14,10 @@ namespace vkTools
|
||||||
{
|
{
|
||||||
class Frustum
|
class Frustum
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
enum side { LEFT = 0, RIGHT = 1, TOP = 2, BOTTOM = 3, BACK = 4, FRONT = 5 };
|
enum side { LEFT = 0, RIGHT = 1, TOP = 2, BOTTOM = 3, BACK = 4, FRONT = 5 };
|
||||||
std::array<glm::vec4, 6> planes;
|
std::array<glm::vec4, 6> planes;
|
||||||
public:
|
|
||||||
void update(glm::mat4 matrix)
|
void update(glm::mat4 matrix)
|
||||||
{
|
{
|
||||||
planes[LEFT].x = matrix[0].w + matrix[0].x;
|
planes[LEFT].x = matrix[0].w + matrix[0].x;
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,6 @@ void main()
|
||||||
outFragColor = vec4((IAmbient + IDiffuse) * vec4(texture(terrainLayers, vec3(inUV, 0.0)).rgb, 1.0));
|
outFragColor = vec4((IAmbient + IDiffuse) * vec4(texture(terrainLayers, vec3(inUV, 0.0)).rgb, 1.0));
|
||||||
*/
|
*/
|
||||||
outFragColor = sampleTerrainLayer();
|
outFragColor = sampleTerrainLayer();
|
||||||
|
|
||||||
|
//outFragColor.rgb = normalize(inNormal);
|
||||||
}
|
}
|
||||||
|
|
@ -8,13 +8,14 @@ layout(set = 0, binding = 0) uniform UBO
|
||||||
mat4 projection;
|
mat4 projection;
|
||||||
mat4 modelview;
|
mat4 modelview;
|
||||||
vec4 lightPos;
|
vec4 lightPos;
|
||||||
|
vec4 frustumPlanes[6];
|
||||||
float displacementFactor;
|
float displacementFactor;
|
||||||
float tessellationFactor;
|
float tessellationFactor;
|
||||||
vec2 viewportDim;
|
vec2 viewportDim;
|
||||||
float tessellatedEdgeSize;
|
float tessellatedEdgeSize;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
layout(set = 0, binding = 2) uniform sampler2D samplerHeight;
|
layout(set = 0, binding = 1) uniform sampler2D samplerHeight;
|
||||||
|
|
||||||
layout (vertices = 4) out;
|
layout (vertices = 4) out;
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ float screenSpaceTessFactor(vec4 p0, vec4 p1)
|
||||||
// Calculate edge mid point
|
// Calculate edge mid point
|
||||||
vec4 midPoint = 0.5 * (p0 + p1);
|
vec4 midPoint = 0.5 * (p0 + p1);
|
||||||
// Sphere radius as distance between the control points
|
// Sphere radius as distance between the control points
|
||||||
float radius = distance(p0, p1) / 2;
|
float radius = distance(p0, p1) / 2.0;
|
||||||
|
|
||||||
// View space
|
// View space
|
||||||
vec4 v0 = ubo.modelview * midPoint;
|
vec4 v0 = ubo.modelview * midPoint;
|
||||||
|
|
@ -54,30 +55,62 @@ float screenSpaceTessFactor(vec4 p0, vec4 p1)
|
||||||
return clamp(distance(clip0, clip1) / ubo.tessellatedEdgeSize * ubo.tessellationFactor, 1.0, 64.0);
|
return clamp(distance(clip0, clip1) / ubo.tessellatedEdgeSize * ubo.tessellationFactor, 1.0, 64.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks the current's patch visibility against the frustum using a sphere check
|
||||||
|
// Sphere radius is given by the patch size
|
||||||
|
bool frustumCheck()
|
||||||
|
{
|
||||||
|
// Fixed radius (increase if patch size is increased in example)
|
||||||
|
const float radius = 8.0f;
|
||||||
|
vec4 pos = gl_in[gl_InvocationID].gl_Position;
|
||||||
|
pos.y -= textureLod(samplerHeight, inUV[0], 0.0).r * ubo.displacementFactor;
|
||||||
|
|
||||||
|
// Check sphere against frustum planes
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
if (dot(pos, ubo.frustumPlanes[i]) + radius < 0.0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
if (gl_InvocationID == 0)
|
if (gl_InvocationID == 0)
|
||||||
{
|
{
|
||||||
if (ubo.tessellationFactor > 0.0)
|
if (!frustumCheck())
|
||||||
{
|
{
|
||||||
gl_TessLevelOuter[0] = screenSpaceTessFactor(gl_in[3].gl_Position, gl_in[0].gl_Position);
|
gl_TessLevelInner[0] = 0.0;
|
||||||
gl_TessLevelOuter[1] = screenSpaceTessFactor(gl_in[0].gl_Position, gl_in[1].gl_Position);
|
gl_TessLevelInner[1] = 0.0;
|
||||||
gl_TessLevelOuter[2] = screenSpaceTessFactor(gl_in[1].gl_Position, gl_in[2].gl_Position);
|
gl_TessLevelOuter[0] = 0.0;
|
||||||
gl_TessLevelOuter[3] = screenSpaceTessFactor(gl_in[2].gl_Position, gl_in[3].gl_Position);
|
gl_TessLevelOuter[1] = 0.0;
|
||||||
gl_TessLevelInner[0] = mix(gl_TessLevelOuter[0], gl_TessLevelOuter[3], 0.5);
|
gl_TessLevelOuter[2] = 0.0;
|
||||||
gl_TessLevelInner[1] = mix(gl_TessLevelOuter[2], gl_TessLevelOuter[1], 0.5);
|
gl_TessLevelOuter[3] = 0.0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Tessellation factor can be set to zero by example
|
if (ubo.tessellationFactor > 0.0)
|
||||||
// to demonstrate a simple passthrough
|
{
|
||||||
gl_TessLevelInner[0] = 1.0;
|
gl_TessLevelOuter[0] = screenSpaceTessFactor(gl_in[3].gl_Position, gl_in[0].gl_Position);
|
||||||
gl_TessLevelInner[1] = 1.0;
|
gl_TessLevelOuter[1] = screenSpaceTessFactor(gl_in[0].gl_Position, gl_in[1].gl_Position);
|
||||||
gl_TessLevelOuter[0] = 1.0;
|
gl_TessLevelOuter[2] = screenSpaceTessFactor(gl_in[1].gl_Position, gl_in[2].gl_Position);
|
||||||
gl_TessLevelOuter[1] = 1.0;
|
gl_TessLevelOuter[3] = screenSpaceTessFactor(gl_in[2].gl_Position, gl_in[3].gl_Position);
|
||||||
gl_TessLevelOuter[2] = 1.0;
|
gl_TessLevelInner[0] = mix(gl_TessLevelOuter[0], gl_TessLevelOuter[3], 0.5);
|
||||||
gl_TessLevelOuter[3] = 1.0;
|
gl_TessLevelInner[1] = mix(gl_TessLevelOuter[2], gl_TessLevelOuter[1], 0.5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Tessellation factor can be set to zero by example
|
||||||
|
// to demonstrate a simple passthrough
|
||||||
|
gl_TessLevelInner[0] = 1.0;
|
||||||
|
gl_TessLevelInner[1] = 1.0;
|
||||||
|
gl_TessLevelOuter[0] = 1.0;
|
||||||
|
gl_TessLevelOuter[1] = 1.0;
|
||||||
|
gl_TessLevelOuter[2] = 1.0;
|
||||||
|
gl_TessLevelOuter[3] = 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -8,8 +8,11 @@ layout (set = 0, binding = 0) uniform UBO
|
||||||
mat4 projection;
|
mat4 projection;
|
||||||
mat4 modelview;
|
mat4 modelview;
|
||||||
vec4 lightPos;
|
vec4 lightPos;
|
||||||
|
vec4 frustumPlanes[6];
|
||||||
float displacementFactor;
|
float displacementFactor;
|
||||||
float tessellationFalloff;
|
float tessellationFactor;
|
||||||
|
vec2 viewportDim;
|
||||||
|
float tessellatedEdgeSize;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
layout (set = 0, binding = 1) uniform sampler2D displacementMap;
|
layout (set = 0, binding = 1) uniform sampler2D displacementMap;
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include "vulkanexamplebase.h"
|
#include "vulkanexamplebase.h"
|
||||||
#include "vulkanMeshLoader.hpp"
|
#include "frustum.hpp"
|
||||||
|
|
||||||
#define VERTEX_BUFFER_BIND_ID 0
|
#define VERTEX_BUFFER_BIND_ID 0
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
|
|
@ -66,8 +66,9 @@ public:
|
||||||
glm::mat4 projection;
|
glm::mat4 projection;
|
||||||
glm::mat4 modelview;
|
glm::mat4 modelview;
|
||||||
glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 0.0f, 0.0f);
|
glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 0.0f, 0.0f);
|
||||||
float displacementFactor = 16.0f * 2.0f;
|
glm::vec4 frustumPlanes[6];
|
||||||
float tessellationFactor = 0.75f;
|
float displacementFactor = 32.0f;
|
||||||
|
float tessellationFactor = 1.0f;
|
||||||
glm::vec2 viewportDim;
|
glm::vec2 viewportDim;
|
||||||
// Desired size of tessellated quad patch edge
|
// Desired size of tessellated quad patch edge
|
||||||
float tessellatedEdgeSize = 20.0f;
|
float tessellatedEdgeSize = 20.0f;
|
||||||
|
|
@ -99,6 +100,17 @@ public:
|
||||||
VkDescriptorSet skysphere;
|
VkDescriptorSet skysphere;
|
||||||
} descriptorSets;
|
} descriptorSets;
|
||||||
|
|
||||||
|
// Pipeline statistics
|
||||||
|
struct {
|
||||||
|
VkBuffer buffer;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
} queryResult;
|
||||||
|
VkQueryPool queryPool;
|
||||||
|
uint64_t pipelineStats[2] = { 0 };
|
||||||
|
|
||||||
|
// View frustum passed to tessellation control shader for culling
|
||||||
|
vkTools::Frustum frustum;
|
||||||
|
|
||||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||||
{
|
{
|
||||||
enableTextOverlay = true;
|
enableTextOverlay = true;
|
||||||
|
|
@ -140,6 +152,58 @@ public:
|
||||||
textureLoader->destroyTexture(textures.heightMap);
|
textureLoader->destroyTexture(textures.heightMap);
|
||||||
textureLoader->destroyTexture(textures.skySphere);
|
textureLoader->destroyTexture(textures.skySphere);
|
||||||
textureLoader->destroyTexture(textures.terrainArray);
|
textureLoader->destroyTexture(textures.terrainArray);
|
||||||
|
|
||||||
|
vkDestroyQueryPool(device, queryPool, nullptr);
|
||||||
|
|
||||||
|
vkDestroyBuffer(device, queryResult.buffer, nullptr);
|
||||||
|
vkFreeMemory(device, queryResult.memory, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup pool and buffer for storing pipeline statistics results
|
||||||
|
void setupQueryResultBuffer()
|
||||||
|
{
|
||||||
|
uint32_t bufSize = 2 * sizeof(uint64_t);
|
||||||
|
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||||
|
VkBufferCreateInfo bufferCreateInfo =
|
||||||
|
vkTools::initializers::bufferCreateInfo(
|
||||||
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
bufSize);
|
||||||
|
|
||||||
|
// Results are saved in a host visible buffer for easy access by the application
|
||||||
|
VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, &queryResult.buffer));
|
||||||
|
vkGetBufferMemoryRequirements(device, queryResult.buffer, &memReqs);
|
||||||
|
memAlloc.allocationSize = memReqs.size;
|
||||||
|
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &queryResult.memory));
|
||||||
|
VK_CHECK_RESULT(vkBindBufferMemory(device, queryResult.buffer, queryResult.memory, 0));
|
||||||
|
|
||||||
|
// Create query pool
|
||||||
|
VkQueryPoolCreateInfo queryPoolInfo = {};
|
||||||
|
queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
|
||||||
|
queryPoolInfo.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
|
||||||
|
queryPoolInfo.pipelineStatistics =
|
||||||
|
VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT |
|
||||||
|
VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT;
|
||||||
|
queryPoolInfo.queryCount = 2;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkCreateQueryPool(device, &queryPoolInfo, NULL, &queryPool));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves the results of the pipeline statistics query submitted to the command buffer
|
||||||
|
void getQueryResults()
|
||||||
|
{
|
||||||
|
// We use vkGetQueryResults to copy the results into a host visible buffer
|
||||||
|
vkGetQueryPoolResults(
|
||||||
|
device,
|
||||||
|
queryPool,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
sizeof(pipelineStats),
|
||||||
|
pipelineStats,
|
||||||
|
sizeof(uint64_t),
|
||||||
|
VK_QUERY_RESULT_64_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadTextures()
|
void loadTextures()
|
||||||
|
|
@ -223,6 +287,8 @@ public:
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||||
|
|
||||||
|
vkCmdResetQueryPool(drawCmdBuffers[i], queryPool, 0, 2);
|
||||||
|
|
||||||
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
||||||
|
|
@ -243,11 +309,16 @@ public:
|
||||||
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.skysphere.indexCount, 1, 0, 0, 0);
|
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.skysphere.indexCount, 1, 0, 0, 0);
|
||||||
|
|
||||||
// Terrrain
|
// Terrrain
|
||||||
|
// Begin pipeline statistics query
|
||||||
|
vkCmdBeginQuery(drawCmdBuffers[i], queryPool, 0, VK_QUERY_CONTROL_PRECISE_BIT);
|
||||||
|
// Render
|
||||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, wireframe ? pipelines.wireframe : pipelines.terrain);
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, wireframe ? pipelines.wireframe : pipelines.terrain);
|
||||||
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.terrain, 0, 1, &descriptorSets.terrain, 0, NULL);
|
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.terrain, 0, 1, &descriptorSets.terrain, 0, NULL);
|
||||||
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.object.vertices.buf, offsets);
|
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.object.vertices.buf, offsets);
|
||||||
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.object.indices.buf, 0, VK_INDEX_TYPE_UINT32);
|
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.object.indices.buf, 0, VK_INDEX_TYPE_UINT32);
|
||||||
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.object.indexCount, 1, 0, 0, 0);
|
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.object.indexCount, 1, 0, 0, 0);
|
||||||
|
// End pipeline statistics query
|
||||||
|
vkCmdEndQuery(drawCmdBuffers[i], queryPool, 0);
|
||||||
|
|
||||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||||
|
|
||||||
|
|
@ -285,7 +356,7 @@ public:
|
||||||
vertices[index].pos[0] = x * wx + wx / 2.0f - (float)PATCH_SIZE * wx / 2.0f;
|
vertices[index].pos[0] = x * wx + wx / 2.0f - (float)PATCH_SIZE * wx / 2.0f;
|
||||||
vertices[index].pos[1] = 0.0f;
|
vertices[index].pos[1] = 0.0f;
|
||||||
vertices[index].pos[2] = y * wy + wy / 2.0f - (float)PATCH_SIZE * wy / 2.0f;
|
vertices[index].pos[2] = y * wy + wy / 2.0f - (float)PATCH_SIZE * wy / 2.0f;
|
||||||
vertices[index].normal = glm::vec3(0.0f, -1.0f, 0.0f);
|
vertices[index].normal = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||||
vertices[index].uv = glm::vec2((float)x / PATCH_SIZE, (float)y / PATCH_SIZE) * UV_SCALE;
|
vertices[index].uv = glm::vec2((float)x / PATCH_SIZE, (float)y / PATCH_SIZE) * UV_SCALE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -459,7 +530,7 @@ public:
|
||||||
// Binding 1 : Height map
|
// Binding 1 : Height map
|
||||||
vkTools::initializers::descriptorSetLayoutBinding(
|
vkTools::initializers::descriptorSetLayoutBinding(
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
1),
|
1),
|
||||||
// Binding 3 : Terrain texture array layers
|
// Binding 3 : Terrain texture array layers
|
||||||
vkTools::initializers::descriptorSetLayoutBinding(
|
vkTools::initializers::descriptorSetLayoutBinding(
|
||||||
|
|
@ -685,6 +756,9 @@ public:
|
||||||
uboTess.lightPos.y = -0.5f - uboTess.displacementFactor; // todo: Not uesed yet
|
uboTess.lightPos.y = -0.5f - uboTess.displacementFactor; // todo: Not uesed yet
|
||||||
uboTess.viewportDim = glm::vec2((float)width, (float)height);
|
uboTess.viewportDim = glm::vec2((float)width, (float)height);
|
||||||
|
|
||||||
|
frustum.update(uboTess.projection * uboTess.modelview);
|
||||||
|
memcpy(uboTess.frustumPlanes, frustum.planes.data(), sizeof(glm::vec4) * 6);
|
||||||
|
|
||||||
float savedFactor = uboTess.tessellationFactor;
|
float savedFactor = uboTess.tessellationFactor;
|
||||||
if (!tessellation)
|
if (!tessellation)
|
||||||
{
|
{
|
||||||
|
|
@ -721,6 +795,9 @@ public:
|
||||||
// Submit to queue
|
// Submit to queue
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
|
|
||||||
|
// Read query results for displaying in next frame
|
||||||
|
getQueryResults();
|
||||||
|
|
||||||
VulkanExampleBase::submitFrame();
|
VulkanExampleBase::submitFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -728,8 +805,9 @@ public:
|
||||||
{
|
{
|
||||||
VulkanExampleBase::prepare();
|
VulkanExampleBase::prepare();
|
||||||
loadMeshes();
|
loadMeshes();
|
||||||
generateTerrain();
|
|
||||||
loadTextures();
|
loadTextures();
|
||||||
|
generateTerrain();
|
||||||
|
setupQueryResultBuffer();
|
||||||
setupVertexDescriptions();
|
setupVertexDescriptions();
|
||||||
prepareUniformBuffers();
|
prepareUniformBuffers();
|
||||||
setupDescriptorSetLayouts();
|
setupDescriptorSetLayouts();
|
||||||
|
|
@ -810,6 +888,10 @@ public:
|
||||||
textOverlay->addText("Press \"f\" to toggle wireframe", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
|
textOverlay->addText("Press \"f\" to toggle wireframe", 5.0f, 100.0f, VulkanTextOverlay::alignLeft);
|
||||||
textOverlay->addText("Press \"t\" to toggle tessellation", 5.0f, 115.0f, VulkanTextOverlay::alignLeft);
|
textOverlay->addText("Press \"t\" to toggle tessellation", 5.0f, 115.0f, VulkanTextOverlay::alignLeft);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
textOverlay->addText("pipeline stats:", width - 5.0f, 5.0f, VulkanTextOverlay::alignRight);
|
||||||
|
textOverlay->addText("VS:" + std::to_string(pipelineStats[0]), width - 5.0f, 20.0f, VulkanTextOverlay::alignRight);
|
||||||
|
textOverlay->addText("TE:" + std::to_string(pipelineStats[1]), width - 5.0f, 35.0f, VulkanTextOverlay::alignRight);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue