mirror of
https://github.com/love2d/love.git
synced 2026-08-21 13:09:56 +02:00
vulkan: first iteration for generic uniforms
Until now we only considered the builtin uniform variables. This commit attempts to make the code in the vulkan Shader implementation more general, as to allow for custom uniforms. This is not possible yet, but should be easier to implement now.
This commit is contained in:
@@ -1671,6 +1671,43 @@ endif()
|
|||||||
|
|
||||||
add_library(love_3p_physfs ${LOVE_SRC_3P_PHYSFS})
|
add_library(love_3p_physfs ${LOVE_SRC_3P_PHYSFS})
|
||||||
|
|
||||||
|
#
|
||||||
|
# spirv_cross
|
||||||
|
#
|
||||||
|
|
||||||
|
set(LOVE_SRC_3P_SPIRV_CROSS
|
||||||
|
src/libraries/spirv_cross/GLSL.std.450.h
|
||||||
|
src/libraries/spirv_cross/spirv_cfg.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_cfg.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_common.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_cpp.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_cpp.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_c.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_c.h
|
||||||
|
src/libraries/spirv_cross/spirv_cross_containers.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_error_handling.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_parsed_ir.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_util.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross_util.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_cross.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_glsl.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_glsl.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_hlsl.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_hlsl.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_msl.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_msl.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_parser.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_parser.hpp
|
||||||
|
src/libraries/spirv_cross/spirv_reflect.cpp
|
||||||
|
src/libraries/spirv_cross/spirv_reflect.hpp
|
||||||
|
src/libraries/spirv_cross/spirv.h
|
||||||
|
src/libraries/spirv_cross/spirv.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(love_3p_spirv_cross ${LOVE_SRC_3P_SPIRV_CROSS})
|
||||||
|
|
||||||
#
|
#
|
||||||
# stb_image
|
# stb_image
|
||||||
#
|
#
|
||||||
@@ -1752,6 +1789,7 @@ set(LOVE_3P
|
|||||||
love_3p_lz4
|
love_3p_lz4
|
||||||
love_3p_noise1234
|
love_3p_noise1234
|
||||||
love_3p_physfs
|
love_3p_physfs
|
||||||
|
love_3p_spirv_cross
|
||||||
love_3p_wuff
|
love_3p_wuff
|
||||||
love_3p_xxhash
|
love_3p_xxhash
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||||
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
||||||
#include "libraries/spirv_cross/spirv_cross.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -150,12 +150,12 @@ Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::loadVolatile() {
|
bool Shader::loadVolatile() {
|
||||||
calculateUniformBufferSizeAligned();
|
|
||||||
compileShaders();
|
compileShaders();
|
||||||
|
calculateUniformBufferSizeAligned();
|
||||||
createDescriptorSetLayout();
|
createDescriptorSetLayout();
|
||||||
createPipelineLayout();
|
createPipelineLayout();
|
||||||
createStreamBuffers();
|
createStreamBuffers();
|
||||||
currentImage = 0;
|
currentFrame = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -201,42 +201,42 @@ static VkDescriptorImageInfo createDescriptorImageInfo(graphics::Texture* textur
|
|||||||
return imageInfo;
|
return imageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
|
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameIndex) {
|
||||||
// detect wether a new frame has begun
|
// detect wether a new frame has begun
|
||||||
if (currentImage != imageIndex) {
|
if (currentFrame != frameIndex) {
|
||||||
currentImage = imageIndex;
|
currentFrame = frameIndex;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
// we needed more memory last frame, let's collapse all buffers into a single one.
|
// we needed more memory last frame, let's collapse all buffers into a single one.
|
||||||
if (streamBuffers.at(currentImage).size() > 1) {
|
if (streamBuffers.at(currentFrame).size() > 1) {
|
||||||
size_t newSize = 0;
|
size_t newSize = 0;
|
||||||
for (auto streamBuffer : streamBuffers.at(currentImage)) {
|
for (auto streamBuffer : streamBuffers.at(currentFrame)) {
|
||||||
newSize += streamBuffer->getSize();
|
newSize += streamBuffer->getSize();
|
||||||
delete streamBuffer;
|
delete streamBuffer;
|
||||||
}
|
}
|
||||||
streamBuffers.at(currentImage).clear();
|
streamBuffers.at(currentFrame).clear();
|
||||||
streamBuffers.at(currentImage).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, newSize));
|
streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, newSize));
|
||||||
}
|
}
|
||||||
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer
|
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer
|
||||||
else {
|
else {
|
||||||
streamBuffers.at(currentImage).at(0)->nextFrame();
|
streamBuffers.at(currentFrame).at(0)->nextFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// still the same frame
|
// still the same frame
|
||||||
else {
|
else {
|
||||||
auto usedStreamBufferMemory = count * uniformBufferSizeAligned;
|
auto usedStreamBufferMemory = count * uniformBufferSizeAligned;
|
||||||
if (usedStreamBufferMemory >= streamBuffers.at(currentImage).back()->getSize()) {
|
if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize()) {
|
||||||
// we ran out of memory in the current frame, need to allocate more.
|
// we ran out of memory in the current frame, need to allocate more.
|
||||||
streamBuffers.at(currentImage).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
|
streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// additional data is always added onto the last stream buffer in the current frame
|
// additional data is always added onto the last stream buffer in the current frame
|
||||||
auto currentStreamBuffer = streamBuffers.at(currentImage).back();
|
auto currentStreamBuffer = streamBuffers.at(currentFrame).back();
|
||||||
|
|
||||||
auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
|
auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
|
||||||
memcpy(mapInfo.data, &uniformData, uniformBufferSizeAligned);
|
memcpy(mapInfo.data, localUniformStagingData.data(), uniformBufferSizeAligned);
|
||||||
currentStreamBuffer->unmap(uniformBufferSizeAligned);
|
currentStreamBuffer->unmap(uniformBufferSizeAligned);
|
||||||
currentStreamBuffer->markUsed(uniformBufferSizeAligned);
|
currentStreamBuffer->markUsed(uniformBufferSizeAligned);
|
||||||
|
|
||||||
@@ -245,53 +245,42 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t image
|
|||||||
bufferInfo.offset = count * uniformBufferSizeAligned;
|
bufferInfo.offset = count * uniformBufferSizeAligned;
|
||||||
bufferInfo.range = sizeof(BuiltinUniformData);
|
bufferInfo.range = sizeof(BuiltinUniformData);
|
||||||
|
|
||||||
auto mainTexImageInfo = createDescriptorImageInfo(mainTex);
|
std::vector<VkWriteDescriptorSet> descriptorWrite{};
|
||||||
auto ytextureImageInfo = createDescriptorImageInfo(ytexture);
|
|
||||||
auto cbtextureImageInfo = createDescriptorImageInfo(cbtexture);
|
|
||||||
auto crtextureImageInfo = createDescriptorImageInfo(crtexture);
|
|
||||||
|
|
||||||
std::array<VkWriteDescriptorSet, 5> descriptorWrite{};
|
// uniform buffer update always happens.
|
||||||
descriptorWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
VkWriteDescriptorSet uniformWrite{};
|
||||||
descriptorWrite[0].dstSet = 0;
|
uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptorWrite[0].dstBinding = 0;
|
uniformWrite.dstSet = 0;
|
||||||
descriptorWrite[0].dstArrayElement = 0;
|
uniformWrite.dstBinding = builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->location;
|
||||||
descriptorWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
uniformWrite.dstArrayElement = 0;
|
||||||
descriptorWrite[0].descriptorCount = 1;
|
uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
descriptorWrite[0].pBufferInfo = &bufferInfo;
|
uniformWrite.descriptorCount = 1;
|
||||||
|
uniformWrite.pBufferInfo = &bufferInfo;
|
||||||
|
|
||||||
descriptorWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptorWrite.push_back(uniformWrite);
|
||||||
descriptorWrite[1].dstSet = 0;
|
|
||||||
descriptorWrite[1].dstBinding = 1;
|
|
||||||
descriptorWrite[1].dstArrayElement = 0;
|
|
||||||
descriptorWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
descriptorWrite[1].descriptorCount = 1;
|
|
||||||
descriptorWrite[1].pImageInfo = &mainTexImageInfo;
|
|
||||||
|
|
||||||
descriptorWrite[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
// update everything other than uniform buffers (since that's already taken care of.
|
||||||
descriptorWrite[2].dstSet = 0;
|
for (const auto& [key, val] : uniformInfos) {
|
||||||
descriptorWrite[2].dstBinding = 2;
|
// fixme: other types.
|
||||||
descriptorWrite[2].dstArrayElement = 0;
|
if (val.baseType == UNIFORM_SAMPLER) {
|
||||||
descriptorWrite[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
VkWriteDescriptorSet write{};
|
||||||
descriptorWrite[2].descriptorCount = 1;
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptorWrite[2].pImageInfo = &ytextureImageInfo;
|
write.dstSet = 0;
|
||||||
|
write.dstBinding = val.location;
|
||||||
|
write.dstArrayElement = 0;
|
||||||
|
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
write.descriptorCount = 1;
|
||||||
|
const auto imageInfo = createDescriptorImageInfo(val.textures[0]); // fixme: arrays
|
||||||
|
write.pImageInfo = &imageInfo;
|
||||||
|
|
||||||
descriptorWrite[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptorWrite.push_back(write);
|
||||||
descriptorWrite[3].dstSet = 0;
|
}
|
||||||
descriptorWrite[3].dstBinding = 3;
|
}
|
||||||
descriptorWrite[3].dstArrayElement = 0;
|
|
||||||
descriptorWrite[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
descriptorWrite[3].descriptorCount = 1;
|
|
||||||
descriptorWrite[3].pImageInfo = &cbtextureImageInfo;
|
|
||||||
|
|
||||||
descriptorWrite[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
vkCmdPushDescriptorSet(
|
||||||
descriptorWrite[4].dstSet = 0;
|
commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
descriptorWrite[4].dstBinding = 4;
|
pipelineLayout, 0,
|
||||||
descriptorWrite[4].dstArrayElement = 0;
|
static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data());
|
||||||
descriptorWrite[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
descriptorWrite[4].descriptorCount = 1;
|
|
||||||
descriptorWrite[4].pImageInfo = &crtextureImageInfo;
|
|
||||||
|
|
||||||
vkCmdPushDescriptorSet(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data());
|
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -309,22 +298,89 @@ void Shader::attach() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Shader::getVertexAttributeIndex(const std::string& name) {
|
int Shader::getVertexAttributeIndex(const std::string& name) {
|
||||||
return vertexAttributeIndices.at(name);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::calculateUniformBufferSizeAligned() {
|
void Shader::calculateUniformBufferSizeAligned() {
|
||||||
gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
|
gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
|
||||||
auto vgfx = (Graphics*)gfx;
|
auto vgfx = (Graphics*)gfx;
|
||||||
auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
|
auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
|
||||||
|
size_t size = localUniformStagingData.size();
|
||||||
uniformBufferSizeAligned =
|
uniformBufferSizeAligned =
|
||||||
static_cast<VkDeviceSize>(
|
static_cast<VkDeviceSize>(
|
||||||
std::ceil(
|
std::ceil(
|
||||||
static_cast<float>(sizeof(BuiltinUniformData)) / static_cast<float>(minAlignment)
|
static_cast<float>(size) / static_cast<float>(minAlignment)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
* minAlignment;
|
* minAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType& type, size_t baseoff, const std::string& basename) {
|
||||||
|
using namespace spirv_cross;
|
||||||
|
|
||||||
|
const auto& membertypes = type.member_types;
|
||||||
|
|
||||||
|
for (size_t uindex = 0; uindex < membertypes.size(); uindex) {
|
||||||
|
const auto& memberType = comp.get_type(membertypes[uindex]);
|
||||||
|
size_t memberSize = comp.get_declared_struct_member_size(type, uindex);
|
||||||
|
size_t offset = baseoff + comp.type_struct_member_offset(type, uindex);
|
||||||
|
|
||||||
|
std::string name = basename + comp.get_member_name(type.self, uindex);
|
||||||
|
|
||||||
|
switch (memberType.basetype) {
|
||||||
|
case SPIRType::Struct:
|
||||||
|
name += ".";
|
||||||
|
buildLocalUniforms(comp, memberType, offset, name);
|
||||||
|
continue;
|
||||||
|
case SPIRType::Int:
|
||||||
|
case SPIRType::UInt:
|
||||||
|
case SPIRType::Float:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformInfo u = {};
|
||||||
|
u.name = name;
|
||||||
|
u.dataSize = memberSize;
|
||||||
|
u.count = memberType.array.empty() ? 1 : memberType.array[0];
|
||||||
|
u.components = 1;
|
||||||
|
u.data = localUniformStagingData.data() + offset;
|
||||||
|
|
||||||
|
if (memberType.columns == 1) {
|
||||||
|
if (memberType.basetype == SPIRType::Int) {
|
||||||
|
u.baseType = UNIFORM_INT;
|
||||||
|
}
|
||||||
|
else if (memberType.basetype == SPIRType::UInt) {
|
||||||
|
u.baseType = UNIFORM_UINT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u.baseType = UNIFORM_FLOAT;
|
||||||
|
}
|
||||||
|
u.components = memberType.vecsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u.baseType = UNIFORM_MATRIX;
|
||||||
|
u.matrix.rows = memberType.vecsize;
|
||||||
|
u.matrix.columns = memberType.columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixme: initializer values
|
||||||
|
|
||||||
|
uniformInfos[u.name] = u;
|
||||||
|
|
||||||
|
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
||||||
|
if (getConstant(u.name.c_str(), builtin)) {
|
||||||
|
if (builtin == BUILTIN_UNIFORMS_PER_DRAW) {
|
||||||
|
builtinUniformDataOffset = offset;
|
||||||
|
}
|
||||||
|
builtinUniformInfo[builtin] = &uniformInfos[u.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// update uniform.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Shader::compileShaders() {
|
void Shader::compileShaders() {
|
||||||
using namespace glslang;
|
using namespace glslang;
|
||||||
using namespace spirv_cross;
|
using namespace spirv_cross;
|
||||||
@@ -335,7 +391,6 @@ void Shader::compileShaders() {
|
|||||||
auto vgfx = (Graphics*)gfx;
|
auto vgfx = (Graphics*)gfx;
|
||||||
device = vgfx->getDevice();
|
device = vgfx->getDevice();
|
||||||
|
|
||||||
mainTex = vgfx->getDefaultTexture();
|
|
||||||
ytexture = vgfx->getDefaultTexture();
|
ytexture = vgfx->getDefaultTexture();
|
||||||
crtexture = vgfx->getDefaultTexture();
|
crtexture = vgfx->getDefaultTexture();
|
||||||
cbtexture = vgfx->getDefaultTexture();
|
cbtexture = vgfx->getDefaultTexture();
|
||||||
@@ -385,6 +440,8 @@ void Shader::compileShaders() {
|
|||||||
throw love::Exception("mapIO failed");
|
throw love::Exception("mapIO failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uniformInfos.clear();
|
||||||
|
|
||||||
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
|
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
|
||||||
auto glslangStage = getGlslShaderType((ShaderStageType)i);
|
auto glslangStage = getGlslShaderType((ShaderStageType)i);
|
||||||
auto intermediate = program->getIntermediate(glslangStage);
|
auto intermediate = program->getIntermediate(glslangStage);
|
||||||
@@ -424,49 +481,158 @@ void Shader::compileShaders() {
|
|||||||
shaderStageInfo.pName = "main";
|
shaderStageInfo.pName = "main";
|
||||||
|
|
||||||
shaderStages.push_back(shaderStageInfo);
|
shaderStages.push_back(shaderStageInfo);
|
||||||
|
|
||||||
|
spirv_cross::CompilerGLSL comp(spirv);
|
||||||
|
|
||||||
|
// we only care about variables that are actually getting used.
|
||||||
|
auto active = comp.get_active_interface_variables();
|
||||||
|
auto shaderResources = comp.get_shader_resources(active);
|
||||||
|
comp.set_enabled_interface_variables(std::move(active));
|
||||||
|
|
||||||
|
std::string builtinUniformName = "love_UniformsPerDraw";
|
||||||
|
|
||||||
|
for (const auto& resource : shaderResources.uniform_buffers) {
|
||||||
|
size_t uniformBufferObjectSize = comp.get_declared_struct_size(comp.get_type(resource.base_type_id));
|
||||||
|
|
||||||
|
const auto& resourceType = comp.get_type(resource.type_id);
|
||||||
|
unsigned memberCount = resourceType.member_types.size();
|
||||||
|
for (unsigned i = 0; i < memberCount; i++) {
|
||||||
|
auto& type = comp.get_type(resourceType.member_types[i]);
|
||||||
|
auto baseType = type.basetype;
|
||||||
|
const std::string& name = comp.get_member_name(resourceType.self, i);
|
||||||
|
|
||||||
|
if (name == "gl_DefaultUniformBlock") {
|
||||||
|
auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
|
||||||
|
localUniformStagingData.resize(defaultUniformBlockSize);
|
||||||
|
|
||||||
|
std::string basename("");
|
||||||
|
buildLocalUniforms(comp, type, 0, basename);
|
||||||
|
}
|
||||||
|
else if (name == builtinUniformName) {
|
||||||
|
UniformInfo u{};
|
||||||
|
u.name = name;
|
||||||
|
u.dataSize = sizeof(BuiltinUniformData);
|
||||||
|
|
||||||
|
localUniformStagingData.resize(u.dataSize);
|
||||||
|
builtinUniformDataOffset = 0;
|
||||||
|
|
||||||
|
u.count = type.array.empty() ? 1 : type.array[0];
|
||||||
|
u.components = 1;
|
||||||
|
u.data = localUniformStagingData.data();
|
||||||
|
|
||||||
|
if (type.columns == 1) {
|
||||||
|
if (type.basetype == SPIRType::Int) {
|
||||||
|
u.baseType = UNIFORM_INT;
|
||||||
|
}
|
||||||
|
else if (type.basetype == SPIRType::UInt) {
|
||||||
|
u.baseType = UNIFORM_UINT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u.baseType = UNIFORM_FLOAT;
|
||||||
|
}
|
||||||
|
u.components = type.vecsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u.baseType = UNIFORM_MATRIX;
|
||||||
|
u.matrix.rows = type.vecsize;
|
||||||
|
u.matrix.columns = type.columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
uniformInfos[u.name] = u;
|
||||||
|
|
||||||
|
builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW] = &uniformInfos[u.name];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw love::Exception("unimplemented: non default uniform blocks.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& r : shaderResources.sampled_images) {
|
||||||
|
const SPIRType& basetype = comp.get_type(r.base_type_id);
|
||||||
|
const SPIRType& type = comp.get_type(r.type_id);
|
||||||
|
const SPIRType& imagetype = comp.get_type(basetype.image.type);
|
||||||
|
|
||||||
|
graphics::Shader::UniformInfo info;
|
||||||
|
info.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
||||||
|
info.baseType = UNIFORM_SAMPLER;
|
||||||
|
info.name = r.name;
|
||||||
|
info.count = type.array.empty() ? 1 : type.array[0];
|
||||||
|
info.isDepthSampler = type.image.depth;
|
||||||
|
info.components = 1;
|
||||||
|
|
||||||
|
switch (imagetype.basetype) {
|
||||||
|
case SPIRType::Float:
|
||||||
|
info.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||||
|
break;
|
||||||
|
case SPIRType::Int:
|
||||||
|
info.dataBaseType = DATA_BASETYPE_INT;
|
||||||
|
break;
|
||||||
|
case SPIRType::UInt:
|
||||||
|
info.dataBaseType = DATA_BASETYPE_UINT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (basetype.image.dim) {
|
||||||
|
case spv::Dim2D:
|
||||||
|
info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
|
||||||
|
info.textures = new love::graphics::Texture * [info.count];
|
||||||
|
break;
|
||||||
|
case spv::Dim3D:
|
||||||
|
info.textureType = TEXTURE_VOLUME;
|
||||||
|
info.textures = new love::graphics::Texture * [info.count];
|
||||||
|
break;
|
||||||
|
case spv::DimCube:
|
||||||
|
if (basetype.image.arrayed) {
|
||||||
|
throw love::Exception("cubemap arrays are not currently supported");
|
||||||
|
}
|
||||||
|
info.textureType = TEXTURE_CUBE;
|
||||||
|
info.textures = new love::graphics::Texture * [info.count];
|
||||||
|
break;
|
||||||
|
case spv::DimBuffer:
|
||||||
|
throw love::Exception("dim buffers not implemented yet");
|
||||||
|
default:
|
||||||
|
throw love::Exception("unknown dim");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.baseType == UNIFORM_SAMPLER) {
|
||||||
|
auto tex = vgfx->getDefaultTexture();
|
||||||
|
for (int i = 0; i < info.count; i++) {
|
||||||
|
info.textures[i] = tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fixme
|
||||||
|
else if (info.baseType == UNIFORM_TEXELBUFFER) {
|
||||||
|
throw love::Exception("texel buffers not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
uniformInfos[r.name] = info;
|
||||||
|
BuiltinUniform builtin;
|
||||||
|
if (getConstant(r.name.c_str(), builtin)) {
|
||||||
|
builtinUniformInfo[builtin] = &uniformInfos[info.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixme: should generate this dynamically.
|
|
||||||
void Shader::createDescriptorSetLayout() {
|
void Shader::createDescriptorSetLayout() {
|
||||||
auto vgfx = (Graphics*)gfx;
|
auto vgfx = (Graphics*)gfx;
|
||||||
vkCmdPushDescriptorSet = vgfx->getVkCmdPushDescriptorSetKHRFunctionPointer();
|
vkCmdPushDescriptorSet = vgfx->getVkCmdPushDescriptorSetKHRFunctionPointer();
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding uboLayoutBinding{};
|
std::vector<VkDescriptorSetLayoutBinding> bindings;
|
||||||
uboLayoutBinding.binding = 0;
|
|
||||||
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
||||||
uboLayoutBinding.descriptorCount = 1;
|
|
||||||
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
|
for (auto const& [key, val] : uniformInfos) {
|
||||||
samplerLayoutBinding.binding = 1;
|
VkDescriptorSetLayoutBinding layoutBinding{};
|
||||||
samplerLayoutBinding.descriptorCount = 1;
|
layoutBinding.binding = val.location;
|
||||||
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
layoutBinding.descriptorType = val.baseType == UNIFORM_SAMPLER ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
samplerLayoutBinding.pImmutableSamplers = nullptr;
|
layoutBinding.descriptorCount = 1; // is this correct?
|
||||||
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; // fixme: can we determine in what shader it got used?
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding videoYBinding{};
|
bindings.push_back(layoutBinding);
|
||||||
videoYBinding.binding = 2;
|
}
|
||||||
videoYBinding.descriptorCount = 1;
|
|
||||||
videoYBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
videoYBinding.pImmutableSamplers = nullptr;
|
|
||||||
videoYBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding videoCBBinding{};
|
|
||||||
videoCBBinding.binding = 3;
|
|
||||||
videoCBBinding.descriptorCount = 1;
|
|
||||||
videoCBBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
videoCBBinding.pImmutableSamplers = nullptr;
|
|
||||||
videoCBBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding videoCRinding{};
|
|
||||||
videoCRinding.binding = 4;
|
|
||||||
videoCRinding.descriptorCount = 1;
|
|
||||||
videoCRinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
videoCRinding.pImmutableSamplers = nullptr;
|
|
||||||
videoCRinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
||||||
|
|
||||||
std::array<VkDescriptorSetLayoutBinding, 5> bindings = { uboLayoutBinding, samplerLayoutBinding, videoYBinding, videoCBBinding, videoCRinding };
|
|
||||||
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
||||||
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
|
layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
|
||||||
@@ -506,11 +672,12 @@ void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cb
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shader::setUniformData(BuiltinUniformData& data) {
|
void Shader::setUniformData(BuiltinUniformData& data) {
|
||||||
uniformData = data;
|
char* ptr = (char*) builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->data + builtinUniformDataOffset;
|
||||||
|
memcpy(ptr, &data, sizeof(BuiltinUniformData));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::setMainTex(graphics::Texture* texture) {
|
void Shader::setMainTex(graphics::Texture* texture) {
|
||||||
mainTex = texture;
|
builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture;
|
||||||
}
|
}
|
||||||
} // vulkan
|
} // vulkan
|
||||||
} // graphics
|
} // graphics
|
||||||
|
|||||||
@@ -6,9 +6,12 @@
|
|||||||
#include "Vulkan.h"
|
#include "Vulkan.h"
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
#include "libraries/spirv_cross/spirv_reflect.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|
||||||
namespace love {
|
namespace love {
|
||||||
@@ -26,7 +29,7 @@ public:
|
|||||||
|
|
||||||
const VkPipelineLayout getGraphicsPipelineLayout() const;
|
const VkPipelineLayout getGraphicsPipelineLayout() const;
|
||||||
|
|
||||||
void cmdPushDescriptorSets(VkCommandBuffer, uint32_t currentImage);
|
void cmdPushDescriptorSets(VkCommandBuffer, uint32_t currentFrame);
|
||||||
|
|
||||||
void attach() override;
|
void attach() override;
|
||||||
|
|
||||||
@@ -58,6 +61,11 @@ private:
|
|||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createPipelineLayout();
|
void createPipelineLayout();
|
||||||
void createStreamBuffers();
|
void createStreamBuffers();
|
||||||
|
void buildLocalUniforms(
|
||||||
|
spirv_cross::Compiler& comp,
|
||||||
|
const spirv_cross::SPIRType& type,
|
||||||
|
size_t baseoff,
|
||||||
|
const std::string& basename);
|
||||||
|
|
||||||
VkDeviceSize uniformBufferSizeAligned;
|
VkDeviceSize uniformBufferSizeAligned;
|
||||||
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSet;
|
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSet;
|
||||||
@@ -75,27 +83,18 @@ private:
|
|||||||
Graphics* gfx;
|
Graphics* gfx;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
|
|
||||||
std::map<std::string, int> vertexAttributeIndices = {
|
std::unordered_map<std::string, graphics::Shader::UniformInfo> uniformInfos;
|
||||||
{ "VertexPosition", 0 },
|
UniformInfo* builtinUniformInfo[BUILTIN_MAX_ENUM];
|
||||||
{ "VertexTexCoord", 1 },
|
|
||||||
{ "VertexColor", 2 }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<std::string, int> uniformBindings = {
|
std::unique_ptr<StreamBuffer> uniformBufferObjectBuffer;
|
||||||
{ "love_UniformsPerDraw", 0 },
|
std::vector<uint8> localUniformStagingData;
|
||||||
{ "love_VideoYChannel", 1 },
|
size_t builtinUniformDataOffset;
|
||||||
{ "love_VideoCbChannel", 2 },
|
|
||||||
{ "love_VideoCrChannel", 3 },
|
|
||||||
{ "MainTex", 4 }
|
|
||||||
};
|
|
||||||
|
|
||||||
BuiltinUniformData uniformData;
|
|
||||||
graphics::Texture* mainTex;
|
|
||||||
graphics::Texture* ytexture;
|
graphics::Texture* ytexture;
|
||||||
graphics::Texture* cbtexture;
|
graphics::Texture* cbtexture;
|
||||||
graphics::Texture* crtexture;
|
graphics::Texture* crtexture;
|
||||||
|
|
||||||
uint32_t currentImage;
|
uint32_t currentFrame;
|
||||||
// todo: give this variable a better name
|
// todo: give this variable a better name
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user