CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/D3D11/ShaderManagerD3D11.cpp
Views: 1401
// Copyright (c) 2015- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "ppsspp_config.h"1819#include <d3d11.h>20#include <D3Dcompiler.h>2122#include <map>2324#include "Common/Math/lin/matrix4x4.h"25#include "Common/Math/math_util.h"26#include "Common/Data/Convert/SmallDataConvert.h"27#include "Common/GPU/thin3d.h"28#include "Common/Data/Encoding/Utf8.h"29#include "Common/Log.h"30#include "Common/CommonTypes.h"31#include "Core/Config.h"32#include "GPU/Math3D.h"33#include "GPU/GPUState.h"34#include "GPU/ge_constants.h"35#include "GPU/Common/VertexShaderGenerator.h"36#include "GPU/D3D11/ShaderManagerD3D11.h"37#include "GPU/D3D11/D3D11Util.h"3839D3D11FragmentShader::D3D11FragmentShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, FShaderID id, const char *code, bool useHWTransform)40: device_(device), useHWTransform_(useHWTransform), id_(id) {41source_ = code;4243module_ = CreatePixelShaderD3D11(device, code, strlen(code), featureLevel);44if (!module_)45failed_ = true;46}4748D3D11FragmentShader::~D3D11FragmentShader() {49if (module_)50module_->Release();51}5253std::string D3D11FragmentShader::GetShaderString(DebugShaderStringType type) const {54switch (type) {55case SHADER_STRING_SOURCE_CODE:56return source_;57case SHADER_STRING_SHORT_DESC:58return FragmentShaderDesc(id_);59default:60return "N/A";61}62}6364D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, VShaderID id, const char *code, bool useHWTransform)65: device_(device), useHWTransform_(useHWTransform), id_(id) {66source_ = code;6768module_ = CreateVertexShaderD3D11(device, code, strlen(code), &bytecode_, featureLevel);69if (!module_)70failed_ = true;71}7273D3D11VertexShader::~D3D11VertexShader() {74if (module_)75module_->Release();76}7778std::string D3D11VertexShader::GetShaderString(DebugShaderStringType type) const {79switch (type) {80case SHADER_STRING_SOURCE_CODE:81return source_;82case SHADER_STRING_SHORT_DESC:83return VertexShaderDesc(id_);84default:85return "N/A";86}87}8889static constexpr size_t CODE_BUFFER_SIZE = 32768;9091ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel)92: ShaderManagerCommon(draw), device_(device), context_(context), featureLevel_(featureLevel) {93codeBuffer_ = new char[CODE_BUFFER_SIZE];94memset(&ub_base, 0, sizeof(ub_base));95memset(&ub_lights, 0, sizeof(ub_lights));96memset(&ub_bones, 0, sizeof(ub_bones));9798static_assert(sizeof(ub_base) <= 512, "ub_base grew too big");99static_assert(sizeof(ub_lights) <= 512, "ub_lights grew too big");100static_assert(sizeof(ub_bones) <= 384, "ub_bones grew too big");101102D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE };103ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_base));104desc.ByteWidth = sizeof(ub_lights);105ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_lights));106desc.ByteWidth = sizeof(ub_bones);107ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_bones));108}109110ShaderManagerD3D11::~ShaderManagerD3D11() {111push_base->Release();112push_lights->Release();113push_bones->Release();114ClearShaders();115delete[] codeBuffer_;116}117118void ShaderManagerD3D11::Clear() {119for (const auto &[_, fs] : fsCache_) {120delete fs;121}122for (const auto &[_, vs] : vsCache_) {123delete vs;124}125fsCache_.clear();126vsCache_.clear();127lastFSID_.set_invalid();128lastVSID_.set_invalid();129gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);130}131132void ShaderManagerD3D11::ClearShaders() {133Clear();134DirtyLastShader();135gstate_c.Dirty(DIRTY_ALL_UNIFORMS);136}137138void ShaderManagerD3D11::DirtyLastShader() {139lastFSID_.set_invalid();140lastVSID_.set_invalid();141lastVShader_ = nullptr;142lastFShader_ = nullptr;143gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);144}145146uint64_t ShaderManagerD3D11::UpdateUniforms(bool useBufferedRendering) {147uint64_t dirty = gstate_c.GetDirtyUniforms();148if (dirty != 0) {149D3D11_MAPPED_SUBRESOURCE map;150if (dirty & DIRTY_BASE_UNIFORMS) {151BaseUpdateUniforms(&ub_base, dirty, true, useBufferedRendering);152context_->Map(push_base, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);153memcpy(map.pData, &ub_base, sizeof(ub_base));154context_->Unmap(push_base, 0);155}156if (dirty & DIRTY_LIGHT_UNIFORMS) {157LightUpdateUniforms(&ub_lights, dirty);158context_->Map(push_lights, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);159memcpy(map.pData, &ub_lights, sizeof(ub_lights));160context_->Unmap(push_lights, 0);161}162if (dirty & DIRTY_BONE_UNIFORMS) {163BoneUpdateUniforms(&ub_bones, dirty);164context_->Map(push_bones, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);165memcpy(map.pData, &ub_bones, sizeof(ub_bones));166context_->Unmap(push_bones, 0);167}168}169gstate_c.CleanUniforms();170return dirty;171}172173void ShaderManagerD3D11::BindUniforms() {174ID3D11Buffer *vs_cbs[3] = { push_base, push_lights, push_bones };175ID3D11Buffer *ps_cbs[1] = { push_base };176context_->VSSetConstantBuffers(0, 3, vs_cbs);177context_->PSSetConstantBuffers(0, 1, ps_cbs);178}179180void ShaderManagerD3D11::GetShaders(int prim, VertexDecoder *decoder, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {181VShaderID VSID;182FShaderID FSID;183184if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {185gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);186ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);187} else {188VSID = lastVSID_;189}190191if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {192gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);193ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs());194} else {195FSID = lastFSID_;196}197198// Just update uniforms if this is the same shader as last time.199if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {200*vshader = lastVShader_;201*fshader = lastFShader_;202// Already all set, no need to look up in shader maps.203return;204}205206VSCache::iterator vsIter = vsCache_.find(VSID);207D3D11VertexShader *vs;208if (vsIter == vsCache_.end()) {209// Vertex shader not in cache. Let's compile it.210std::string genErrorString;211uint32_t attrMask;212uint64_t uniformMask;213VertexShaderFlags flags;214GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);215_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));216vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, useHWTransform);217vsCache_[VSID] = vs;218} else {219vs = vsIter->second;220}221lastVSID_ = VSID;222223FSCache::iterator fsIter = fsCache_.find(FSID);224D3D11FragmentShader *fs;225if (fsIter == fsCache_.end()) {226// Fragment shader not in cache. Let's compile it.227std::string genErrorString;228uint64_t uniformMask;229FragmentShaderFlags flags;230GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &genErrorString);231_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));232fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform);233fsCache_[FSID] = fs;234} else {235fs = fsIter->second;236}237238lastFSID_ = FSID;239240lastVShader_ = vs;241lastFShader_ = fs;242243*vshader = vs;244*fshader = fs;245}246247std::vector<std::string> ShaderManagerD3D11::DebugGetShaderIDs(DebugShaderType type) {248std::string id;249std::vector<std::string> ids;250switch (type) {251case SHADER_TYPE_VERTEX:252{253for (auto iter : vsCache_) {254iter.first.ToString(&id);255ids.push_back(id);256}257break;258}259case SHADER_TYPE_FRAGMENT:260{261for (auto iter : fsCache_) {262iter.first.ToString(&id);263ids.push_back(id);264}265break;266}267default:268break;269}270return ids;271}272273std::string ShaderManagerD3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {274ShaderID shaderId;275shaderId.FromString(id);276switch (type) {277case SHADER_TYPE_VERTEX:278{279auto iter = vsCache_.find(VShaderID(shaderId));280if (iter == vsCache_.end()) {281return "";282}283return iter->second->GetShaderString(stringType);284}285286case SHADER_TYPE_FRAGMENT:287{288auto iter = fsCache_.find(FShaderID(shaderId));289if (iter == fsCache_.end()) {290return "";291}292return iter->second->GetShaderString(stringType);293}294default:295return "N/A";296}297}298299300