Not even with long texts and small scales
This commit is contained in:
@@ -199,6 +199,10 @@ StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, uint32 stride, co
|
||||
, contents(resourceData.size)
|
||||
, stride(stride)
|
||||
{
|
||||
if(resourceData.data != nullptr)
|
||||
{
|
||||
std::memcpy(contents.data(), resourceData.data, resourceData.size);
|
||||
}
|
||||
}
|
||||
StructuredBuffer::~StructuredBuffer()
|
||||
{
|
||||
|
||||
@@ -27,23 +27,38 @@ void TextPass::beginFrame()
|
||||
float y = render.position.y;
|
||||
for(uint32 c : render.text)
|
||||
{
|
||||
const GlyphData& glyph = fontData.glyphDataSet[fontData.characterToGlyphIndex[c]];
|
||||
Vector2 bearing = glyph.bearing;
|
||||
Vector2 size = glyph.size;
|
||||
float xpos = x + bearing.x * render.scale;
|
||||
float ypos = y - (size.y - bearing.y) * render.scale;
|
||||
|
||||
float w = size.x * render.scale;
|
||||
float h = size.y * render.scale;
|
||||
|
||||
instanceData.add(GlyphInstanceData{
|
||||
.position = Vector2(xpos, ypos),
|
||||
.widthHeight = Vector2(w, h),
|
||||
.glyphIndex = fontData.characterToGlyphIndex[c],
|
||||
.position = Vector2(x, y)
|
||||
});
|
||||
x += (fontData.characterAdvance[c] >> 6) * render.scale;
|
||||
x += (glyph.advance >> 6) * render.scale;
|
||||
}
|
||||
VertexBufferCreateInfo vbInfo;
|
||||
vbInfo.numVertices = static_cast<uint32>(instanceData.size());
|
||||
vbInfo.vertexSize = sizeof(GlyphInstanceData);
|
||||
vbInfo.resourceData.data = reinterpret_cast<uint8*>(instanceData.data());
|
||||
vbInfo.resourceData.size = static_cast<uint32>(instanceData.size() * sizeof(GlyphInstanceData));
|
||||
VertexBufferCreateInfo vbInfo = {
|
||||
.resourceData = {
|
||||
.size = static_cast<uint32>(instanceData.size() * sizeof(GlyphInstanceData)),
|
||||
.data = reinterpret_cast<uint8*>(instanceData.data()),
|
||||
},
|
||||
.vertexSize = sizeof(GlyphInstanceData),
|
||||
.numVertices = static_cast<uint32>(instanceData.size()),
|
||||
};
|
||||
resources.vertexBuffer = graphics->createVertexBuffer(vbInfo);
|
||||
|
||||
resources.glyphDataSet = fontData.glyphDataSet;
|
||||
resources.textureArraySet = fontData.textureArraySet;
|
||||
|
||||
resources.scale = render.scale;
|
||||
resources.textData = {
|
||||
.textColor = render.textColor,
|
||||
.scale = render.scale,
|
||||
};
|
||||
}
|
||||
//co_return;
|
||||
}
|
||||
@@ -57,10 +72,10 @@ void TextPass::render()
|
||||
Gfx::PRenderCommand command = graphics->createRenderCommand("TextPassCommand");
|
||||
command->setViewport(viewport);
|
||||
command->bindPipeline(pipeline);
|
||||
command->bindDescriptor({generalSet, resources.glyphDataSet, resources.textureArraySet});
|
||||
command->bindDescriptor({generalSet, resources.textureArraySet});
|
||||
command->bindVertexBuffer({VertexInputStream(0, 0, resources.vertexBuffer)});
|
||||
|
||||
command->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float), &resources.scale);
|
||||
command->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TextData), &resources.textData);
|
||||
command->draw(4, static_cast<uint32>(resources.vertexBuffer->getNumVertices()), 0, 0);
|
||||
commands.add(command);
|
||||
}
|
||||
@@ -101,36 +116,39 @@ void TextPass::createRenderPass()
|
||||
Array<Gfx::VertexElement> elements;
|
||||
elements.add({
|
||||
.streamIndex = 0,
|
||||
.offset = offsetof(GlyphInstanceData, glyphIndex),
|
||||
.vertexFormat = Gfx::SE_FORMAT_R32_UINT,
|
||||
.offset = offsetof(GlyphInstanceData, position),
|
||||
.vertexFormat = Gfx::SE_FORMAT_R32G32_SFLOAT,
|
||||
.attributeIndex = 0,
|
||||
.stride = sizeof(GlyphInstanceData),
|
||||
.bInstanced = 1
|
||||
});
|
||||
elements.add({
|
||||
.streamIndex = 0,
|
||||
.offset = offsetof(GlyphInstanceData, position),
|
||||
.offset = offsetof(GlyphInstanceData, widthHeight),
|
||||
.vertexFormat = Gfx::SE_FORMAT_R32G32_SFLOAT,
|
||||
.attributeIndex = 1,
|
||||
.stride = sizeof(GlyphInstanceData),
|
||||
.bInstanced = 1
|
||||
});
|
||||
elements.add({
|
||||
.streamIndex = 0,
|
||||
.offset = offsetof(GlyphInstanceData, glyphIndex),
|
||||
.vertexFormat = Gfx::SE_FORMAT_R32_UINT,
|
||||
.attributeIndex = 2,
|
||||
.stride = sizeof(GlyphInstanceData),
|
||||
.bInstanced = 1
|
||||
});
|
||||
declaration = graphics->createVertexDeclaration(elements);
|
||||
|
||||
generalLayout = graphics->createDescriptorLayout("TextGeneral");
|
||||
generalLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
generalLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER);
|
||||
generalLayout->create();
|
||||
|
||||
glyphDataLayout = graphics->createDescriptorLayout("TextGlyphData");
|
||||
glyphDataLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
glyphDataLayout->create();
|
||||
|
||||
textureArrayLayout = graphics->createDescriptorLayout("TextTextureArray");
|
||||
textureArrayLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT);
|
||||
textureArrayLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 256, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT);
|
||||
textureArrayLayout->create();
|
||||
|
||||
|
||||
Matrix4 projectionMatrix = glm::ortho(0.f, (float)viewport->getSizeX(), 0.f, (float)viewport->getSizeY());
|
||||
projectionBuffer = graphics->createUniformBuffer({
|
||||
.resourceData = {
|
||||
@@ -154,12 +172,11 @@ void TextPass::createRenderPass()
|
||||
|
||||
pipelineLayout = graphics->createPipelineLayout();
|
||||
pipelineLayout->addDescriptorLayout(0, generalLayout);
|
||||
pipelineLayout->addDescriptorLayout(1, glyphDataLayout);
|
||||
pipelineLayout->addDescriptorLayout(2, textureArrayLayout);
|
||||
pipelineLayout->addDescriptorLayout(1, textureArrayLayout);
|
||||
pipelineLayout->addPushConstants({
|
||||
.stageFlags = Gfx::SE_SHADER_STAGE_VERTEX_BIT,
|
||||
.stageFlags = Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(float)});
|
||||
.size = sizeof(TextData)});
|
||||
pipelineLayout->create();
|
||||
|
||||
Gfx::PRenderTargetLayout layout = new Gfx::RenderTargetLayout(renderTarget, depthAttachment);
|
||||
@@ -190,34 +207,22 @@ TextPass::FontData& TextPass::getFontData(PFontAsset font)
|
||||
if(fontData.exists(font))
|
||||
{
|
||||
return fontData[font];
|
||||
}
|
||||
const Map<uint32, FontAsset::Glyph>& fontGlyphs = font->getGlyphData();
|
||||
}
|
||||
const auto& fontGlyphs = font->getGlyphData();
|
||||
FontData& fd = fontData[font];
|
||||
Array<GlyphData> buffer;
|
||||
Array<GlyphData> glyphData;
|
||||
Array<Gfx::PTexture> textures;
|
||||
buffer.reserve(fontGlyphs.size());
|
||||
glyphData.reserve(fontGlyphs.size());
|
||||
for(const auto& [key, value] : fontGlyphs)
|
||||
{
|
||||
fd.characterToGlyphIndex[key] = static_cast<uint32>(buffer.size());
|
||||
fd.characterAdvance[key] = value.advance;
|
||||
GlyphData& gd = buffer.add();
|
||||
fd.characterToGlyphIndex[key] = static_cast<uint32>(glyphData.size());
|
||||
GlyphData& gd = glyphData.add();
|
||||
gd.bearing = value.bearing;
|
||||
gd.size = value.size;
|
||||
gd.advance = value.advance;
|
||||
textures.add(value.texture);
|
||||
}
|
||||
StructuredBufferCreateInfo bufferInfo = {
|
||||
.resourceData = {
|
||||
.size = static_cast<uint32>(buffer.size() * sizeof(GlyphData)),
|
||||
.data = reinterpret_cast<uint8*>(buffer.data()),
|
||||
},
|
||||
.stride = sizeof(GlyphData),
|
||||
.bDynamic = false,
|
||||
};
|
||||
|
||||
Gfx::PStructuredBuffer glyphBuffer = graphics->createStructuredBuffer(bufferInfo);
|
||||
fd.glyphDataSet = glyphDataLayout->allocateDescriptorSet();
|
||||
fd.glyphDataSet->updateBuffer(0, glyphBuffer);
|
||||
fd.glyphDataSet->writeChanges();
|
||||
fd.glyphDataSet = glyphData;
|
||||
|
||||
fd.textureArraySet = textureArrayLayout->allocateDescriptorSet();
|
||||
fd.textureArraySet->updateTextureArray(0, textures);
|
||||
|
||||
@@ -37,21 +37,24 @@ private:
|
||||
{
|
||||
Vector2 bearing;
|
||||
Vector2 size;
|
||||
uint32 advance;
|
||||
};
|
||||
struct GlyphInstanceData
|
||||
{
|
||||
uint32 glyphIndex;
|
||||
Vector2 position;
|
||||
Vector2 widthHeight;
|
||||
uint32 glyphIndex;
|
||||
};
|
||||
struct TextData
|
||||
{
|
||||
Vector4 textColor;
|
||||
float scale;
|
||||
};
|
||||
struct FontData
|
||||
{
|
||||
Gfx::PDescriptorSet glyphDataSet;
|
||||
Gfx::PDescriptorSet textureArraySet;
|
||||
Array<GlyphData> glyphDataSet;
|
||||
Map<uint32, uint32> characterToGlyphIndex;
|
||||
// Logically this should be part of GlyphData,
|
||||
// but because GlyphData mirrors shader data and we need
|
||||
// the advance on the CPU, we need this in a separate structure
|
||||
Map<uint32, uint32> characterAdvance;
|
||||
};
|
||||
FontData& getFontData(PFontAsset font);
|
||||
Map<PFontAsset, FontData> fontData;
|
||||
@@ -59,9 +62,8 @@ private:
|
||||
struct TextResources
|
||||
{
|
||||
Gfx::PVertexBuffer vertexBuffer;
|
||||
Gfx::PDescriptorSet glyphDataSet;
|
||||
Gfx::PDescriptorSet textureArraySet;
|
||||
float scale;
|
||||
TextData textData;
|
||||
};
|
||||
Array<TextResources> textResources;
|
||||
|
||||
@@ -70,7 +72,6 @@ private:
|
||||
Gfx::PTexture2D depthBuffer;
|
||||
|
||||
Gfx::PDescriptorLayout generalLayout;
|
||||
Gfx::PDescriptorLayout glyphDataLayout;
|
||||
Gfx::PDescriptorLayout textureArrayLayout;
|
||||
|
||||
Gfx::PDescriptorSet generalSet;
|
||||
|
||||
@@ -90,16 +90,18 @@ PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDevice
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
for (auto& [allocatedOffset, freeAllocation] : freeRanges)
|
||||
for (auto& it : freeRanges)
|
||||
{
|
||||
VkDeviceSize allocatedOffset = it.first;
|
||||
PSubAllocation freeAllocation = it.second;
|
||||
assert(allocatedOffset == freeAllocation->allocatedOffset);
|
||||
VkDeviceSize alignedOffset = align(allocatedOffset, alignment);
|
||||
VkDeviceSize alignmentAdjustment = alignedOffset - allocatedOffset;
|
||||
VkDeviceSize size = alignmentAdjustment + requestedSize;
|
||||
if (freeAllocation->size == size)
|
||||
{
|
||||
freeRanges.erase(allocatedOffset);
|
||||
activeAllocations[allocatedOffset] = freeAllocation.getHandle();
|
||||
freeRanges.erase(allocatedOffset);
|
||||
bytesUsed += size;
|
||||
return freeAllocation;
|
||||
}
|
||||
@@ -184,7 +186,10 @@ void Allocation::markFree(SubAllocation *allocation)
|
||||
activeAllocations.erase(allocation->allocatedOffset);
|
||||
}
|
||||
bytesUsed -= allocation->allocatedSize;
|
||||
// TODO: delete allocation when bytesUsed == 0
|
||||
if(bytesUsed == 0)
|
||||
{
|
||||
allocator->free(this);
|
||||
}
|
||||
}
|
||||
|
||||
Allocator::Allocator(PGraphics graphics)
|
||||
@@ -230,6 +235,7 @@ PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2
|
||||
{
|
||||
PAllocation newAllocation = new Allocation(graphics, this, requirements.size, memoryTypeIndex, properties, dedicatedInfo);
|
||||
heaps[heapIndex].allocations.add(newAllocation);
|
||||
heaps[heapIndex].inUse += newAllocation->bytesAllocated;
|
||||
return newAllocation->getSuballocation(requirements.size, requirements.alignment);
|
||||
}
|
||||
}
|
||||
@@ -245,6 +251,7 @@ PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2
|
||||
// no suitable allocations found, allocate new block
|
||||
PAllocation newAllocation = new Allocation(graphics, this, (requirements.size > MemoryBlockSize) ? requirements.size : (VkDeviceSize)MemoryBlockSize, memoryTypeIndex, properties, nullptr);
|
||||
heaps[heapIndex].allocations.add(newAllocation);
|
||||
heaps[heapIndex].inUse += newAllocation->bytesAllocated;
|
||||
return newAllocation->getSuballocation(requirements.size, requirements.alignment);
|
||||
}
|
||||
|
||||
@@ -257,13 +264,13 @@ void Allocator::free(Allocation *allocation)
|
||||
{
|
||||
if (heap.allocations[i] == allocation)
|
||||
{
|
||||
heap.inUse -= allocation->bytesAllocated;
|
||||
heap.allocations.removeAt(i, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VkResult Allocator::findMemoryType(uint32 typeBits, VkMemoryPropertyFlags properties, uint8 *typeIndex)
|
||||
{
|
||||
for (uint8 memoryIndex = 0; memoryIndex < memProperties.memoryTypeCount && typeBits; ++memoryIndex)
|
||||
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
}
|
||||
|
||||
void free(Allocation *allocation);
|
||||
|
||||
void notifyUsageChanged(int64 usageChange);
|
||||
private:
|
||||
enum
|
||||
{
|
||||
@@ -151,6 +151,7 @@ private:
|
||||
struct HeapInfo
|
||||
{
|
||||
VkDeviceSize maxSize = 0;
|
||||
VkDeviceSize inUse = 0;
|
||||
Array<PAllocation> allocations;
|
||||
};
|
||||
Array<HeapInfo> heaps;
|
||||
|
||||
@@ -14,7 +14,7 @@ struct PendingBuffer
|
||||
bool bWriteOnly;
|
||||
};
|
||||
|
||||
static Map<ShaderBuffer *, PendingBuffer> pendingBuffers;
|
||||
static std::map<ShaderBuffer *, PendingBuffer> pendingBuffers;
|
||||
|
||||
ShaderBuffer::ShaderBuffer(PGraphics graphics, uint32 size, VkBufferUsageFlags usage, Gfx::QueueType& queueType, bool bDynamic)
|
||||
: graphics(graphics)
|
||||
@@ -54,8 +54,7 @@ ShaderBuffer::ShaderBuffer(PGraphics graphics, uint32 size, VkBufferUsageFlags u
|
||||
VK_CHECK(vkCreateBuffer(graphics->getDevice(), &info, nullptr, &buffers[i].buffer));
|
||||
bufferReqInfo.buffer = buffers[i].buffer;
|
||||
vkGetBufferMemoryRequirements2(graphics->getDevice(), &bufferReqInfo, &memRequirements);
|
||||
auto temp = graphics->getAllocator()->allocate(memRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buffers[i].buffer);
|
||||
buffers[i].allocation = temp;
|
||||
buffers[i].allocation = graphics->getAllocator()->allocate(memRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buffers[i].buffer);
|
||||
vkBindBufferMemory(graphics->getDevice(), buffers[i].buffer, buffers[i].allocation->getHandle(), buffers[i].allocation->getOffset());
|
||||
}
|
||||
}
|
||||
@@ -245,7 +244,7 @@ void ShaderBuffer::unlock()
|
||||
auto found = pendingBuffers.find(this);
|
||||
if (found != pendingBuffers.end())
|
||||
{
|
||||
PendingBuffer pending = found->value;
|
||||
PendingBuffer pending = found->second;
|
||||
pending.stagingBuffer->flushMappedMemory();
|
||||
pendingBuffers.erase(this);
|
||||
if (pending.bWriteOnly)
|
||||
|
||||
@@ -229,10 +229,6 @@ void Window::present()
|
||||
while (presentResult != VK_SUCCESS)
|
||||
{
|
||||
presentResult = vkQueuePresentKHR(graphics->getGraphicsCommands()->getQueue()->getHandle(), &info);
|
||||
if(presentResult == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
recreateSwapchain(windowState);
|
||||
}
|
||||
}
|
||||
Gfx::currentFrameIndex = (Gfx::currentFrameIndex + 1)%Gfx::numFramesBuffered;
|
||||
static double lastFrameTime = 0.f;
|
||||
|
||||
Reference in New Issue
Block a user