bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PixelShaderUid uid; GetPixelShaderUid(uid, dstAlphaMode, API_D3D, components); if (g_ActiveConfig.bEnableShaderDebugging) { PixelShaderCode code; GeneratePixelShaderCode(code, dstAlphaMode, API_D3D, components); pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p"); } // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return (last_entry->shader != nullptr); } } last_uid = uid; // Check if the shader is already in the cache PSCache::iterator iter; iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { const PSCacheEntry &entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return (entry.shader != nullptr); } // Need to compile a new shader PixelShaderCode code; GeneratePixelShaderCode(code, dstAlphaMode, API_D3D, components); D3DBlob* pbytecode; if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { PixelShaders[uid].code = code.GetBuffer(); } GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return success; }
void ShaderCache::HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_type) { s_last_geometry_shader_uid = gs_uid; if (gs_uid.GetUidData()->IsPassthrough()) { s_last_geometry_shader_bytecode = {}; return; } auto gs_iterator = s_gs_bytecode_cache.find(gs_uid); if (gs_iterator != s_gs_bytecode_cache.end()) { s_last_geometry_shader_bytecode = gs_iterator->second; } else { ShaderCode gs_code = GenerateGeometryShaderCode(APIType::D3D, gs_uid.GetUidData()); ID3DBlob* gs_bytecode = nullptr; if (!D3D::CompileGeometryShader(gs_code.GetBuffer(), &gs_bytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return; } s_last_geometry_shader_bytecode = InsertByteCode(gs_uid, &s_gs_bytecode_cache, gs_bytecode); s_gs_disk_cache.Append(gs_uid, reinterpret_cast<u8*>(gs_bytecode->GetBufferPointer()), static_cast<u32>(gs_bytecode->GetBufferSize())); } }
void ShaderCache::HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_alpha_mode) { s_last_pixel_shader_uid = ps_uid; auto ps_iterator = s_ps_bytecode_cache.find(ps_uid); if (ps_iterator != s_ps_bytecode_cache.end()) { s_last_pixel_shader_bytecode = ps_iterator->second; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); } else { ShaderCode ps_code = GeneratePixelShaderCode(APIType::D3D, ps_uid.GetUidData()); ID3DBlob* ps_bytecode = nullptr; if (!D3D::CompilePixelShader(ps_code.GetBuffer(), &ps_bytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return; } s_last_pixel_shader_bytecode = InsertByteCode(ps_uid, &s_ps_bytecode_cache, ps_bytecode); s_ps_disk_cache.Append(ps_uid, reinterpret_cast<u8*>(ps_bytecode->GetBufferPointer()), static_cast<u32>(ps_bytecode->GetBufferSize())); SETSTAT(stats.numPixelShadersAlive, static_cast<int>(s_ps_bytecode_cache.size())); INCSTAT(stats.numPixelShadersCreated); } }
void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid) { s_last_vertex_shader_uid = vs_uid; auto vs_iterator = s_vs_bytecode_cache.find(vs_uid); if (vs_iterator != s_vs_bytecode_cache.end()) { s_last_vertex_shader_bytecode = vs_iterator->second; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); } else { ShaderCode vs_code = GenerateVertexShaderCode(APIType::D3D, vs_uid.GetUidData()); ID3DBlob* vs_bytecode = nullptr; if (!D3D::CompileVertexShader(vs_code.GetBuffer(), &vs_bytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return; } s_last_vertex_shader_bytecode = InsertByteCode(vs_uid, &s_vs_bytecode_cache, vs_bytecode); s_vs_disk_cache.Append(vs_uid, reinterpret_cast<u8*>(vs_bytecode->GetBufferPointer()), static_cast<u32>(vs_bytecode->GetBufferSize())); SETSTAT(stats.numVertexShadersAlive, static_cast<int>(s_vs_bytecode_cache.size())); INCSTAT(stats.numVertexShadersCreated); } }
HRESULT StateCache::GetPipelineStateObjectFromCache(SmallPsoDesc* pso_desc, ID3D12PipelineState** pso, D3D12_PRIMITIVE_TOPOLOGY_TYPE topology, const GeometryShaderUid* gs_uid, const PixelShaderUid* ps_uid, const VertexShaderUid* vs_uid) { auto it = m_small_pso_map.find(*pso_desc); if (it == m_small_pso_map.end()) { // Not found, create new PSO. // RootSignature, SampleMask, SampleDesc, NumRenderTargets, RTVFormats, DSVFormat // never change so they are set in constructor and forgotten. m_current_pso_desc.GS = pso_desc->gs_bytecode; m_current_pso_desc.PS = pso_desc->ps_bytecode; m_current_pso_desc.VS = pso_desc->vs_bytecode; m_current_pso_desc.BlendState = GetDesc12(pso_desc->blend_state); m_current_pso_desc.DepthStencilState = GetDesc12(pso_desc->depth_stencil_state); m_current_pso_desc.RasterizerState = GetDesc12(pso_desc->rasterizer_state); m_current_pso_desc.PrimitiveTopologyType = topology; m_current_pso_desc.InputLayout = pso_desc->input_layout->GetActiveInputLayout12(); ID3D12PipelineState* new_pso = nullptr; HRESULT hr = D3D::device12->CreateGraphicsPipelineState(&m_current_pso_desc, IID_PPV_ARGS(&new_pso)); if (FAILED(hr)) { return hr; } m_small_pso_map[*pso_desc] = new_pso; *pso = new_pso; // This contains all of the information needed to reconstruct a PSO at startup. SmallPsoDiskDesc disk_desc = {}; disk_desc.blend_state_hex = pso_desc->blend_state.hex; disk_desc.depth_stencil_state_hex = pso_desc->depth_stencil_state.hex; disk_desc.rasterizer_state_hex = pso_desc->rasterizer_state.hex; disk_desc.ps_uid = *ps_uid; disk_desc.vs_uid = *vs_uid; disk_desc.gs_uid = *gs_uid; disk_desc.vertex_declaration = pso_desc->input_layout->GetVertexDeclaration(); disk_desc.topology = topology; // This shouldn't fail.. but if it does, don't cache to disk. ID3DBlob* psoBlob = nullptr; hr = new_pso->GetCachedBlob(&psoBlob); if (SUCCEEDED(hr)) { s_pso_disk_cache.Append(disk_desc, reinterpret_cast<const u8*>(psoBlob->GetBufferPointer()), static_cast<u32>(psoBlob->GetBufferSize())); psoBlob->Release(); } } else { *pso = it->second; } return S_OK; }
bool VertexShaderCache::SetShader(u32 components) { VertexShaderUid uid; GetVertexShaderUid(uid, components, API_D3D); if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; GenerateVertexShaderCode(code, components, API_D3D); vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v"); } if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (last_entry->shader != nullptr); } } last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry &entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != nullptr); } ShaderCode code; GenerateVertexShaderCode(code, components, API_D3D); D3DBlob* pbytecode = nullptr; D3D::CompileVertexShader(code.GetBuffer(), &pbytecode); if (pbytecode == nullptr) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code.GetBuffer(); } GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
void ShaderCache::HandlePSUIDChange( const PixelShaderUid &ps_uid, bool on_gpu_thread) { s_shaders_lock.lock(); ByteCodeCacheEntry* entry = &ps_bytecode_cache->GetOrAdd(ps_uid); s_shaders_lock.unlock(); if (on_gpu_thread) { s_last_pixel_shader_bytecode = entry; } if (entry->m_initialized.test_and_set()) { return; } // Need to compile a new shader ShaderCompilerWorkUnit *wunit = s_compiler->NewUnit(PIXELSHADERGEN_BUFFERSIZE); wunit->GenerateCodeHandler = [ps_uid](ShaderCompilerWorkUnit* wunit) { ShaderCode code; code.SetBuffer(wunit->code.data()); GeneratePixelShaderCodeD3D11(code, ps_uid.GetUidData()); wunit->codesize = (u32)code.BufferSize(); }; wunit->entrypoint = "main"; wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3; wunit->target = D3D::PixelShaderVersionString(); wunit->ResultHandler = [ps_uid, entry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { D3DBlob* shaderBuffer = new D3DBlob(wunit->shaderbytecode); s_ps_disk_cache.Append(ps_uid, shaderBuffer->Data(), shaderBuffer->Size()); PushByteCode(entry, shaderBuffer); wunit->shaderbytecode->Release(); wunit->shaderbytecode = nullptr; } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char *)wunit->code.data()); file << ((const char *)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile pixel shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::PixelShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; s_compiler->CompileShaderAsync(wunit); }
void ProgramShaderCache::Shutdown() { // store all shaders in cache on disk if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) { for (auto& entry : pshaders) { // Clear any prior error code glGetError(); if (entry.second.in_cache) { continue; } GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || !binary_size) { continue; } std::vector<u8> data(binary_size + sizeof(GLenum)); u8* binary = &data[sizeof(GLenum)]; GLenum* prog_format = (GLenum*)&data[0]; glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); if (glGetError() != GL_NO_ERROR) { continue; } g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); } g_program_disk_cache.Sync(); g_program_disk_cache.Close(); } glUseProgram(0); for (auto& entry : pshaders) { entry.second.Destroy(); } pshaders.clear(); pixel_uid_checker.Invalidate(); vertex_uid_checker.Invalidate(); delete s_buffer; s_buffer = nullptr; }
bool VertexShaderCache::SetShader(u32 components) { VertexShaderUid uid; GetVertexShaderUid(uid, components, API_D3D9); if (g_ActiveConfig.bEnableShaderDebugging) { VertexShaderCode code; GenerateVertexShaderCode(code, components, API_D3D9); vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v"); } if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (last_entry->shader != NULL); } } last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry &entry = iter->second; last_entry = &entry; if (entry.shader) D3D::SetVertexShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != NULL); } VertexShaderCode code; GenerateVertexShaderCode(code, components, API_D3D9); u8 *bytecode; int bytecodelen; if (!D3D::CompileVertexShader(code.GetBuffer(), (int)strlen(code.GetBuffer()), &bytecode, &bytecodelen)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, bytecode, bytecodelen); bool success = InsertByteCode(uid, bytecode, bytecodelen, true); if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code.GetBuffer(); } delete [] bytecode; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
bool GeometryShaderCache::SetShader(u32 primitive_type) { GeometryShaderUid uid = GetGeometryShaderUid(primitive_type); // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return true; } } last_uid = uid; // Check if the shader is a pass-through shader if (uid.GetUidData()->IsPassthrough()) { // Return the default pass-through shader last_entry = &pass_entry; return true; } // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); if (iter != GeometryShaders.end()) { const GSCacheEntry& entry = iter->second; last_entry = &entry; return (entry.shader != nullptr); } // Need to compile a new shader ShaderCode code = GenerateGeometryShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); return success; }
bool VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); ValidateVertexShaderIDs(API_D3D11, last_entry->safe_uid, last_entry->code, components); return (last_entry->shader != NULL); } } last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry &entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); ValidateVertexShaderIDs(API_D3D11, entry.safe_uid, entry.code, components); return (entry.shader != NULL); } const char *code = GenerateVertexShaderCode(components, API_D3D11); D3DBlob* pbytecode = NULL; D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode); if (pbytecode == NULL) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code; GetSafeVertexShaderId(&vshaders[uid].safe_uid, components); } GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
bool PixelShaderCache::SetShader() { PixelShaderUid uid = GetPixelShaderUid(); // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return (last_entry->shader != nullptr); } } last_uid = uid; // Check if the shader is already in the cache PSCache::iterator iter; iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { const PSCacheEntry& entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return (entry.shader != nullptr); } // Need to compile a new shader ShaderCode code = GeneratePixelShaderCode(APIType::D3D, uid.GetUidData()); D3DBlob* pbytecode; if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return success; }
bool VertexShaderCache::SetUberShader(D3DVertexFormat* vertex_format) { D3DVertexFormat* uber_vertex_format = static_cast<D3DVertexFormat*>( VertexLoaderManager::GetUberVertexFormat(vertex_format->GetVertexDeclaration())); UberShader::VertexShaderUid uid = UberShader::GetVertexShaderUid(); if (last_uber_entry && last_uber_uid == uid) { if (!last_uber_entry->shader) return false; uber_vertex_format->SetInputLayout(last_uber_entry->bytecode); D3D::stateman->SetVertexShader(last_uber_entry->shader); return true; } auto iter = ubervshaders.find(uid); if (iter != ubervshaders.end()) { const VSCacheEntry& entry = iter->second; last_uber_uid = uid; last_uber_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); if (!last_uber_entry->shader) return false; uber_vertex_format->SetInputLayout(last_uber_entry->bytecode); D3D::stateman->SetVertexShader(last_uber_entry->shader); return true; } // Need to compile a new shader D3DBlob* bytecode = nullptr; ShaderCode code = UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3D::CompileVertexShader(code.GetBuffer(), &bytecode); if (!InsertByteCode(uid, bytecode)) { SAFE_RELEASE(bytecode); return false; } g_uber_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size()); bytecode->Release(); return SetUberShader(vertex_format); }
void ProgramShaderCache::Shutdown() { // store all shaders in cache on disk if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) { for (auto& entry : pshaders) { if (entry.second.in_cache) { continue; } GLint binary_size; glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); if (!binary_size) { continue; } u8 *data = new u8[binary_size+sizeof(GLenum)]; u8 *binary = data + sizeof(GLenum); GLenum *prog_format = (GLenum*)data; glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); g_program_disk_cache.Append(entry.first, data, binary_size+sizeof(GLenum)); delete [] data; } g_program_disk_cache.Sync(); g_program_disk_cache.Close(); } glUseProgram(0); for (auto& entry : pshaders) { entry.second.Destroy(); } pshaders.clear(); pixel_uid_checker.Invalidate(); vertex_uid_checker.Invalidate(); delete s_buffer; s_buffer = nullptr; }
void ProgramShaderCache::Shutdown(void) { // store all shaders in cache on disk if (g_ogl_config.bSupportsGLSLCache) { PCache::iterator iter = pshaders.begin(); for (; iter != pshaders.end(); ++iter) { if(iter->second.in_cache) continue; GLint binary_size; glGetProgramiv(iter->second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); if(!binary_size) continue; u8 *data = new u8[binary_size+sizeof(GLenum)]; u8 *binary = data + sizeof(GLenum); GLenum *prog_format = (GLenum*)data; glGetProgramBinary(iter->second.shader.glprogid, binary_size, NULL, prog_format, binary); g_program_disk_cache.Append(iter->first, data, binary_size+sizeof(GLenum)); delete [] data; } g_program_disk_cache.Sync(); g_program_disk_cache.Close(); } glUseProgram(0); PCache::iterator iter = pshaders.begin(); for (; iter != pshaders.end(); ++iter) iter->second.Destroy(); pshaders.clear(); pixel_uid_checker.Invalidate(); vertex_uid_checker.Invalidate(); if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) { delete s_buffer; s_buffer = 0; delete [] s_ubo_buffer; s_ubo_buffer = 0; } }
bool VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (vshaders[uid].shader != NULL); } memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { iter->second.frameCount = frameCount; const VSCacheEntry &entry = iter->second; last_entry = &entry; if (entry.shader) D3D::SetVertexShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != NULL); } const char *code = GenerateVertexShaderCode(components, API_D3D9); u8 *bytecode; int bytecodelen; if (!D3D::CompileVertexShader(code, (int)strlen(code), &bytecode, &bytecodelen)) { if (g_ActiveConfig.bShowShaderErrors) { PanicAlert("Failed to compile Vertex Shader:\n\n%s", code); } GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, bytecode, bytecodelen); g_vs_disk_cache.Sync(); bool result = InsertByteCode(uid, bytecode, bytecodelen, true); delete [] bytecode; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return result; }
bool VertexShaderCache::SetShader() { VertexShaderUid uid = GetVertexShaderUid(); if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (last_entry->shader != nullptr); } } last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry& entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != nullptr); } ShaderCode code = GenerateVertexShaderCode(API_D3D, uid.GetUidData()); D3DBlob* pbytecode = nullptr; D3D::CompileVertexShader(code.GetBuffer(), &pbytecode); if (pbytecode == nullptr) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
HRESULT StateCache::GetPipelineStateObjectFromCache(const SmallPsoDesc& pso_desc, ID3D12PipelineState** pso, D3D12_PRIMITIVE_TOPOLOGY_TYPE topology) { auto it = m_small_pso_map.find(pso_desc); if (it == m_small_pso_map.end()) { // Not found, create new PSO. // RootSignature, SampleMask, NumRenderTargets, RTVFormats, DSVFormat // never change so they are set in constructor and forgotten. m_current_pso_desc.GS = pso_desc.gs_bytecode; m_current_pso_desc.PS = pso_desc.ps_bytecode; m_current_pso_desc.VS = pso_desc.vs_bytecode; m_current_pso_desc.HS = pso_desc.hs_bytecode; m_current_pso_desc.DS = pso_desc.ds_bytecode; m_current_pso_desc.RTVFormats[0] = pso_desc.rtformat; m_current_pso_desc.pRootSignature = D3D::GetRootSignature(); m_current_pso_desc.BlendState = GetDesc(pso_desc.blend_state); m_current_pso_desc.DepthStencilState = GetDesc(pso_desc.depth_stencil_state); m_current_pso_desc.RasterizerState = GetDesc(pso_desc.rasterizer_state); m_current_pso_desc.PrimitiveTopologyType = topology; m_current_pso_desc.InputLayout = pso_desc.input_Layout->GetActiveInputLayout(); m_current_pso_desc.SampleDesc.Count = pso_desc.sample_count; ComPtr<ID3D12PipelineState> new_pso; HRESULT hr = D3D::device->CreateGraphicsPipelineState(&m_current_pso_desc, IID_PPV_ARGS(new_pso.ReleaseAndGetAddressOf())); if (FAILED(hr)) { CheckHR(hr); return hr; } m_small_pso_map[pso_desc] = new_pso; *pso = new_pso.Get(); if (m_enable_disk_cache) { // This contains all of the information needed to reconstruct a PSO at startup. SmallPsoDiskDesc disk_desc = {}; disk_desc.using_uber_pixel_shader = pso_desc.using_uber_pixel_shader; disk_desc.using_uber_vertex_shader = pso_desc.using_uber_vertex_shader; disk_desc.root_signature_index = static_cast<u32>(D3D::GetRootSignatureIndex()); disk_desc.blend_state_hex = pso_desc.blend_state.hex; disk_desc.depth_stencil_state_hex = pso_desc.depth_stencil_state.hex; disk_desc.rasterizer_state_hex = pso_desc.rasterizer_state.hex; disk_desc.gs_uid = ShaderCache::GetActiveGeometryShaderUid(); if (pso_desc.using_uber_pixel_shader) { disk_desc.pus_uid = ShaderCache::GetActivePixelUberShaderUid(); } else { disk_desc.ps_uid = ShaderCache::GetActivePixelShaderUid(); } if (pso_desc.using_uber_vertex_shader) { disk_desc.vus_uid = ShaderCache::GetActiveVertexUberShaderUid(); } else { disk_desc.vs_uid = ShaderCache::GetActiveVertexShaderUid(); } disk_desc.hds_uid = ShaderCache::GetActiveTessellationShaderUid(); disk_desc.vertex_declaration = pso_desc.input_Layout->GetVertexDeclaration(); disk_desc.topology = topology; disk_desc.sample_desc.Count = g_ActiveConfig.iMultisamples; disk_desc.rtformat = pso_desc.rtformat; // This shouldn't fail.. but if it does, don't cache to disk. ComPtr<ID3DBlob> psoBlob; hr = new_pso->GetCachedBlob(psoBlob.ReleaseAndGetAddressOf()); if (SUCCEEDED(hr)) { s_pso_disk_cache.Append(disk_desc, reinterpret_cast<const u8*>(psoBlob->GetBufferPointer()), static_cast<u32>(psoBlob->GetBufferSize())); } } } else { *pso = it->second.Get(); } return S_OK; }
void VertexShaderCache::PrepareShader(u32 components, const XFMemory &xfr, const BPMemory &bpm, bool ongputhread) { VertexShaderUid uid; GetVertexShaderUID(uid, components, xfr, bpm); if (ongputhread) { Compiler->ProcCompilationResults(); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; GenerateVertexShaderCodeD3D9(code, uid.GetUidData()); } #endif if (last_entry) { if (uid == last_uid) { return; } } last_uid = uid; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); } else { if (external_last_uid == uid) { return; } external_last_uid = uid; } vshaderslock.lock(); VSCacheEntry *entry = &vshaders[uid]; vshaderslock.unlock(); if (ongputhread) { last_entry = entry; } // Compile only when we have a new instance if (entry->initialized.test_and_set()) { return; } ShaderCompilerWorkUnit *wunit = Compiler->NewUnit(VERTEXSHADERGEN_BUFFERSIZE); wunit->GenerateCodeHandler = [uid](ShaderCompilerWorkUnit* wunit) { ShaderCode code; code.SetBuffer(wunit->code.data()); GenerateVertexShaderCodeD3D9(code, uid.GetUidData()); wunit->codesize = (u32)code.BufferSize(); }; wunit->entrypoint = "main"; wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3; wunit->target = D3D::VertexShaderVersionString(); wunit->ResultHandler = [uid, entry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { ID3DBlob* shaderBuffer = wunit->shaderbytecode; const u8* bytecode = (const u8*)shaderBuffer->GetBufferPointer(); u32 bytecodelen = (u32)shaderBuffer->GetBufferSize(); g_vs_disk_cache.Append(uid, bytecode, bytecodelen); PushByteCode(uid, bytecode, bytecodelen, entry); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.bEnableShaderDebugging) { entry->code = wunit->code.data(); } #endif } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char*)wunit->code.data()); file << ((const char*)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile vertex shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::VertexShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; Compiler->CompileShaderAsync(wunit); }
bool GeometryShaderCache::SetShader(u32 primitive_type) { switch (primitive_type) { case PRIMITIVE_TRIANGLES: currentPrimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; case PRIMITIVE_LINES: currentPrimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; break; case PRIMITIVE_POINTS: currentPrimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; break; default: CHECK(0, "Invalid primitive type."); break; } GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D); // Check if the shader is already set if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return true; } last_uid = uid; D3D::commandListMgr->dirtyPso = true; if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); } // Check if the shader is a pass-through shader if (uid.GetUidData()->IsPassthrough()) { // Return the default pass-through shader last_entry = &pass_entry; return true; } // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); if (iter != GeometryShaders.end()) { const GSCacheEntry &entry = iter->second; last_entry = &entry; return (entry.shader12.pShaderBytecode != nullptr); } // Need to compile a new shader ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { GeometryShaders[uid].code = code.GetBuffer(); } return success; }
bool VertexShaderCache::SetShader(D3DVertexFormat* vertex_format) { if (g_ActiveConfig.bDisableSpecializedShaders) return SetUberShader(vertex_format); VertexShaderUid uid = GetVertexShaderUid(); if (last_entry && uid == last_uid) { if (last_entry->pending) return SetUberShader(vertex_format); if (!last_entry->shader) return false; vertex_format->SetInputLayout(last_entry->bytecode); D3D::stateman->SetVertexShader(last_entry->shader); return true; } auto iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry& entry = iter->second; if (entry.pending) return SetUberShader(vertex_format); last_uid = uid; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); if (!last_entry->shader) return false; vertex_format->SetInputLayout(last_entry->bytecode); D3D::stateman->SetVertexShader(last_entry->shader); return true; } // Background compiling? if (g_ActiveConfig.CanBackgroundCompileShaders()) { // Create a pending entry VSCacheEntry entry; entry.pending = true; vshaders[uid] = entry; // Queue normal shader compiling and use ubershader g_async_compiler->QueueWorkItem( g_async_compiler->CreateWorkItem<VertexShaderCompilerWorkItem>(uid)); return SetUberShader(vertex_format); } // Need to compile a new shader D3DBlob* bytecode = nullptr; ShaderCode code = GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3D::CompileVertexShader(code.GetBuffer(), &bytecode); if (!InsertByteCode(uid, bytecode)) { SAFE_RELEASE(bytecode); return false; } g_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size()); bytecode->Release(); return SetShader(vertex_format); }
void VertexShaderCache::UberVertexShaderCompilerWorkItem::Retrieve() { if (InsertShader(m_uid, m_vs, m_bytecode)) g_uber_vs_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size()); }
bool GeometryShaderCache::SetShader(u32 primitive_type) { GeometryShaderUid uid; GetGeometryShaderUid(uid, primitive_type, API_D3D); if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; GenerateGeometryShaderCode(code, primitive_type, API_D3D); geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); } // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return true; } } last_uid = uid; // Check if the shader is a pass-through shader if (uid.GetUidData()->IsPassthrough()) { // Return the default pass-through shader last_entry = &pass_entry; return true; } // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); if (iter != GeometryShaders.end()) { const GSCacheEntry &entry = iter->second; last_entry = &entry; return (entry.shader != nullptr); } // Need to compile a new shader ShaderCode code; GenerateGeometryShaderCode(code, primitive_type, API_D3D); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { GeometryShaders[uid].code = code.GetBuffer(); } return success; }
void ShaderCache::HandleTSUIDChange( const TessellationShaderUid& ts_uid, bool on_gpu_thread) { s_shaders_lock.lock(); std::pair<ByteCodeCacheEntry, ByteCodeCacheEntry>& entry = ts_bytecode_cache->GetOrAdd(ts_uid); s_shaders_lock.unlock(); ByteCodeCacheEntry* dentry = &entry.first; ByteCodeCacheEntry* hentry = &entry.second; if (on_gpu_thread) { if (dentry->m_compiled && hentry->m_compiled) { s_last_domain_shader_bytecode = dentry; s_last_hull_shader_bytecode = hentry; } else { s_last_tessellation_shader_uid = {}; s_last_domain_shader_bytecode = &s_pass_entry; s_last_hull_shader_bytecode = &s_pass_entry; } } if (dentry->m_initialized.test_and_set()) { return; } hentry->m_initialized.test_and_set(); // Need to compile a new shader ShaderCode code; ShaderCompilerWorkUnit *wunit = s_compiler->NewUnit(TESSELLATIONSHADERGEN_BUFFERSIZE); ShaderCompilerWorkUnit *wunitd = s_compiler->NewUnit(TESSELLATIONSHADERGEN_BUFFERSIZE); code.SetBuffer(wunit->code.data()); GenerateTessellationShaderCode(code, API_D3D11, ts_uid.GetUidData()); memcpy(wunitd->code.data(), wunit->code.data(), code.BufferSize()); wunit->codesize = (u32)code.BufferSize(); wunit->entrypoint = "HS_TFO"; wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_SKIP_OPTIMIZATION; wunit->target = D3D::HullShaderVersionString(); wunitd->codesize = (u32)code.BufferSize(); wunitd->entrypoint = "DS_TFO"; wunitd->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3; wunitd->target = D3D::DomainShaderVersionString(); wunitd->ResultHandler = [ts_uid, dentry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { D3DBlob* shaderBuffer = new D3DBlob(wunit->shaderbytecode); s_ds_disk_cache.Append(ts_uid, shaderBuffer->Data(), shaderBuffer->Size()); PushByteCode(dentry, shaderBuffer); wunit->shaderbytecode->Release(); wunit->shaderbytecode = nullptr; } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_ds_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char *)wunit->code.data()); file << ((const char *)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile domain shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::DomainShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; wunit->ResultHandler = [ts_uid, hentry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { D3DBlob* shaderBuffer = new D3DBlob(wunit->shaderbytecode); s_hs_disk_cache.Append(ts_uid, shaderBuffer->Data(), shaderBuffer->Size()); PushByteCode(hentry, shaderBuffer); wunit->shaderbytecode->Release(); wunit->shaderbytecode = nullptr; } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_hs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char *)wunit->code.data()); file << ((const char *)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile hull shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::HullShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; s_compiler->CompileShaderAsync(wunit); s_compiler->CompileShaderAsync(wunitd); }