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/GLES/GPU_GLES.cpp
Views: 1401
// Copyright (c) 2012- 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 "Common/Profiler/Profiler.h"18#include "Common/Data/Text/I18n.h"1920#include "Common/Log.h"21#include "Common/Serialize/Serializer.h"22#include "Common/File/FileUtil.h"23#include "Common/GraphicsContext.h"24#include "Common/System/OSD.h"25#include "Common/VR/PPSSPPVR.h"2627#include "Core/Config.h"28#include "Core/Debugger/Breakpoints.h"29#include "Core/MemMapHelpers.h"30#include "Core/Config.h"31#include "Core/Reporting.h"32#include "Core/System.h"33#include "Core/ELF/ParamSFO.h"3435#include "GPU/GPUState.h"36#include "GPU/ge_constants.h"37#include "GPU/GeDisasm.h"38#include "GPU/Common/FramebufferManagerCommon.h"39#include "GPU/GLES/ShaderManagerGLES.h"40#include "GPU/GLES/GPU_GLES.h"41#include "GPU/GLES/FramebufferManagerGLES.h"42#include "GPU/GLES/DrawEngineGLES.h"43#include "GPU/GLES/TextureCacheGLES.h"4445#ifdef _WIN3246#include "Windows/GPU/WindowsGLContext.h"47#endif4849GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)50: GPUCommonHW(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) {51gstate_c.SetUseFlags(CheckGPUFeatures());5253shaderManagerGL_ = new ShaderManagerGLES(draw);54framebufferManagerGL_ = new FramebufferManagerGLES(draw);55framebufferManager_ = framebufferManagerGL_;56textureCacheGL_ = new TextureCacheGLES(draw, framebufferManager_->GetDraw2D());57textureCache_ = textureCacheGL_;58drawEngineCommon_ = &drawEngine_;59shaderManager_ = shaderManagerGL_;6061drawEngine_.SetShaderManager(shaderManagerGL_);62drawEngine_.SetTextureCache(textureCacheGL_);63drawEngine_.SetFramebufferManager(framebufferManagerGL_);64drawEngine_.SetFragmentTestCache(&fragmentTestCache_);65drawEngine_.Init();66framebufferManagerGL_->SetTextureCache(textureCacheGL_);67framebufferManagerGL_->SetShaderManager(shaderManagerGL_);68framebufferManagerGL_->SetDrawEngine(&drawEngine_);69framebufferManagerGL_->Init(msaaLevel_);70textureCacheGL_->SetFramebufferManager(framebufferManagerGL_);71textureCacheGL_->SetShaderManager(shaderManagerGL_);72textureCacheGL_->SetDrawEngine(&drawEngine_);73fragmentTestCache_.SetTextureCache(textureCacheGL_);7475// Sanity check gstate76if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {77ERROR_LOG(Log::G3D, "gstate has drifted out of sync!");78}7980// No need to flush before the tex scale/offset commands if we are baking81// the tex scale/offset into the vertices anyway.8283UpdateCmdInfo();8485BuildReportingInfo();8687textureCache_->NotifyConfigChanged();8889// Load shader cache.90std::string discID = g_paramSFO.GetDiscID();91if (discID.size()) {92if (g_Config.bShaderCache) {93File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE));94shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) / (discID + ".glshadercache");95// Actually precompiled by IsReady() since we're single-threaded.96File::IOFile f(shaderCachePath_, "rb");97if (f.IsOpen()) {98if (shaderManagerGL_->LoadCacheFlags(f, &drawEngine_)) {99if (drawEngineCommon_->EverUsedExactEqualDepth()) {100sawExactEqualDepth_ = true;101}102gstate_c.SetUseFlags(CheckGPUFeatures());103// We're compiling now, clear if they changed.104gstate_c.useFlagsChanged = false;105106if (shaderManagerGL_->LoadCache(f))107NOTICE_LOG(Log::G3D, "Precompiling the shader cache from '%s'", shaderCachePath_.c_str());108}109}110} else {111INFO_LOG(Log::G3D, "Shader cache disabled. Not loading.");112}113}114115if (g_Config.bHardwareTessellation) {116// Disable hardware tessellation if device is unsupported.117if (!drawEngine_.SupportsHWTessellation()) {118ERROR_LOG(Log::G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");119auto gr = GetI18NCategory(I18NCat::GRAPHICS);120g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("Turn off Hardware Tessellation - unsupported"));121}122}123}124125GPU_GLES::~GPU_GLES() {126// If we're here during app shutdown (exiting the Windows app in-game, for example)127// everything should already be cleared since DeviceLost has been run.128129if (shaderCachePath_.Valid() && draw_) {130if (g_Config.bShaderCache) {131shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);132} else {133INFO_LOG(Log::G3D, "Shader cache disabled. Not saving.");134}135}136fragmentTestCache_.Clear();137}138139// Take the raw GL extension and versioning data and turn into feature flags.140// TODO: This should use DrawContext::GetDeviceCaps() more and more, and eventually141// this can be shared between all the backends.142u32 GPU_GLES::CheckGPUFeatures() const {143u32 features = GPUCommonHW::CheckGPUFeatures();144145features |= GPU_USE_16BIT_FORMATS;146147if (gl_extensions.GLES3 || !gl_extensions.IsGLES)148features |= GPU_USE_TEXTURE_LOD_CONTROL;149150bool canUseInstanceID = gl_extensions.EXT_draw_instanced || gl_extensions.ARB_draw_instanced;151bool canDefInstanceID = gl_extensions.IsGLES || gl_extensions.EXT_gpu_shader4 || gl_extensions.VersionGEThan(3, 1);152bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID);153if (instanceRendering)154features |= GPU_USE_INSTANCE_RENDERING;155156int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits;157if (maxVertexTextureImageUnits >= 3) // At least 3 for hardware tessellation158features |= GPU_USE_VERTEX_TEXTURE_FETCH;159160if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float)161features |= GPU_USE_TEXTURE_FLOAT;162163if (!draw_->GetShaderLanguageDesc().bitwiseOps) {164features |= GPU_USE_FRAGMENT_TEST_CACHE;165}166167// Can't use switch-case in older glsl.168if ((gl_extensions.IsGLES && !gl_extensions.GLES3) || (!gl_extensions.IsGLES && !gl_extensions.VersionGEThan(1, 3)))169features &= ~GPU_USE_LIGHT_UBERSHADER;170171if (IsVREnabled() || g_Config.bForceVR) {172features |= GPU_USE_VIRTUAL_REALITY;173features &= ~GPU_USE_VS_RANGE_CULLING;174}175176if (!gl_extensions.GLES3) {177// Heuristic.178features &= ~GPU_USE_FRAGMENT_UBERSHADER;179}180181features = CheckGPUFeaturesLate(features);182183if (draw_->GetBugs().Has(Draw::Bugs::ADRENO_RESOURCE_DEADLOCK) && g_Config.bVendorBugChecksEnabled) {184if (PSP_CoreParameter().compat.flags().OldAdrenoPixelDepthRoundingGL) {185features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;186}187}188189// This is a bit ugly, but lets us reuse most of the depth logic in GPUCommon.190if (features & GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) {191if (gl_extensions.IsGLES && !gl_extensions.GLES3) {192// Unsupported, switch to GPU_ROUND_DEPTH_TO_16BIT instead.193features &= ~GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;194features |= GPU_ROUND_DEPTH_TO_16BIT;195}196}197return features;198}199200void GPU_GLES::BuildReportingInfo() {201GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);202203std::string glVendor = render->GetGLString(GL_VENDOR);204std::string glRenderer = render->GetGLString(GL_RENDERER);205std::string glVersion = render->GetGLString(GL_VERSION);206std::string glSlVersion = render->GetGLString(GL_SHADING_LANGUAGE_VERSION);207std::string glExtensions;208209if (gl_extensions.VersionGEThan(3, 0)) {210glExtensions = g_all_gl_extensions;211} else {212glExtensions = render->GetGLString(GL_EXTENSIONS);213}214215char temp[16384];216snprintf(temp, sizeof(temp), "%s (%s %s), %s (extensions: %s)", glVersion.c_str(), glVendor.c_str(), glRenderer.c_str(), glSlVersion.c_str(), glExtensions.c_str());217reportingPrimaryInfo_ = glVendor;218reportingFullInfo_ = temp;219220Reporting::UpdateConfig();221}222223void GPU_GLES::DeviceLost() {224INFO_LOG(Log::G3D, "GPU_GLES: DeviceLost");225226// Simply drop all caches and textures.227// FBOs appear to survive? Or no?228// TransformDraw has registered as a GfxResourceHolder.229fragmentTestCache_.DeviceLost();230231GPUCommonHW::DeviceLost();232}233234void GPU_GLES::DeviceRestore(Draw::DrawContext *draw) {235GPUCommonHW::DeviceRestore(draw);236237fragmentTestCache_.DeviceRestore(draw_);238}239240void GPU_GLES::BeginHostFrame() {241GPUCommonHW::BeginHostFrame();242drawEngine_.BeginFrame();243244textureCache_->StartFrame();245246// Save the cache from time to time. TODO: How often? We save on exit, so shouldn't need to do this all that often.247248const int saveShaderCacheFrameInterval = 32767; // power of 2 - 1. About every 10 minutes at 60fps.249if (shaderCachePath_.Valid() && !(gpuStats.numFlips & saveShaderCacheFrameInterval) && coreState == CORE_RUNNING) {250shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);251}252shaderManagerGL_->DirtyLastShader();253254// Not sure if this is really needed.255gstate_c.Dirty(DIRTY_ALL_UNIFORMS);256257framebufferManager_->BeginFrame();258259fragmentTestCache_.Decimate();260if (gstate_c.useFlagsChanged) {261// TODO: It'd be better to recompile them in the background, probably?262// This most likely means that saw equal depth changed.263WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers");264shaderManager_->ClearShaders();265framebufferManager_->ClearAllDepthBuffers();266gstate_c.useFlagsChanged = false;267}268}269270void GPU_GLES::EndHostFrame() {271drawEngine_.EndFrame();272}273274void GPU_GLES::FinishDeferred() {275// This finishes reading any vertex data that is pending.276drawEngine_.FinishDeferred();277}278279void GPU_GLES::GetStats(char *buffer, size_t bufsize) {280size_t offset = FormatGPUStatsCommon(buffer, bufsize);281buffer += offset;282bufsize -= offset;283if ((int)bufsize < 0)284return;285snprintf(buffer, bufsize,286"Vertex, Fragment, Programs loaded: %d, %d, %d\n",287shaderManagerGL_->GetNumVertexShaders(),288shaderManagerGL_->GetNumFragmentShaders(),289shaderManagerGL_->GetNumPrograms()290);291}292293294