2017-10-11 23:28:06 +02:00
|
|
|
#include "dxvk_shader.h"
|
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
2018-07-30 20:15:19 +02:00
|
|
|
DxvkShaderConstData::DxvkShaderConstData() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkShaderConstData::DxvkShaderConstData(
|
|
|
|
size_t dwordCount,
|
|
|
|
const uint32_t* dwordArray)
|
|
|
|
: m_size(dwordCount), m_data(new uint32_t[dwordCount]) {
|
|
|
|
for (size_t i = 0; i < dwordCount; i++)
|
|
|
|
m_data[i] = dwordArray[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkShaderConstData::DxvkShaderConstData(DxvkShaderConstData&& other)
|
|
|
|
: m_size(other.m_size), m_data(other.m_data) {
|
|
|
|
other.m_size = 0;
|
|
|
|
other.m_data = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkShaderConstData& DxvkShaderConstData::operator = (DxvkShaderConstData&& other) {
|
|
|
|
delete[] m_data;
|
|
|
|
this->m_size = other.m_size;
|
|
|
|
this->m_data = other.m_data;
|
|
|
|
other.m_size = 0;
|
|
|
|
other.m_data = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkShaderConstData::~DxvkShaderConstData() {
|
|
|
|
delete[] m_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-07 09:38:31 +01:00
|
|
|
DxvkShaderModule::DxvkShaderModule(
|
2017-11-20 14:03:00 +01:00
|
|
|
const Rc<vk::DeviceFn>& vkd,
|
2018-05-03 20:26:55 +02:00
|
|
|
const Rc<DxvkShader>& shader,
|
|
|
|
const SpirvCodeBuffer& code)
|
|
|
|
: m_vkd(vkd), m_shader(shader) {
|
2017-11-20 14:03:00 +01:00
|
|
|
VkShaderModuleCreateInfo info;
|
|
|
|
info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
|
|
info.pNext = nullptr;
|
|
|
|
info.flags = 0;
|
|
|
|
info.codeSize = code.size();
|
|
|
|
info.pCode = code.data();
|
|
|
|
|
|
|
|
if (m_vkd->vkCreateShaderModule(m_vkd->device(),
|
|
|
|
&info, nullptr, &m_module) != VK_SUCCESS)
|
|
|
|
throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to create shader module");
|
2017-10-11 23:28:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-07 09:38:31 +01:00
|
|
|
DxvkShaderModule::~DxvkShaderModule() {
|
2017-11-20 14:03:00 +01:00
|
|
|
m_vkd->vkDestroyShaderModule(
|
|
|
|
m_vkd->device(), m_module, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-10 11:44:40 +01:00
|
|
|
VkPipelineShaderStageCreateInfo DxvkShaderModule::stageInfo(const VkSpecializationInfo* specInfo) const {
|
2017-11-20 14:03:00 +01:00
|
|
|
VkPipelineShaderStageCreateInfo info;
|
|
|
|
info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
|
|
info.pNext = nullptr;
|
|
|
|
info.flags = 0;
|
2018-05-03 20:26:55 +02:00
|
|
|
info.stage = m_shader->stage();
|
2017-11-20 14:03:00 +01:00
|
|
|
info.module = m_module;
|
|
|
|
info.pName = "main";
|
2018-01-10 11:44:40 +01:00
|
|
|
info.pSpecializationInfo = specInfo;
|
2017-11-20 14:03:00 +01:00
|
|
|
return info;
|
2017-10-14 23:52:47 +02:00
|
|
|
}
|
|
|
|
|
2017-12-07 09:38:31 +01:00
|
|
|
|
|
|
|
DxvkShader::DxvkShader(
|
2017-12-08 18:14:05 +01:00
|
|
|
VkShaderStageFlagBits stage,
|
|
|
|
uint32_t slotCount,
|
|
|
|
const DxvkResourceSlot* slotInfos,
|
2018-01-12 14:25:26 +01:00
|
|
|
const DxvkInterfaceSlots& iface,
|
2018-07-30 20:15:19 +02:00
|
|
|
const SpirvCodeBuffer& code,
|
2018-06-23 20:19:46 +02:00
|
|
|
const DxvkShaderOptions& options,
|
2018-07-30 20:15:19 +02:00
|
|
|
DxvkShaderConstData&& constData)
|
|
|
|
: m_stage(stage), m_code(code), m_interface(iface),
|
2018-06-23 20:19:46 +02:00
|
|
|
m_options(options), m_constData(std::move(constData)) {
|
2018-05-03 20:07:42 +02:00
|
|
|
// Write back resource slot infos
|
2017-12-07 09:38:31 +01:00
|
|
|
for (uint32_t i = 0; i < slotCount; i++)
|
|
|
|
m_slots.push_back(slotInfos[i]);
|
2018-04-10 12:48:46 +02:00
|
|
|
|
|
|
|
// Gather the offsets where the binding IDs
|
|
|
|
// are stored so we can quickly remap them.
|
|
|
|
for (auto ins : m_code) {
|
|
|
|
if (ins.opCode() == spv::OpDecorate
|
|
|
|
&& ((ins.arg(2) == spv::DecorationBinding)
|
|
|
|
|| (ins.arg(2) == spv::DecorationSpecId)))
|
|
|
|
m_idOffsets.push_back(ins.offset() + 3);
|
|
|
|
}
|
2017-12-07 09:38:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkShader::~DxvkShader() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-08 21:49:30 +02:00
|
|
|
bool DxvkShader::hasCapability(spv::Capability cap) {
|
|
|
|
for (auto ins : m_code) {
|
|
|
|
// OpCapability instructions come first
|
|
|
|
if (ins.opCode() != spv::OpCapability)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (ins.arg(1) == cap)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-07 09:38:31 +01:00
|
|
|
void DxvkShader::defineResourceSlots(
|
|
|
|
DxvkDescriptorSlotMapping& mapping) const {
|
|
|
|
for (const auto& slot : m_slots)
|
2018-01-09 20:35:29 +01:00
|
|
|
mapping.defineSlot(slot.slot, slot.type, slot.view, m_stage);
|
2017-12-07 09:38:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rc<DxvkShaderModule> DxvkShader::createShaderModule(
|
2017-12-08 18:14:05 +01:00
|
|
|
const Rc<vk::DeviceFn>& vkd,
|
2018-05-03 20:26:55 +02:00
|
|
|
const DxvkDescriptorSlotMapping& mapping) {
|
2017-12-08 22:30:41 +01:00
|
|
|
SpirvCodeBuffer spirvCode = m_code;
|
|
|
|
|
2018-04-10 12:48:46 +02:00
|
|
|
// Remap resource binding IDs
|
|
|
|
uint32_t* code = spirvCode.data();
|
2018-09-01 20:27:36 +02:00
|
|
|
for (uint32_t ofs : m_idOffsets) {
|
|
|
|
if (code[ofs] < MaxNumResourceSlots)
|
|
|
|
code[ofs] = mapping.getBindingId(code[ofs]);
|
|
|
|
}
|
2017-12-08 22:30:41 +01:00
|
|
|
|
2018-05-03 20:26:55 +02:00
|
|
|
return new DxvkShaderModule(vkd, this, spirvCode);
|
2017-12-08 18:14:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-23 18:17:16 +01:00
|
|
|
void DxvkShader::dump(std::ostream& outputStream) const {
|
|
|
|
m_code.store(outputStream);
|
2017-12-07 09:38:31 +01:00
|
|
|
}
|
|
|
|
|
2017-10-11 23:28:06 +02:00
|
|
|
}
|