Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/OpenGL/GLProfiler.cpp
10523 views
1
#include <cstdarg>
2
3
#include "Common/GPU/OpenGL/GLProfiler.h"
4
#include "Common/GPU/OpenGL/GLCommon.h"
5
#include "Common/GPU/OpenGL/GLFeatures.h"
6
#include "Common/GPU/OpenGL/GLDebugLog.h"
7
#include "Common/Log.h"
8
9
// For iOS, define function pointer types and variables locally since gl3stub.h
10
// content is excluded on iOS. These will remain NULL since iOS doesn't support
11
// GL_EXT_disjoint_timer_query.
12
#if PPSSPP_PLATFORM(IOS)
13
typedef void (*PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);
14
typedef void (*PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params);
15
static PFNGLQUERYCOUNTERPROC glQueryCounter = nullptr;
16
static PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = nullptr;
17
#endif
18
19
// Constants - same values for both EXT and ARB versions
20
#ifndef GL_TIMESTAMP
21
#define GL_TIMESTAMP 0x8E28
22
#endif
23
#ifndef GL_QUERY_RESULT
24
#define GL_QUERY_RESULT 0x8866
25
#endif
26
#ifndef GL_GPU_DISJOINT_EXT
27
#define GL_GPU_DISJOINT_EXT 0x8FBB
28
#endif
29
30
// GLCommon.h provides access to GL functions:
31
// - On GLES: function pointers from gl3stub.h, loaded via eglGetProcAddress
32
// - On desktop GL: GLEW provides the functions
33
34
void GLProfiler::Init() {
35
supported_ = false;
36
firstFrame_ = true;
37
numQueries_ = 0;
38
scopes_.clear();
39
scopeStack_.clear();
40
41
// Check for extension support
42
// Function pointers are declared in gl3stub.h and loaded appropriately per platform
43
if (gl_extensions.EXT_disjoint_timer_query) {
44
// GLES path - use function pointers loaded with EXT suffix
45
if (glQueryCounter && glGetQueryObjectui64v) {
46
supported_ = true;
47
INFO_LOG(Log::G3D, "GLProfiler: Using GL_EXT_disjoint_timer_query");
48
}
49
} else if (gl_extensions.ARB_timer_query) {
50
// Desktop GL path - use function pointers (no suffix)
51
if (glQueryCounter && glGetQueryObjectui64v) {
52
supported_ = true;
53
INFO_LOG(Log::G3D, "GLProfiler: Using GL_ARB_timer_query");
54
}
55
}
56
57
if (supported_) {
58
// Pre-allocate query objects
59
queries_.resize(MAX_QUERY_COUNT);
60
glGenQueries(MAX_QUERY_COUNT, queries_.data());
61
CHECK_GL_ERROR_IF_DEBUG();
62
}
63
}
64
65
void GLProfiler::Shutdown() {
66
if (supported_ && !queries_.empty()) {
67
glDeleteQueries((GLsizei)queries_.size(), queries_.data());
68
queries_.clear();
69
}
70
supported_ = false;
71
scopes_.clear();
72
scopeStack_.clear();
73
}
74
75
void GLProfiler::BeginFrame() {
76
if (!supported_) {
77
return;
78
}
79
80
// Check if profiling is enabled
81
if (enabledPtr_ && !*enabledPtr_) {
82
scopes_.clear();
83
scopeStack_.clear();
84
numQueries_ = 0;
85
return;
86
}
87
88
// Check for disjoint operation (GPU frequency changed) - GLES only
89
if (gl_extensions.EXT_disjoint_timer_query) {
90
GLint disjoint = 0;
91
glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint);
92
if (disjoint) {
93
// Results are invalid, just clear and start fresh
94
WARN_LOG(Log::G3D, "GLProfiler: GPU disjoint detected, timing results discarded");
95
scopes_.clear();
96
scopeStack_.clear();
97
numQueries_ = 0;
98
firstFrame_ = true;
99
return;
100
}
101
}
102
103
// Read results from previous frame (guaranteed complete now)
104
if (numQueries_ > 0 && !firstFrame_) {
105
static const char * const indent[4] = { "", " ", " ", " " };
106
107
if (!scopes_.empty()) {
108
INFO_LOG(Log::G3D, "OpenGL profiling events this frame:");
109
}
110
111
// Log results
112
for (auto &scope : scopes_) {
113
if (scope.endQueryId == -1) {
114
WARN_LOG(Log::G3D, "Unclosed scope: %s", scope.name);
115
continue;
116
}
117
118
GLuint64 startTime = 0, endTime = 0;
119
glGetQueryObjectui64v(queries_[scope.startQueryId], GL_QUERY_RESULT, &startTime);
120
glGetQueryObjectui64v(queries_[scope.endQueryId], GL_QUERY_RESULT, &endTime);
121
122
// Times are in nanoseconds, convert to milliseconds
123
double milliseconds = (double)(endTime - startTime) / 1000000.0;
124
125
INFO_LOG(Log::G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds);
126
}
127
}
128
129
firstFrame_ = false;
130
scopes_.clear();
131
scopeStack_.clear();
132
numQueries_ = 0;
133
}
134
135
void GLProfiler::Begin(const char *fmt, ...) {
136
if (!supported_ || (enabledPtr_ && !*enabledPtr_) || numQueries_ >= MAX_QUERY_COUNT - 1) {
137
return;
138
}
139
140
GLProfilerScope scope;
141
va_list args;
142
va_start(args, fmt);
143
vsnprintf(scope.name, sizeof(scope.name), fmt, args);
144
va_end(args);
145
scope.startQueryId = numQueries_;
146
scope.endQueryId = -1;
147
scope.level = (int)scopeStack_.size();
148
149
scopeStack_.push_back(scopes_.size());
150
scopes_.push_back(scope);
151
152
glQueryCounter(queries_[numQueries_], GL_TIMESTAMP);
153
numQueries_++;
154
}
155
156
void GLProfiler::End() {
157
if (!supported_ || (enabledPtr_ && !*enabledPtr_) || numQueries_ >= MAX_QUERY_COUNT - 1) {
158
return;
159
}
160
161
if (scopeStack_.empty()) {
162
WARN_LOG(Log::G3D, "GLProfiler::End called without matching Begin");
163
return;
164
}
165
166
size_t scopeId = scopeStack_.back();
167
scopeStack_.pop_back();
168
169
GLProfilerScope &scope = scopes_[scopeId];
170
scope.endQueryId = numQueries_;
171
172
glQueryCounter(queries_[numQueries_], GL_TIMESTAMP);
173
numQueries_++;
174
}
175
176