CSC8503_Advanced_Game_Technologies / Plugins / PlayStation4 / PS4Shader.cpp
PS4Shader.cpp
Raw
#ifdef _ORBIS
#include "PS4Shader.h"

#include <iostream>
#include <fstream>
#include <gnmx\shader_parser.h>
#include <..\samples\sample_code\graphics\api_gnm\toolkit\shader_loader.h>

using std::ifstream;

using namespace NCL;
using namespace NCL::PS4;

PS4Shader::PS4Shader() 
{
	fetchShader		= NULL;
	vertexShader	= NULL;
	pixelShader		= NULL;
}

PS4Shader* PS4Shader::GenerateShader(const string& vertex,const string& pixel) {
	PS4Shader* shader = new PS4Shader();

	shader->GenerateVertexShader(vertex, true);
	shader->GeneratePixelShader(pixel);

	return shader;
}

PS4Shader::~PS4Shader()
{
}

void PS4Shader::GenerateVertexShader(const string&name, bool makeFetch) {
	char*	binData = NULL;	//resulting compiled shader bytes
	int		binSize = 0;
	Gnmx::ShaderInfo shaderInfo;

	if (ShaderIsBinary(name)) {
		if (LoadShaderBinary(name, binData, binSize)) {		
			vertexBinary.loadFromMemory(binData, binSize);

			//sce::Shader::Binary::Buffer* constantBuffer = vertexBinary.getBufferResourceByName("LOLBUFFER");

			Gnmx::parseShader(&shaderInfo, binData);

			void* shaderBinary = garlicAllocator->allocate(shaderInfo.m_gpuShaderCodeSize, Gnm::kAlignmentOfShaderInBytes);
			void* shaderHeader = onionAllocator->allocate(shaderInfo.m_vsShader->computeSize(), Gnm::kAlignmentOfBufferInBytes);

			memcpy(shaderBinary, shaderInfo.m_gpuShaderCode, shaderInfo.m_gpuShaderCodeSize);
			memcpy(shaderHeader, shaderInfo.m_vsShader, shaderInfo.m_vsShader->computeSize());

			vertexShader = (Gnmx::VsShader*)shaderHeader;
			vertexShader->patchShaderGpuAddress(shaderBinary);
		}
		else {
			std::cout << "Failed to generate vertex shader: " << name << " from binary. " << std::endl;
			return;
		}
	}
	else {
		string shaderString;
		if (LoadShaderText(name, shaderString)) {
			//shaderString now contains the pssl shader data
			//MAGIC GOES HERE
		}
		else {
			std::cout << "Failed to generate vertex shader: " << name << " from raw text. " << std::endl;
			return;
		}
	}

	Gnm::registerResource(nullptr, ownerHandle, vertexShader->getBaseAddress(),
							shaderInfo.m_gpuShaderCodeSize, name.c_str(), Gnm::kResourceTypeShaderBaseAddress, 0);

	Gnmx::generateInputOffsetsCache(&vertexCache, Gnm::kShaderStageVs, vertexShader);

	if (makeFetch) {
		GenerateFetchShader(binData);
	}
	//delete binData;//done with bindata now!
}

void PS4Shader::GenerateFetchShader(char* binData) {
	fetchShader = garlicAllocator->allocate(Gnmx::Toolkit::calculateMemoryRequiredForVsFetchShader(binData));

	uint32_t shaderModifier;
	Gnmx::generateVsFetchShader(fetchShader, &shaderModifier, vertexShader);

	vertexShader->applyFetchShaderModifier(shaderModifier);
}

void PS4Shader::GeneratePixelShader(const string&name) {
	char*	binData = NULL;	//resulting compiled shader bytes
	int		binSize = 0;
	Gnmx::ShaderInfo shaderInfo;

	if (ShaderIsBinary(name)) {
		if (LoadShaderBinary(name, binData, binSize)) {
			pixelBinary.loadFromMemory(binData, binSize);
			Gnmx::parseShader(&shaderInfo, binData);

			void* shaderBinary = garlicAllocator->allocate(shaderInfo.m_gpuShaderCodeSize, Gnm::kAlignmentOfShaderInBytes);
			void* shaderHeader = onionAllocator->allocate(shaderInfo.m_psShader->computeSize(), Gnm::kAlignmentOfBufferInBytes);

			memcpy(shaderBinary, shaderInfo.m_gpuShaderCode, shaderInfo.m_gpuShaderCodeSize);
			memcpy(shaderHeader, shaderInfo.m_psShader, shaderInfo.m_psShader->computeSize());

			pixelShader = (Gnmx::PsShader*)shaderHeader;
			pixelShader->patchShaderGpuAddress(shaderBinary);
		}
	}
	else {
		bool a = true;
	}

	Gnm::registerResource(nullptr, ownerHandle, vertexShader->getBaseAddress(),
		shaderInfo.m_gpuShaderCodeSize, name.c_str(), Gnm::kResourceTypeShaderBaseAddress, 0);

	Gnmx::generateInputOffsetsCache(&pixelCache, Gnm::kShaderStagePs, pixelShader);

	//delete binData;
}



bool PS4Shader::LoadShaderText(const string &name, string&into) {

	return false;
}

bool PS4Shader::LoadShaderBinary(const string &name, char*& into, int& dataSize) {
	std::ifstream binFile(name, std::ios::binary);

	if (!binFile) {
		return false;
	}
	binFile.seekg(0, ios::end);
	int size = binFile.tellg();

	into = new char[size];

	binFile.seekg(0, ios::beg);
	binFile.read(into, size);

	dataSize = size;

	return true;
}

bool PS4Shader::ShaderIsBinary(const string& name) {
	if (name.length() >= 3 && 
		name[name.length() - 3] == '.' &&
		name[name.length() - 2] == 's' &&
		name[name.length() - 1] == 'b'	) {
		return true;
	}
	return false;
}

void	PS4Shader::SubmitShaderSwitch(Gnmx::GnmxGfxContext& cmdList) {
	cmdList.setActiveShaderStages(Gnm::kActiveShaderStagesVsPs);

	cmdList.setVsShader(vertexShader, 0, fetchShader, &vertexCache);
	cmdList.setPsShader(pixelShader, &pixelCache);
}

int		PS4Shader::GetConstantBuffer(const string &name) {
	sce::Shader::Binary::Buffer* constantBuffer = vertexBinary.getBufferResourceByName(name.c_str());
	if (!constantBuffer) {
		return -1;
	}
	return constantBuffer->m_resourceIndex;
}

#endif