// Copyright 2017 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include "Common/Assert.h" #include "VideoBackends/OGL/OGLPipeline.h" #include "VideoBackends/OGL/OGLShader.h" #include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/Render.h" #include "VideoBackends/OGL/VertexManager.h" #include "VideoCommon/VideoConfig.h" namespace OGL { static GLenum MapToGLPrimitive(PrimitiveType primitive_type) { switch (primitive_type) { case PrimitiveType::Points: return GL_POINTS; case PrimitiveType::Lines: return GL_LINES; case PrimitiveType::Triangles: return GL_TRIANGLES; case PrimitiveType::TriangleStrip: return GL_TRIANGLE_STRIP; default: return 0; } } OGLPipeline::OGLPipeline(const GLVertexFormat* vertex_format, const RasterizationState& rasterization_state, const DepthState& depth_state, const BlendingState& blending_state, PipelineProgram* program, GLuint gl_primitive) : m_vertex_format(vertex_format), m_rasterization_state(rasterization_state), m_depth_state(depth_state), m_blending_state(blending_state), m_program(program), m_gl_primitive(gl_primitive) { } OGLPipeline::~OGLPipeline() { // We don't want to destroy the shaders. ProgramShaderCache::ReleasePipelineProgram(m_program); } AbstractPipeline::CacheData OGLPipeline::GetCacheData() const { // More than one pipeline can share the same shaders. To avoid bloating the cache with multiple // copies of the same program combination, we set a flag on the program object so that it can't // be retrieved again. When booting, the pipeline cache is loaded in-order, so the additional // pipelines which use the program combination will re-use the already-created object. if (!g_ActiveConfig.backend_info.bSupportsPipelineCacheData || m_program->binary_retrieved) return {}; GLint program_size = 0; glGetProgramiv(m_program->shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &program_size); if (program_size == 0) return {}; // Clear any existing error. glGetError(); // We pack the format at the start of the buffer. CacheData data(program_size + sizeof(u32)); GLsizei data_size = 0; GLenum program_format = 0; glGetProgramBinary(m_program->shader.glprogid, program_size, &data_size, &program_format, &data[sizeof(u32)]); if (glGetError() != GL_NO_ERROR || data_size == 0) return {}; u32 program_format_u32 = static_cast(program_format); std::memcpy(&data[0], &program_format_u32, sizeof(u32)); data.resize(data_size + sizeof(u32)); m_program->binary_retrieved = true; return data; } std::unique_ptr OGLPipeline::Create(const AbstractPipelineConfig& config, const void* cache_data, size_t cache_data_size) { PipelineProgram* program = ProgramShaderCache::GetPipelineProgram( static_cast(config.vertex_format), static_cast(config.vertex_shader), static_cast(config.geometry_shader), static_cast(config.pixel_shader), cache_data, cache_data_size); if (!program) return nullptr; const GLVertexFormat* vertex_format = static_cast(config.vertex_format); GLenum gl_primitive = MapToGLPrimitive(config.rasterization_state.primitive); return std::make_unique(vertex_format, config.rasterization_state, config.depth_state, config.blending_state, program, gl_primitive); } } // namespace OGL