Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/GLES/GPU_GLES.cpp
5663 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Common/Profiler/Profiler.h"
19
#include "Common/Data/Text/I18n.h"
20
21
#include "Common/Log.h"
22
#include "Common/Serialize/Serializer.h"
23
#include "Common/File/FileUtil.h"
24
#include "Common/GraphicsContext.h"
25
#include "Common/System/OSD.h"
26
#include "Common/VR/PPSSPPVR.h"
27
#include "Common/StringUtils.h"
28
29
#include "Core/Config.h"
30
#include "Core/Reporting.h"
31
#include "Core/Core.h"
32
#include "Core/ELF/ParamSFO.h"
33
34
#include "GPU/GPUState.h"
35
#include "GPU/Common/FramebufferManagerCommon.h"
36
#include "GPU/GLES/ShaderManagerGLES.h"
37
#include "GPU/GLES/GPU_GLES.h"
38
#include "GPU/GLES/FramebufferManagerGLES.h"
39
#include "GPU/GLES/DrawEngineGLES.h"
40
#include "GPU/GLES/TextureCacheGLES.h"
41
42
#ifdef _WIN32
43
#include "Windows/GPU/WindowsGLContext.h"
44
#endif
45
46
GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
47
: GPUCommonHW(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) {
48
gstate_c.SetUseFlags(CheckGPUFeatures());
49
50
shaderManagerGL_ = new ShaderManagerGLES(draw);
51
framebufferManagerGL_ = new FramebufferManagerGLES(draw);
52
framebufferManager_ = framebufferManagerGL_;
53
textureCacheGL_ = new TextureCacheGLES(draw, framebufferManager_->GetDraw2D());
54
textureCache_ = textureCacheGL_;
55
drawEngineCommon_ = &drawEngine_;
56
shaderManager_ = shaderManagerGL_;
57
58
drawEngine_.SetGPUCommon(this);
59
drawEngine_.SetShaderManager(shaderManagerGL_);
60
drawEngine_.SetTextureCache(textureCacheGL_);
61
drawEngine_.SetFramebufferManager(framebufferManagerGL_);
62
drawEngine_.SetFragmentTestCache(&fragmentTestCache_);
63
drawEngine_.Init();
64
framebufferManagerGL_->SetTextureCache(textureCacheGL_);
65
framebufferManagerGL_->SetShaderManager(shaderManagerGL_);
66
framebufferManagerGL_->SetDrawEngine(&drawEngine_);
67
framebufferManagerGL_->Init(msaaLevel_);
68
textureCacheGL_->SetFramebufferManager(framebufferManagerGL_);
69
textureCacheGL_->SetShaderManager(shaderManagerGL_);
70
textureCacheGL_->SetDrawEngine(&drawEngine_);
71
fragmentTestCache_.SetTextureCache(textureCacheGL_);
72
73
// Sanity check gstate
74
if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
75
ERROR_LOG(Log::G3D, "gstate has drifted out of sync!");
76
}
77
78
// No need to flush before the tex scale/offset commands if we are baking
79
// the tex scale/offset into the vertices anyway.
80
81
UpdateCmdInfo();
82
83
BuildReportingInfo();
84
85
textureCache_->NotifyConfigChanged();
86
87
// Load shader cache.
88
std::string discID = g_paramSFO.GetDiscID();
89
if (discID.size()) {
90
if (g_Config.bShaderCache) {
91
File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE));
92
shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) / (discID + ".glshadercache");
93
// Actually precompiled by IsReady() since we're single-threaded.
94
File::IOFile f(shaderCachePath_, "rb");
95
if (f.IsOpen()) {
96
if (shaderManagerGL_->LoadCacheFlags(f, &drawEngine_)) {
97
if (drawEngineCommon_->EverUsedExactEqualDepth()) {
98
sawExactEqualDepth_ = true;
99
}
100
gstate_c.SetUseFlags(CheckGPUFeatures());
101
// We're compiling now, clear if they changed.
102
gstate_c.useFlagsChanged = false;
103
104
if (shaderManagerGL_->LoadCache(f))
105
NOTICE_LOG(Log::G3D, "Precompiling the shader cache from '%s'", shaderCachePath_.c_str());
106
}
107
}
108
} else {
109
INFO_LOG(Log::G3D, "Shader cache disabled. Not loading.");
110
}
111
}
112
113
if (g_Config.bHardwareTessellation) {
114
// Log information that we disable hardware tessellation if device is unsupported.
115
if (!drawEngine_.SupportsHWTessellation()) {
116
ERROR_LOG(Log::G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
117
}
118
}
119
}
120
121
GPU_GLES::~GPU_GLES() {
122
// If we're here during app shutdown (exiting the Windows app in-game, for example)
123
// everything should already be cleared since DeviceLost has been run.
124
125
if (shaderCachePath_.Valid() && draw_) {
126
if (g_Config.bShaderCache) {
127
shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);
128
} else {
129
INFO_LOG(Log::G3D, "Shader cache disabled. Not saving.");
130
}
131
}
132
fragmentTestCache_.Clear();
133
}
134
135
// Take the raw GL extension and versioning data and turn into feature flags.
136
// TODO: This should use DrawContext::GetDeviceCaps() more and more, and eventually
137
// this can be shared between all the backends.
138
u32 GPU_GLES::CheckGPUFeatures() const {
139
u32 features = GPUCommonHW::CheckGPUFeatures();
140
141
features |= GPU_USE_16BIT_FORMATS;
142
143
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
144
features |= GPU_USE_TEXTURE_LOD_CONTROL;
145
146
bool canUseInstanceID = gl_extensions.EXT_draw_instanced || gl_extensions.ARB_draw_instanced;
147
bool canDefInstanceID = gl_extensions.IsGLES || gl_extensions.EXT_gpu_shader4 || gl_extensions.VersionGEThan(3, 1);
148
bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID);
149
if (instanceRendering)
150
features |= GPU_USE_INSTANCE_RENDERING;
151
152
int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits;
153
if (maxVertexTextureImageUnits >= 3) // At least 3 for hardware tessellation
154
features |= GPU_USE_VERTEX_TEXTURE_FETCH;
155
156
if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float)
157
features |= GPU_USE_TEXTURE_FLOAT;
158
159
if (!draw_->GetShaderLanguageDesc().bitwiseOps) {
160
features |= GPU_USE_FRAGMENT_TEST_CACHE;
161
}
162
163
// Can't use switch-case in older glsl.
164
if ((gl_extensions.IsGLES && !gl_extensions.GLES3) || (!gl_extensions.IsGLES && !gl_extensions.VersionGEThan(1, 3)))
165
features &= ~GPU_USE_LIGHT_UBERSHADER;
166
167
if (IsVREnabled() || g_Config.bForceVR) {
168
features |= GPU_USE_VIRTUAL_REALITY;
169
features &= ~GPU_USE_VS_RANGE_CULLING;
170
}
171
172
if (!gl_extensions.GLES3) {
173
// Heuristic.
174
features &= ~GPU_USE_FRAGMENT_UBERSHADER;
175
}
176
177
features = CheckGPUFeaturesLate(features);
178
179
if (draw_->GetBugs().Has(Draw::Bugs::ADRENO_RESOURCE_DEADLOCK) && g_Config.bVendorBugChecksEnabled) {
180
if (PSP_CoreParameter().compat.flags().OldAdrenoPixelDepthRoundingGL) {
181
features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
182
}
183
}
184
185
// This is a bit ugly, but lets us reuse most of the depth logic in GPUCommon.
186
if (features & GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) {
187
if (gl_extensions.IsGLES && !gl_extensions.GLES3) {
188
// Unsupported, switch to GPU_ROUND_DEPTH_TO_16BIT instead.
189
features &= ~GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
190
features |= GPU_ROUND_DEPTH_TO_16BIT;
191
}
192
}
193
return features;
194
}
195
196
void GPU_GLES::BuildReportingInfo() {
197
GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
198
199
std::string glVendor = render->GetGLString(GL_VENDOR);
200
std::string glRenderer = render->GetGLString(GL_RENDERER);
201
std::string glVersion = render->GetGLString(GL_VERSION);
202
std::string glSlVersion = render->GetGLString(GL_SHADING_LANGUAGE_VERSION);
203
std::string glExtensions;
204
205
if (gl_extensions.VersionGEThan(3, 0)) {
206
glExtensions = g_all_gl_extensions;
207
} else {
208
glExtensions = render->GetGLString(GL_EXTENSIONS);
209
}
210
211
reportingPrimaryInfo_ = glVendor;
212
reportingFullInfo_ = StringFromFormat("%s (%s %s), %s (extensions: %s)", glVersion.c_str(), glVendor.c_str(), glRenderer.c_str(), glSlVersion.c_str(), glExtensions.c_str());
213
214
Reporting::UpdateConfig();
215
}
216
217
void GPU_GLES::DeviceLost() {
218
INFO_LOG(Log::G3D, "GPU_GLES: DeviceLost");
219
220
// Simply drop all caches and textures.
221
// FBOs appear to survive? Or no?
222
// TransformDraw has registered as a GfxResourceHolder.
223
fragmentTestCache_.DeviceLost();
224
225
GPUCommonHW::DeviceLost();
226
}
227
228
void GPU_GLES::DeviceRestore(Draw::DrawContext *draw) {
229
GPUCommonHW::DeviceRestore(draw);
230
231
fragmentTestCache_.DeviceRestore(draw_);
232
}
233
234
void GPU_GLES::BeginHostFrame(const DisplayLayoutConfig &config) {
235
GPUCommonHW::BeginHostFrame(config);
236
drawEngine_.BeginFrame();
237
238
textureCache_->StartFrame();
239
240
// Save the cache from time to time. TODO: How often? We save on exit, so shouldn't need to do this all that often.
241
242
const int saveShaderCacheFrameInterval = 32767; // power of 2 - 1. About every 10 minutes at 60fps.
243
if (shaderCachePath_.Valid() && !(gpuStats.numFlips & saveShaderCacheFrameInterval) && coreState == CORE_RUNNING_CPU) {
244
shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);
245
}
246
shaderManagerGL_->DirtyLastShader();
247
248
// Not sure if this is really needed.
249
gstate_c.Dirty(DIRTY_ALL_UNIFORMS);
250
251
framebufferManager_->BeginFrame(config);
252
253
fragmentTestCache_.Decimate();
254
if (gstate_c.useFlagsChanged) {
255
// TODO: It'd be better to recompile them in the background, probably?
256
// This most likely means that saw equal depth changed.
257
WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers");
258
shaderManager_->ClearShaders();
259
framebufferManager_->ClearAllDepthBuffers();
260
gstate_c.useFlagsChanged = false;
261
}
262
}
263
264
void GPU_GLES::EndHostFrame() {
265
drawEngine_.EndFrame();
266
}
267
268
void GPU_GLES::FinishDeferred() {
269
// This finishes reading any vertex data that is pending.
270
drawEngine_.FinishDeferred();
271
}
272
273
void GPU_GLES::GetStats(char *buffer, size_t bufsize) {
274
size_t offset = FormatGPUStatsCommon(buffer, bufsize);
275
buffer += offset;
276
bufsize -= offset;
277
if ((int)bufsize < 0)
278
return;
279
snprintf(buffer, bufsize,
280
"Vertex, Fragment, Programs loaded: %d, %d, %d\n",
281
shaderManagerGL_->GetNumVertexShaders(),
282
shaderManagerGL_->GetNumFragmentShaders(),
283
shaderManagerGL_->GetNumPrograms()
284
);
285
}
286
287