mirror of
https://github.com/wiiu-env/AutobootModule.git
synced 2024-11-17 00:29:15 +01:00
446 lines
19 KiB
C++
446 lines
19 KiB
C++
#include "ShaderSerializer.h"
|
|
#include <cstdint>
|
|
#include <gx2/sampler.h>
|
|
#include <gx2/shaders.h>
|
|
#include <gx2r/buffer.h>
|
|
#include <malloc.h>
|
|
#include <memory>
|
|
#include <span>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
/*
|
|
* Based on https://github.com/Crementif/UntitledSandGame/blob/e752613ba54ac8f6767a8b37e9ac3f68ca180ad7/source/common/shader_serializer.h
|
|
*/
|
|
|
|
template<typename Type>
|
|
static void writeAt(std::vector<uint8_t> &fh, size_t pos, Type value) {
|
|
*reinterpret_cast<Type *>(fh.data() + pos) = value;
|
|
}
|
|
|
|
template<typename Type>
|
|
static void write(std::vector<uint8_t> &fh, Type value) {
|
|
auto pos = fh.size();
|
|
fh.resize(pos + sizeof(Type));
|
|
*reinterpret_cast<Type *>(fh.data() + pos) = value;
|
|
}
|
|
|
|
static void writeString(std::vector<uint8_t> &fh, const char *str) {
|
|
auto pos = fh.size();
|
|
auto len = strlen(str) + 1;
|
|
fh.resize((static_cast<size_t>(pos + len) + (4 - 1)) & ~(4 - 1));
|
|
memcpy(fh.data() + pos, str, len);
|
|
}
|
|
|
|
static void writeGX2RBuffer(std::vector<uint8_t> &fh, GX2RBuffer *buffer) {
|
|
write(fh, buffer->flags);
|
|
write(fh, buffer->elemSize);
|
|
write(fh, buffer->elemCount);
|
|
auto pos = fh.size();
|
|
fh.resize(pos + buffer->elemSize * buffer->elemCount);
|
|
memcpy(fh.data() + pos, buffer->buffer, buffer->elemSize * buffer->elemCount);
|
|
}
|
|
|
|
std::vector<uint8_t> SerializeVertexShader(GX2VertexShader *vertexShader) {
|
|
std::vector<uint8_t> data;
|
|
|
|
// write regs
|
|
write(data, vertexShader->regs.sq_pgm_resources_vs);
|
|
write(data, vertexShader->regs.vgt_primitiveid_en);
|
|
write(data, vertexShader->regs.spi_vs_out_config);
|
|
write(data, vertexShader->regs.num_spi_vs_out_id);
|
|
for (uint32_t spi_vs : vertexShader->regs.spi_vs_out_id) {
|
|
write(data, spi_vs);
|
|
}
|
|
write(data, vertexShader->regs.pa_cl_vs_out_cntl);
|
|
write(data, vertexShader->regs.sq_vtx_semantic_clear);
|
|
write(data, vertexShader->regs.num_sq_vtx_semantic);
|
|
for (uint32_t sq_vtx : vertexShader->regs.sq_vtx_semantic) {
|
|
write(data, sq_vtx);
|
|
}
|
|
write(data, vertexShader->regs.vgt_strmout_buffer_en);
|
|
write(data, vertexShader->regs.vgt_vertex_reuse_block_cntl);
|
|
write(data, vertexShader->regs.vgt_hos_reuse_depth);
|
|
|
|
// write program
|
|
write(data, vertexShader->size);
|
|
for (uint32_t i = 0; i < vertexShader->size; i++) {
|
|
write(data, ((uint8_t *) vertexShader->program)[i]);
|
|
}
|
|
write(data, vertexShader->mode);
|
|
|
|
// write uniform blocks
|
|
write(data, vertexShader->uniformBlockCount);
|
|
for (uint32_t i = 0; i < vertexShader->uniformBlockCount; i++) {
|
|
writeString(data, vertexShader->uniformBlocks[i].name);
|
|
write(data, vertexShader->uniformBlocks[i].offset);
|
|
write(data, vertexShader->uniformBlocks[i].size);
|
|
}
|
|
|
|
// write uniform vars
|
|
write(data, vertexShader->uniformVarCount);
|
|
for (uint32_t i = 0; i < vertexShader->uniformVarCount; i++) {
|
|
writeString(data, vertexShader->uniformVars[i].name);
|
|
write(data, vertexShader->uniformVars[i].type);
|
|
write(data, vertexShader->uniformVars[i].count);
|
|
write(data, vertexShader->uniformVars[i].offset);
|
|
write(data, vertexShader->uniformVars[i].block);
|
|
}
|
|
|
|
// write initial values
|
|
write(data, vertexShader->initialValueCount);
|
|
for (uint32_t i = 0; i < vertexShader->initialValueCount; i++) {
|
|
write(data, vertexShader->initialValues[i].value[0]);
|
|
write(data, vertexShader->initialValues[i].value[1]);
|
|
write(data, vertexShader->initialValues[i].value[2]);
|
|
write(data, vertexShader->initialValues[i].value[3]);
|
|
write(data, vertexShader->initialValues[i].offset);
|
|
}
|
|
|
|
// write loop vars
|
|
write(data, vertexShader->loopVarCount);
|
|
for (uint32_t i = 0; i < vertexShader->loopVarCount; i++) {
|
|
write(data, vertexShader->loopVars[i].offset);
|
|
write(data, vertexShader->loopVars[i].value);
|
|
}
|
|
|
|
// write sampler vars
|
|
write(data, vertexShader->samplerVarCount);
|
|
for (uint32_t i = 0; i < vertexShader->samplerVarCount; i++) {
|
|
writeString(data, vertexShader->samplerVars[i].name);
|
|
write(data, vertexShader->samplerVars[i].type);
|
|
write(data, vertexShader->samplerVars[i].location);
|
|
}
|
|
|
|
// write attribute vars
|
|
write(data, vertexShader->attribVarCount);
|
|
for (uint32_t i = 0; i < vertexShader->attribVarCount; i++) {
|
|
writeString(data, vertexShader->attribVars[i].name);
|
|
write(data, vertexShader->attribVars[i].type);
|
|
write(data, vertexShader->attribVars[i].count);
|
|
write(data, vertexShader->attribVars[i].location);
|
|
}
|
|
|
|
// write ring item size
|
|
write(data, vertexShader->ringItemsize);
|
|
|
|
// write stream out
|
|
write(data, vertexShader->hasStreamOut);
|
|
for (uint32_t stride : vertexShader->streamOutStride) {
|
|
write(data, stride);
|
|
}
|
|
|
|
// write gx2rBuffer
|
|
writeGX2RBuffer(data, &vertexShader->gx2rBuffer);
|
|
|
|
return data;
|
|
}
|
|
|
|
std::vector<uint8_t> SerializePixelShader(GX2PixelShader *pixelShader) {
|
|
std::vector<uint8_t> data;
|
|
|
|
// write regs
|
|
write(data, pixelShader->regs.sq_pgm_resources_ps);
|
|
write(data, pixelShader->regs.sq_pgm_exports_ps);
|
|
write(data, pixelShader->regs.spi_ps_in_control_0);
|
|
write(data, pixelShader->regs.spi_ps_in_control_1);
|
|
write(data, pixelShader->regs.num_spi_ps_input_cntl);
|
|
for (uint32_t spi_ps : pixelShader->regs.spi_ps_input_cntls) {
|
|
write(data, spi_ps);
|
|
}
|
|
write(data, pixelShader->regs.cb_shader_mask);
|
|
write(data, pixelShader->regs.cb_shader_control);
|
|
write(data, pixelShader->regs.db_shader_control);
|
|
write(data, pixelShader->regs.spi_input_z);
|
|
|
|
// write program
|
|
write(data, pixelShader->size);
|
|
for (uint32_t i = 0; i < pixelShader->size; i++) {
|
|
write(data, ((uint8_t *) pixelShader->program)[i]);
|
|
}
|
|
write(data, pixelShader->mode);
|
|
|
|
// write uniform blocks
|
|
write(data, pixelShader->uniformBlockCount);
|
|
for (uint32_t i = 0; i < pixelShader->uniformBlockCount; i++) {
|
|
writeString(data, pixelShader->uniformBlocks[i].name);
|
|
write(data, pixelShader->uniformBlocks[i].offset);
|
|
write(data, pixelShader->uniformBlocks[i].size);
|
|
}
|
|
|
|
// write uniform vars
|
|
write(data, pixelShader->uniformVarCount);
|
|
for (uint32_t i = 0; i < pixelShader->uniformVarCount; i++) {
|
|
writeString(data, pixelShader->uniformVars[i].name);
|
|
write(data, pixelShader->uniformVars[i].type);
|
|
write(data, pixelShader->uniformVars[i].count);
|
|
write(data, pixelShader->uniformVars[i].offset);
|
|
write(data, pixelShader->uniformVars[i].block);
|
|
}
|
|
|
|
// write initial values
|
|
write(data, pixelShader->initialValueCount);
|
|
for (uint32_t i = 0; i < pixelShader->initialValueCount; i++) {
|
|
write(data, pixelShader->initialValues[i].value[0]);
|
|
write(data, pixelShader->initialValues[i].value[1]);
|
|
write(data, pixelShader->initialValues[i].value[2]);
|
|
write(data, pixelShader->initialValues[i].value[3]);
|
|
write(data, pixelShader->initialValues[i].offset);
|
|
}
|
|
|
|
// write loop vars
|
|
write(data, pixelShader->loopVarCount);
|
|
for (uint32_t i = 0; i < pixelShader->loopVarCount; i++) {
|
|
write(data, pixelShader->loopVars[i].offset);
|
|
write(data, pixelShader->loopVars[i].value);
|
|
}
|
|
|
|
// write sampler vars
|
|
write(data, pixelShader->samplerVarCount);
|
|
for (uint32_t i = 0; i < pixelShader->samplerVarCount; i++) {
|
|
writeString(data, pixelShader->samplerVars[i].name);
|
|
write(data, pixelShader->samplerVars[i].type);
|
|
write(data, pixelShader->samplerVars[i].location);
|
|
}
|
|
|
|
// write gx2rBuffer
|
|
writeGX2RBuffer(data, &pixelShader->gx2rBuffer);
|
|
|
|
return data;
|
|
}
|
|
|
|
template<typename Type>
|
|
static Type readAt(const std::span<const uint8_t> &data, size_t &pos) {
|
|
Type value = *reinterpret_cast<const Type *>(data.data() + pos);
|
|
pos += sizeof(Type);
|
|
return value;
|
|
}
|
|
|
|
static const char *readString(const std::span<const uint8_t> &data, size_t &pos) {
|
|
std::string str(reinterpret_cast<const char *>(data.data() + pos));
|
|
pos += str.size() + 1;
|
|
pos = (pos + 3) & ~3; // align to 4 bytes
|
|
|
|
// Allocate memory for the string and copy the contents
|
|
char *result = static_cast<char *>(malloc(sizeof(char) * (str.size() + 1)));
|
|
strcpy(result, str.c_str());
|
|
return result;
|
|
}
|
|
|
|
static GX2RBuffer readGX2RBuffer(const std::span<const uint8_t> &data, size_t &pos) {
|
|
GX2RBuffer buffer;
|
|
buffer.flags = readAt<GX2RResourceFlags>(data, pos);
|
|
buffer.elemSize = readAt<uint32_t>(data, pos);
|
|
buffer.elemCount = readAt<uint32_t>(data, pos);
|
|
size_t bufferSize = buffer.elemSize * buffer.elemCount;
|
|
buffer.buffer = malloc(sizeof(uint8_t) * bufferSize);
|
|
memcpy(buffer.buffer, data.data() + pos, bufferSize);
|
|
pos += bufferSize;
|
|
return buffer;
|
|
}
|
|
|
|
std::unique_ptr<GX2VertexShaderWrapper> DeserializeVertexShader(const std::span<const uint8_t> &data) {
|
|
size_t pos = 0;
|
|
auto vertexShaderWrapper = std::make_unique<GX2VertexShaderWrapper>();
|
|
auto *vertexShader = vertexShaderWrapper->getVertexShader();
|
|
*vertexShader = {};
|
|
|
|
// read regs
|
|
vertexShader->regs.sq_pgm_resources_vs = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.vgt_primitiveid_en = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.spi_vs_out_config = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.num_spi_vs_out_id = readAt<uint32_t>(data, pos);
|
|
for (uint32_t &spi_vs : vertexShader->regs.spi_vs_out_id) {
|
|
spi_vs = readAt<uint32_t>(data, pos);
|
|
}
|
|
vertexShader->regs.pa_cl_vs_out_cntl = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.sq_vtx_semantic_clear = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.num_sq_vtx_semantic = readAt<uint32_t>(data, pos);
|
|
for (uint32_t &sq_vtx : vertexShader->regs.sq_vtx_semantic) {
|
|
sq_vtx = readAt<uint32_t>(data, pos);
|
|
}
|
|
vertexShader->regs.vgt_strmout_buffer_en = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.vgt_vertex_reuse_block_cntl = readAt<uint32_t>(data, pos);
|
|
vertexShader->regs.vgt_hos_reuse_depth = readAt<uint32_t>(data, pos);
|
|
|
|
// read program
|
|
vertexShader->size = readAt<uint32_t>(data, pos);
|
|
vertexShader->program = memalign(256, vertexShader->size);
|
|
for (uint32_t i = 0; i < vertexShader->size; i++) {
|
|
static_cast<uint8_t *>(vertexShader->program)[i] = readAt<uint8_t>(data, pos);
|
|
}
|
|
vertexShader->mode = readAt<GX2ShaderMode>(data, pos);
|
|
|
|
// read uniform blocks
|
|
vertexShader->uniformBlockCount = readAt<uint32_t>(data, pos);
|
|
if (vertexShader->uniformBlockCount > 0) {
|
|
vertexShader->uniformBlocks = static_cast<GX2UniformBlock *>(malloc(sizeof(GX2UniformBlock) * vertexShader->uniformBlockCount));
|
|
for (uint32_t i = 0; i < vertexShader->uniformBlockCount; i++) {
|
|
vertexShader->uniformBlocks[i].name = readString(data, pos);
|
|
vertexShader->uniformBlocks[i].offset = readAt<uint32_t>(data, pos);
|
|
vertexShader->uniformBlocks[i].size = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read uniform vars
|
|
vertexShader->uniformVarCount = readAt<uint32_t>(data, pos);
|
|
if (vertexShader->uniformVarCount > 0) {
|
|
vertexShader->uniformVars = static_cast<GX2UniformVar *>(malloc(sizeof(GX2UniformVar) * vertexShader->uniformVarCount));
|
|
|
|
for (uint32_t i = 0; i < vertexShader->uniformVarCount; i++) {
|
|
vertexShader->uniformVars[i].name = readString(data, pos);
|
|
vertexShader->uniformVars[i].type = readAt<GX2ShaderVarType>(data, pos);
|
|
vertexShader->uniformVars[i].count = readAt<uint32_t>(data, pos);
|
|
vertexShader->uniformVars[i].offset = readAt<uint32_t>(data, pos);
|
|
vertexShader->uniformVars[i].block = readAt<int32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read initial values
|
|
vertexShader->initialValueCount = readAt<uint32_t>(data, pos);
|
|
if (vertexShader->initialValueCount > 0) {
|
|
vertexShader->initialValues = static_cast<GX2UniformInitialValue *>(malloc(sizeof(GX2UniformInitialValue) * vertexShader->initialValueCount));
|
|
for (uint32_t i = 0; i < vertexShader->initialValueCount; i++) {
|
|
vertexShader->initialValues[i].value[0] = readAt<float>(data, pos);
|
|
vertexShader->initialValues[i].value[1] = readAt<float>(data, pos);
|
|
vertexShader->initialValues[i].value[2] = readAt<float>(data, pos);
|
|
vertexShader->initialValues[i].value[3] = readAt<float>(data, pos);
|
|
vertexShader->initialValues[i].offset = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read loop vars
|
|
vertexShader->loopVarCount = readAt<uint32_t>(data, pos);
|
|
if (vertexShader->loopVarCount > 0) {
|
|
vertexShader->loopVars = static_cast<GX2LoopVar *>(malloc(sizeof(GX2LoopVar) + vertexShader->loopVarCount));
|
|
for (uint32_t i = 0; i < vertexShader->loopVarCount; i++) {
|
|
vertexShader->loopVars[i].offset = readAt<uint32_t>(data, pos);
|
|
vertexShader->loopVars[i].value = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read sampler vars
|
|
vertexShader->samplerVarCount = readAt<uint32_t>(data, pos);
|
|
if (vertexShader->samplerVarCount > 0) {
|
|
vertexShader->samplerVars = static_cast<GX2SamplerVar *>(malloc(sizeof(GX2SamplerVar) * vertexShader->samplerVarCount));
|
|
for (uint32_t i = 0; i < vertexShader->samplerVarCount; i++) {
|
|
vertexShader->samplerVars[i].name = readString(data, pos);
|
|
vertexShader->samplerVars[i].type = readAt<GX2SamplerVarType>(data, pos);
|
|
vertexShader->samplerVars[i].location = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read attribute vars
|
|
vertexShader->attribVarCount = readAt<uint32_t>(data, pos);
|
|
if (vertexShader->attribVarCount > 0) {
|
|
vertexShader->attribVars = static_cast<GX2AttribVar *>(malloc(sizeof(GX2AttribVar) * vertexShader->attribVarCount));
|
|
for (uint32_t i = 0; i < vertexShader->attribVarCount; i++) {
|
|
vertexShader->attribVars[i].name = readString(data, pos);
|
|
vertexShader->attribVars[i].type = readAt<GX2ShaderVarType>(data, pos);
|
|
vertexShader->attribVars[i].count = readAt<uint32_t>(data, pos);
|
|
vertexShader->attribVars[i].location = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read ring item size
|
|
vertexShader->ringItemsize = readAt<uint32_t>(data, pos);
|
|
|
|
// read stream out
|
|
vertexShader->hasStreamOut = readAt<BOOL>(data, pos);
|
|
for (uint32_t &stride : vertexShader->streamOutStride) {
|
|
stride = readAt<uint32_t>(data, pos);
|
|
}
|
|
|
|
// read gx2rBuffer
|
|
vertexShader->gx2rBuffer = readGX2RBuffer(data, pos);
|
|
|
|
return vertexShaderWrapper;
|
|
}
|
|
|
|
std::unique_ptr<GX2PixelShaderWrapper> DeserializePixelShader(const std::span<const uint8_t> &data) {
|
|
size_t pos = 0;
|
|
auto pixelShaderWrapper = std::make_unique<GX2PixelShaderWrapper>();
|
|
auto *pixelShader = pixelShaderWrapper->getPixelShader();
|
|
*pixelShader = {};
|
|
// read regs
|
|
pixelShader->regs.sq_pgm_resources_ps = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.sq_pgm_exports_ps = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.spi_ps_in_control_0 = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.spi_ps_in_control_1 = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.num_spi_ps_input_cntl = readAt<uint32_t>(data, pos);
|
|
for (uint32_t &spi_ps : pixelShader->regs.spi_ps_input_cntls) {
|
|
spi_ps = readAt<uint32_t>(data, pos);
|
|
}
|
|
pixelShader->regs.cb_shader_mask = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.cb_shader_control = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.db_shader_control = readAt<uint32_t>(data, pos);
|
|
pixelShader->regs.spi_input_z = readAt<uint32_t>(data, pos);
|
|
|
|
// read program
|
|
pixelShader->size = readAt<uint32_t>(data, pos);
|
|
pixelShader->program = memalign(256, pixelShader->size);
|
|
for (uint32_t i = 0; i < pixelShader->size; i++) {
|
|
((uint8_t *) pixelShader->program)[i] = readAt<uint8_t>(data, pos);
|
|
}
|
|
pixelShader->mode = readAt<GX2ShaderMode>(data, pos);
|
|
|
|
// read uniform blocks
|
|
pixelShader->uniformBlockCount = readAt<uint32_t>(data, pos);
|
|
if (pixelShader->uniformBlockCount > 0) {
|
|
pixelShader->uniformBlocks = static_cast<GX2UniformBlock *>(malloc(sizeof(GX2UniformBlock) * pixelShader->uniformBlockCount));
|
|
for (uint32_t i = 0; i < pixelShader->uniformBlockCount; i++) {
|
|
pixelShader->uniformBlocks[i].name = readString(data, pos);
|
|
pixelShader->uniformBlocks[i].offset = readAt<uint32_t>(data, pos);
|
|
pixelShader->uniformBlocks[i].size = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read uniform vars
|
|
pixelShader->uniformVarCount = readAt<uint32_t>(data, pos);
|
|
if (pixelShader->uniformVarCount > 0) {
|
|
pixelShader->uniformVars = static_cast<GX2UniformVar *>(malloc(sizeof(GX2UniformVar) + pixelShader->uniformVarCount));
|
|
for (uint32_t i = 0; i < pixelShader->uniformVarCount; i++) {
|
|
pixelShader->uniformVars[i].name = readString(data, pos);
|
|
pixelShader->uniformVars[i].type = readAt<GX2ShaderVarType>(data, pos);
|
|
pixelShader->uniformVars[i].count = readAt<uint32_t>(data, pos);
|
|
pixelShader->uniformVars[i].offset = readAt<uint32_t>(data, pos);
|
|
pixelShader->uniformVars[i].block = readAt<int32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
// read initial values
|
|
pixelShader->initialValueCount = readAt<uint32_t>(data, pos);
|
|
if (pixelShader->initialValueCount > 0) {
|
|
pixelShader->initialValues = static_cast<GX2UniformInitialValue *>(malloc(sizeof(GX2UniformInitialValue) * pixelShader->initialValueCount));
|
|
for (uint32_t i = 0; i < pixelShader->initialValueCount; i++) {
|
|
pixelShader->initialValues[i].value[0] = readAt<float>(data, pos);
|
|
pixelShader->initialValues[i].value[1] = readAt<float>(data, pos);
|
|
pixelShader->initialValues[i].value[2] = readAt<float>(data, pos);
|
|
pixelShader->initialValues[i].value[3] = readAt<float>(data, pos);
|
|
pixelShader->initialValues[i].offset = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
pixelShader->loopVarCount = readAt<uint32_t>(data, pos);
|
|
if (pixelShader->loopVarCount > 0) {
|
|
pixelShader->loopVars = static_cast<GX2LoopVar *>(malloc(sizeof(GX2LoopVar) * pixelShader->loopVarCount));
|
|
for (uint32_t i = 0; i < pixelShader->loopVarCount; i++) {
|
|
pixelShader->loopVars[i].offset = readAt<uint32_t>(data, pos);
|
|
pixelShader->loopVars[i].value = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
pixelShader->samplerVarCount = readAt<uint32_t>(data, pos);
|
|
if (pixelShader->samplerVarCount > 0) {
|
|
pixelShader->samplerVars = static_cast<GX2SamplerVar *>(malloc(sizeof(GX2SamplerVar) * pixelShader->samplerVarCount));
|
|
for (uint32_t i = 0; i < pixelShader->samplerVarCount; i++) {
|
|
pixelShader->samplerVars[i].name = readString(data, pos);
|
|
pixelShader->samplerVars[i].type = readAt<GX2SamplerVarType>(data, pos);
|
|
pixelShader->samplerVars[i].location = readAt<uint32_t>(data, pos);
|
|
}
|
|
}
|
|
|
|
pixelShader->gx2rBuffer = readGX2RBuffer(data, pos);
|
|
|
|
return pixelShaderWrapper;
|
|
} |