Bug Summary

File:Source/Plugins/Plugin_VideoOGL/Src/Render.cpp
Location:line 535, column 3
Description:Value stored to 'bSuccess' is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "Globals.h"
6#include "Thread.h"
7#include "Atomic.h"
8
9#include <vector>
10#include <cmath>
11#include <cstdio>
12
13#include "GLUtil.h"
14#if defined(HAVE_WX1) && HAVE_WX1
15#include "WxUtils.h"
16#endif
17
18#include "FileUtil.h"
19
20#ifdef _WIN32
21#include <mmsystem.h>
22#endif
23
24#include "CommonPaths.h"
25#include "DriverDetails.h"
26#include "VideoConfig.h"
27#include "Statistics.h"
28#include "ImageWrite.h"
29#include "PixelEngine.h"
30#include "Render.h"
31#include "OpcodeDecoding.h"
32#include "BPStructs.h"
33#include "TextureCache.h"
34#include "RasterFont.h"
35#include "VertexShaderGen.h"
36#include "DLCache.h"
37#include "PixelShaderManager.h"
38#include "ProgramShaderCache.h"
39#include "VertexShaderManager.h"
40#include "VertexLoaderManager.h"
41#include "VertexLoader.h"
42#include "PostProcessing.h"
43#include "TextureConverter.h"
44#include "OnScreenDisplay.h"
45#include "Timer.h"
46#include "StringUtil.h"
47#include "FramebufferManager.h"
48#include "Fifo.h"
49#include "Debugger.h"
50#include "Core.h"
51#include "Movie.h"
52#include "Host.h"
53#include "BPFunctions.h"
54#include "FPSCounter.h"
55#include "ConfigManager.h"
56#include "VertexManager.h"
57#include "SamplerCache.h"
58#include "StreamBuffer.h"
59
60#include "main.h" // Local
61#ifdef _WIN32
62#include "EmuWindow.h"
63#endif
64#if defined _WIN32 || defined HAVE_LIBAV
65#include "AVIDump.h"
66#endif
67
68#if defined(HAVE_WX1) && HAVE_WX1
69#include <wx/image.h>
70#endif
71
72// glew1.8 doesn't define KHR_debug
73#ifndef GL_DEBUG_OUTPUT0x92E0
74#define GL_DEBUG_OUTPUT0x92E0 0x92E0
75#endif
76
77
78void VideoConfig::UpdateProjectionHack()
79{
80 ::UpdateProjectionHack(g_Config.iPhackvalue, g_Config.sPhackvalue);
81}
82
83
84#if defined(HAVE_WX1) && HAVE_WX1
85// Screenshot thread struct
86typedef struct
87{
88 int W, H;
89 std::string filename;
90 wxImage *img;
91} ScrStrct;
92#endif
93
94
95int OSDInternalW, OSDInternalH;
96
97namespace OGL
98{
99
100enum MultisampleMode {
101 MULTISAMPLE_OFF,
102 MULTISAMPLE_2X,
103 MULTISAMPLE_4X,
104 MULTISAMPLE_8X,
105 MULTISAMPLE_CSAA_8X,
106 MULTISAMPLE_CSAA_8XQ,
107 MULTISAMPLE_CSAA_16X,
108 MULTISAMPLE_CSAA_16XQ,
109 MULTISAMPLE_SSAA_4X,
110};
111
112
113VideoConfig g_ogl_config;
114
115// Declarations and definitions
116// ----------------------------
117static int s_fps = 0;
118static GLuint s_ShowEFBCopyRegions_VBO = 0;
119static GLuint s_ShowEFBCopyRegions_VAO = 0;
120static SHADER s_ShowEFBCopyRegions;
121
122static RasterFont* s_pfont = NULL__null;
123
124// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
125static int s_MSAASamples = 1;
126static int s_MSAACoverageSamples = 0;
127static int s_LastMultisampleMode = 0;
128
129static u32 s_blendMode;
130
131static bool s_vsync;
132
133#if defined(HAVE_WX1) && HAVE_WX1
134static std::thread scrshotThread;
135#endif
136
137// EFB cache related
138static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks.
139static const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up
140static const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE;
141static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT];
142static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR
143
144int GetNumMSAASamples(int MSAAMode)
145{
146 int samples;
147 switch (MSAAMode)
148 {
149 case MULTISAMPLE_OFF:
150 samples = 1;
151 break;
152
153 case MULTISAMPLE_2X:
154 samples = 2;
155 break;
156
157 case MULTISAMPLE_4X:
158 case MULTISAMPLE_CSAA_8X:
159 case MULTISAMPLE_CSAA_16X:
160 case MULTISAMPLE_SSAA_4X:
161 samples = 4;
162 break;
163
164 case MULTISAMPLE_8X:
165 case MULTISAMPLE_CSAA_8XQ:
166 case MULTISAMPLE_CSAA_16XQ:
167 samples = 8;
168 break;
169
170 default:
171 samples = 1;
172 }
173
174 if(samples <= g_ogl_config.max_samples) return samples;
175
176 ERROR_LOG(VIDEO, "MSAA Bug: %d samples selected, but only %d supported by GPU.", samples, g_ogl_config.max_samples)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 176, "MSAA Bug: %d samples selected, but only %d supported by GPU."
, samples, g_ogl_config.max_samples); } } while (0)
;
177 return g_ogl_config.max_samples;
178}
179
180int GetNumMSAACoverageSamples(int MSAAMode)
181{
182 int samples;
183 switch (g_ActiveConfig.iMultisampleMode)
184 {
185 case MULTISAMPLE_CSAA_8X:
186 case MULTISAMPLE_CSAA_8XQ:
187 samples = 8;
188 break;
189
190 case MULTISAMPLE_CSAA_16X:
191 case MULTISAMPLE_CSAA_16XQ:
192 samples = 16;
193 break;
194
195 default:
196 samples = 0;
197 }
198 if(g_ogl_config.bSupportCoverageMSAA || samples == 0) return samples;
199
200 ERROR_LOG(VIDEO, "MSAA Bug: CSAA selected, but not supported by GPU.")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 200, "MSAA Bug: CSAA selected, but not supported by GPU.");
} } while (0)
;
201 return 0;
202}
203
204void ApplySSAASettings() {
205 // GLES3 doesn't support SSAA
206#ifndef USE_GLES3
207 if(g_ActiveConfig.iMultisampleMode == MULTISAMPLE_SSAA_4X) {
208 if(g_ogl_config.bSupportSampleShading) {
209 glEnable(GL_SAMPLE_SHADING_ARB0x8C36);
210 glMinSampleShadingARB__glewMinSampleShadingARB(s_MSAASamples);
211 } else {
212 ERROR_LOG(VIDEO, "MSAA Bug: SSAA selected, but not supported by GPU.")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 212, "MSAA Bug: SSAA selected, but not supported by GPU.");
} } while (0)
;
213 }
214 } else if(g_ogl_config.bSupportSampleShading) {
215 glDisable(GL_SAMPLE_SHADING_ARB0x8C36);
216 }
217#endif
218}
219
220void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, void* userParam)
221{
222 // GLES3 doesn't natively support this
223 // XXX: Include GLES2 extensions header so we can use this
224#ifndef USE_GLES3
225 const char *s_source;
226 const char *s_type;
227
228 switch(source)
229 {
230 case GL_DEBUG_SOURCE_API_ARB0x8246: s_source = "API"; break;
231 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB0x8247: s_source = "Window System"; break;
232 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB0x8248: s_source = "Shader Compiler"; break;
233 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB0x8249: s_source = "Third Party"; break;
234 case GL_DEBUG_SOURCE_APPLICATION_ARB0x824A: s_source = "Application"; break;
235 case GL_DEBUG_SOURCE_OTHER_ARB0x824B: s_source = "Other"; break;
236 default: s_source = "Unknown"; break;
237 }
238 switch(type)
239 {
240 case GL_DEBUG_TYPE_ERROR_ARB0x824C: s_type = "Error"; break;
241 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB0x824D: s_type = "Deprecated"; break;
242 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB0x824E: s_type = "Undefined"; break;
243 case GL_DEBUG_TYPE_PORTABILITY_ARB0x824F: s_type = "Portability"; break;
244 case GL_DEBUG_TYPE_PERFORMANCE_ARB0x8250: s_type = "Performance"; break;
245 case GL_DEBUG_TYPE_OTHER_ARB0x8251: s_type = "Other"; break;
246 default: s_type = "Unknown"; break;
247 }
248 switch(severity)
249 {
250 case GL_DEBUG_SEVERITY_HIGH_ARB0x9146: ERROR_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 250, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
251 case GL_DEBUG_SEVERITY_MEDIUM_ARB0x9147: WARN_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 251, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
252 case GL_DEBUG_SEVERITY_LOW_ARB0x9148: WARN_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 252, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
253 default: ERROR_LOG(VIDEO, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 253, "id: %x, source: %s, type: %s - %s", id, s_source, s_type
, message); } } while (0)
; break;
254 }
255#endif
256}
257
258#ifndef USE_GLES3
259// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
260void GLAPIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
261{
262 glDepthRange(neardepth, fardepth);
263}
264void GLAPIENTRY ClearDepthf(GLfloat depthval)
265{
266 glClearDepth(depthval);
267}
268#endif
269
270void InitDriverInfo()
271{
272 // Get Vendor
273 std::string svendor = std::string(g_ogl_config.gl_vendor);
274 std::string srenderer = std::string(g_ogl_config.gl_renderer);
275 DriverDetails::Vendor vendor = DriverDetails::VENDOR_UNKNOWN;
276 u32 devfamily = 0;
277 double version = 0.0;
278
279 // Get Vendor first
280 if (svendor == "NVIDIA Corporation" && srenderer != "NVIDIA Tegra")
281 vendor = DriverDetails::VENDOR_NVIDIA;
282 else if (svendor == "ATI Technologies Inc.")
283 vendor = DriverDetails::VENDOR_ATI;
284 else if (std::string::npos != svendor.find("Intel"))
285 vendor = DriverDetails::VENDOR_INTEL;
286 else if (svendor == "ARM")
287 vendor = DriverDetails::VENDOR_ARM;
288 else if (svendor == "Qualcomm")
289 vendor = DriverDetails::VENDOR_QUALCOMM;
290 else if (svendor == "Imagination Technologies")
291 vendor = DriverDetails::VENDOR_IMGTEC;
292 else if (svendor == "NVIDIA Corporation" && srenderer == "NVIDIA Tegra")
293 vendor = DriverDetails::VENDOR_TEGRA;
294 else if (svendor == "Vivante Corporation")
295 vendor = DriverDetails::VENDOR_VIVANTE;
296
297 // Get device family and driver version...if we care about it
298 switch(vendor)
299 {
300 case DriverDetails::VENDOR_QUALCOMM:
301 {
302 if (std::string::npos != srenderer.find("Adreno (TM) 3"))
303 devfamily = 300;
304 else
305 devfamily = 200;
306 double glVersion;
307 sscanf(g_ogl_config.gl_version, "OpenGL ES %lg V@%lg", &glVersion, &version);
308 }
309 break;
310 // We don't care about these
311 default:
312 break;
313 }
314 DriverDetails::Init(vendor, devfamily, version);
315}
316
317// Init functions
318Renderer::Renderer()
319{
320 OSDInternalW = 0;
321 OSDInternalH = 0;
322
323 s_fps=0;
324 s_ShowEFBCopyRegions_VBO = 0;
325 s_blendMode = 0;
326 InitFPSCounter();
327
328 bool bSuccess = true;
329
330 g_ogl_config.gl_vendor = (const char*)glGetString(GL_VENDOR0x1F00);
331 g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER0x1F01);
332 g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION0x1F02);
333 g_ogl_config.glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION0x8B8C);
334
335 InitDriverInfo();
336
337 // Init extension support.
338#ifdef USE_GLES3
339 // Set default GLES3 options
340 GLFunc::Init();
341 WARN_LOG(VIDEO, "Running the OpenGL ES 3 backend!")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 341, "Running the OpenGL ES 3 backend!"); } } while (0)
;
342 g_Config.backend_info.bSupportsDualSourceBlend = false;
343 g_Config.backend_info.bSupportsGLSLUBO = true;
344 g_Config.backend_info.bSupportsPrimitiveRestart = false;
345 g_Config.backend_info.bSupportsEarlyZ = false;
346
347 g_ogl_config.bSupportsGLSLCache = false; // XXX: Reenable once shaders compile correctly
348 g_ogl_config.bSupportsGLPinnedMemory = false;
349 g_ogl_config.bSupportsGLSync = true;
350 g_ogl_config.bSupportsGLBaseVertex = false;
351 g_ogl_config.bSupportCoverageMSAA = false; // XXX: GLES3 spec has MSAA
352 g_ogl_config.bSupportSampleShading = false;
353 g_ogl_config.bSupportOGL31 = false;
354 g_ogl_config.eSupportedGLSLVersion = GLSLES3;
355#else
356 GLint numvertexattribs = 0;
357 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS0x8869, &numvertexattribs);
358 if (numvertexattribs < 16)
359 {
360 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Number of attributes %d not enough.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 362, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
"GPU: Does your video card support OpenGL 2.x?", numvertexattribs
); } } while (0)
361 "GPU: Does your video card support OpenGL 2.x?",do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 362, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
"GPU: Does your video card support OpenGL 2.x?", numvertexattribs
); } } while (0)
362 numvertexattribs)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 362, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
"GPU: Does your video card support OpenGL 2.x?", numvertexattribs
); } } while (0)
;
363 bSuccess = false;
364 }
365#ifdef __APPLE__
366 glewExperimental = 1;
367#endif
368 if (glewInit() != GLEW_OK0)
369 {
370 ERROR_LOG(VIDEO, "glewInit() failed! Does your video card support OpenGL 2.x?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 370, "glewInit() failed! Does your video card support OpenGL 2.x?"
); } } while (0)
;
371 return; // TODO: fail
372 }
373
374#if defined(_DEBUG) || defined(DEBUGFAST)
375 if (GLEW_ARB_debug_output(*(const GLboolean*)&__GLEW_ARB_debug_output))
376 {
377 glDebugMessageControlARB__glewDebugMessageControlARB(GL_DONT_CARE0x1100, GL_DONT_CARE0x1100, GL_DONT_CARE0x1100, 0, NULL__null, true);
378 glDebugMessageCallbackARB__glewDebugMessageCallbackARB( ErrorCallback, NULL__null );
379 glEnable( GL_DEBUG_OUTPUT0x92E0 );
380 }
381#endif
382
383 if (!GLEW_EXT_secondary_color(*(const GLboolean*)&__GLEW_EXT_secondary_color))
384 {
385 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 386, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n" "GPU: Does your video card support OpenGL 2.x?"
); } } while (0)
386 "GPU: Does your video card support OpenGL 2.x?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 386, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n" "GPU: Does your video card support OpenGL 2.x?"
); } } while (0)
;
387 bSuccess = false;
388 }
389
390 if (!GLEW_ARB_framebuffer_object(*(const GLboolean*)&__GLEW_ARB_framebuffer_object))
391 {
392 ERROR_LOG(VIDEO, "GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 393, "GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n"
"GPU: Does your video card support OpenGL 3.0?"); } } while (
0)
393 "GPU: Does your video card support OpenGL 3.0?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 393, "GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n"
"GPU: Does your video card support OpenGL 3.0?"); } } while (
0)
;
394 bSuccess = false;
395 }
396
397 if (!GLEW_ARB_vertex_array_object(*(const GLboolean*)&__GLEW_ARB_vertex_array_object))
398 {
399 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 400, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
400 "GPU: Does your video card support OpenGL 3.0?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 400, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
;
401 bSuccess = false;
402 }
403
404 if (!GLEW_ARB_map_buffer_range(*(const GLboolean*)&__GLEW_ARB_map_buffer_range))
405 {
406 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 407, "GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
407 "GPU: Does your video card support OpenGL 3.0?")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 407, "GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n" "GPU: Does your video card support OpenGL 3.0?"
); } } while (0)
;
408 bSuccess = false;
409 }
410
411 if (!GLEW_ARB_sampler_objects(*(const GLboolean*)&__GLEW_ARB_sampler_objects) && bSuccess)
412 {
413 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_sampler_objects."do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 415, "GPU: OGL ERROR: Need GL_ARB_sampler_objects." "GPU: Does your video card support OpenGL 3.2?"
"Please report this issue, then there will be a workaround")
; } } while (0)
414 "GPU: Does your video card support OpenGL 3.2?"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 415, "GPU: OGL ERROR: Need GL_ARB_sampler_objects." "GPU: Does your video card support OpenGL 3.2?"
"Please report this issue, then there will be a workaround")
; } } while (0)
415 "Please report this issue, then there will be a workaround")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 415, "GPU: OGL ERROR: Need GL_ARB_sampler_objects." "GPU: Does your video card support OpenGL 3.2?"
"Please report this issue, then there will be a workaround")
; } } while (0)
;
416 bSuccess = false;
417 }
418 if (!GLEW_ARB_texture_non_power_of_two(*(const GLboolean*)&__GLEW_ARB_texture_non_power_of_two))
419 WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported.")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 419, "ARB_texture_non_power_of_two not supported."); } } while
(0)
;
420
421 // OpenGL 3 doesn't provide GLES like float functions for depth.
422 // They are in core in OpenGL 4.1, so almost every driver should support them.
423 // But for the oldest ones, we provide fallbacks to the old double functions.
424 if (!GLEW_ARB_ES2_compatibility(*(const GLboolean*)&__GLEW_ARB_ES2_compatibility))
425 {
426 glDepthRangef__glewDepthRangef = DepthRangef;
427 glClearDepthf__glewClearDepthf = ClearDepthf;
428
429 }
430
431 if (!bSuccess)
432 return; // TODO: fail
433
434 g_Config.backend_info.bSupportsDualSourceBlend = GLEW_ARB_blend_func_extended(*(const GLboolean*)&__GLEW_ARB_blend_func_extended);
435 g_Config.backend_info.bSupportsGLSLUBO = GLEW_ARB_uniform_buffer_object(*(const GLboolean*)&__GLEW_ARB_uniform_buffer_object);
436 g_Config.backend_info.bSupportsPrimitiveRestart = GLEW_VERSION_3_1(*(const GLboolean*)&__GLEW_VERSION_3_1) || GLEW_NV_primitive_restart(*(const GLboolean*)&__GLEW_NV_primitive_restart);
437 g_Config.backend_info.bSupportsEarlyZ = GLEW_ARB_shader_image_load_store(*(const GLboolean*)&__GLEW_ARB_shader_image_load_store);
438
439 g_ogl_config.bSupportsGLSLCache = GLEW_ARB_get_program_binary(*(const GLboolean*)&__GLEW_ARB_get_program_binary);
440 g_ogl_config.bSupportsGLPinnedMemory = GLEW_AMD_pinned_memory(*(const GLboolean*)&__GLEW_AMD_pinned_memory);
441 g_ogl_config.bSupportsGLSync = GLEW_ARB_sync(*(const GLboolean*)&__GLEW_ARB_sync);
442 g_ogl_config.bSupportsGLBaseVertex = GLEW_ARB_draw_elements_base_vertex(*(const GLboolean*)&__GLEW_ARB_draw_elements_base_vertex
)
;
443 g_ogl_config.bSupportCoverageMSAA = GLEW_NV_framebuffer_multisample_coverage(*(const GLboolean*)&__GLEW_NV_framebuffer_multisample_coverage
)
;
444 g_ogl_config.bSupportSampleShading = GLEW_ARB_sample_shading(*(const GLboolean*)&__GLEW_ARB_sample_shading);
445 g_ogl_config.bSupportOGL31 = GLEW_VERSION_3_1(*(const GLboolean*)&__GLEW_VERSION_3_1);
446
447 if(strstr(g_ogl_config.glsl_version, "1.00") || strstr(g_ogl_config.glsl_version, "1.10"))
448 {
449 ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need at least GLSL 1.20\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 451, "GPU: OGL ERROR: Need at least GLSL 1.20\n" "GPU: Does your video card support OpenGL 2.1?\n"
"GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version
); } } while (0)
450 "GPU: Does your video card support OpenGL 2.1?\n"do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 451, "GPU: OGL ERROR: Need at least GLSL 1.20\n" "GPU: Does your video card support OpenGL 2.1?\n"
"GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version
); } } while (0)
451 "GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 451, "GPU: OGL ERROR: Need at least GLSL 1.20\n" "GPU: Does your video card support OpenGL 2.1?\n"
"GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version
); } } while (0)
;
452 bSuccess = false;
453 }
454 else if(strstr(g_ogl_config.glsl_version, "1.20"))
455 {
456 g_ogl_config.eSupportedGLSLVersion = GLSL_120;
457 g_Config.backend_info.bSupportsDualSourceBlend = false; //TODO: implement dual source blend
458 g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
459 }
460 else if(strstr(g_ogl_config.glsl_version, "1.30"))
461 {
462 g_ogl_config.eSupportedGLSLVersion = GLSL_130;
463 g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
464 }
465 else if(strstr(g_ogl_config.glsl_version, "1.40"))
466 {
467 g_ogl_config.eSupportedGLSLVersion = GLSL_140;
468 g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
469 }
470 else
471 {
472 g_ogl_config.eSupportedGLSLVersion = GLSL_150;
473 }
474#endif
475
476 glGetIntegerv(GL_MAX_SAMPLES0x8D57, &g_ogl_config.max_samples);
477 if(g_ogl_config.max_samples < 1)
478 g_ogl_config.max_samples = 1;
479
480 if(g_Config.backend_info.bSupportsGLSLUBO && (
481 // hd3000 get corruption, hd4000 also and a big slowdown
482 !strcmp(g_ogl_config.gl_vendor, "Intel Open Source Technology Center") && (
483 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.0") ||
484 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.1") ||
485 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.2") ||
486 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.0.3") ||
487 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.1.0") ||
488 !strcmp(g_ogl_config.gl_version, "3.0 Mesa 9.1.1") )
489 )) {
490 g_Config.backend_info.bSupportsGLSLUBO = false;
491 ERROR_LOG(VIDEO, "Buggy driver detected. Disable UBO")do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 491, "Buggy driver detected. Disable UBO"); } } while (0)
;
492 }
493
494 UpdateActiveConfig();
495
496 OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s",
497 g_ogl_config.gl_vendor,
498 g_ogl_config.gl_renderer,
499 g_ogl_config.gl_version).c_str(), 5000);
500
501 WARN_LOG(VIDEO,"Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
502 g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
503 g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
504 g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
505 g_ActiveConfig.backend_info.bSupportsEarlyZ ? "" : "EarlyZ ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
506 g_ogl_config.bSupportsGLPinnedMemory ? "" : "PinnedMemory ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
507 g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
508 g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
509 g_ogl_config.bSupportsGLSync ? "" : "Sync ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
510 g_ogl_config.bSupportCoverageMSAA ? "" : "CSAA ",do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
511 g_ogl_config.bSupportSampleShading ? "" : "SSAA "do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
512 )do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 512, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s", g_ActiveConfig
.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend "
, g_ActiveConfig.backend_info.bSupportsGLSLUBO ? "" : "UniformBuffer "
, g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" :
"PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ
? "" : "EarlyZ ", g_ogl_config.bSupportsGLPinnedMemory ? "" :
"PinnedMemory ", g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache "
, g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", g_ogl_config
.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportCoverageMSAA
? "" : "CSAA ", g_ogl_config.bSupportSampleShading ? "" : "SSAA "
); } } while (0)
;
513
514 s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
515 s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
516 s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
517 ApplySSAASettings();
518
519 // Decide framebuffer size
520 s_backbuffer_width = (int)GLInterface->GetBackBufferWidth();
521 s_backbuffer_height = (int)GLInterface->GetBackBufferHeight();
522
523 // Handle VSync on/off
524 s_vsync = g_ActiveConfig.IsVSync();
525 GLInterface->SwapInterval(s_vsync);
526
527 // check the max texture width and height
528 GLint max_texture_size;
529 glGetIntegerv(GL_MAX_TEXTURE_SIZE0x0D33, (GLint *)&max_texture_size);
530 if (max_texture_size < 1024)
531 ERROR_LOG(VIDEO, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.",do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 532, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024."
, max_texture_size); } } while (0)
532 max_texture_size)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 532, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024."
, max_texture_size); } } while (0)
;
533
534 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
535 bSuccess = false;
Value stored to 'bSuccess' is never read
536
537 // TODO: Move these somewhere else?
538 FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
539 FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
540
541 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
542
543 s_LastEFBScale = g_ActiveConfig.iEFBScale;
544 CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
545
546 // Because of the fixed framebuffer size we need to disable the resolution
547 // options while running
548 g_Config.bRunning = true;
549
550 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
551 bSuccess = false;
552
553 glStencilFunc(GL_ALWAYS0x0207, 0, 0);
554 glBlendFunc(GL_ONE1, GL_ONE1);
555
556 glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport
557
558 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
559 glClearDepthf__glewClearDepthf(1.0f);
560 glEnable(GL_DEPTH_TEST0x0B71);
561 glDepthFunc(GL_LEQUAL0x0203);
562
563 glPixelStorei(GL_UNPACK_ALIGNMENT0x0CF5, 4); // 4-byte pixel alignment
564
565 glDisable(GL_STENCIL_TEST0x0B90);
566 glEnable(GL_SCISSOR_TEST0x0C11);
567
568 glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
569 glBlendColor__glewBlendColor(0, 0, 0, 0.5f);
570 glClearDepthf__glewClearDepthf(1.0f);
571
572#ifndef USE_GLES3
573 if(g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
574 {
575 if(g_ogl_config.bSupportOGL31)
576 {
577 glEnable(GL_PRIMITIVE_RESTART0x8F9D);
578 glPrimitiveRestartIndex__glewPrimitiveRestartIndex(65535);
579 }
580 else
581 {
582 glEnableClientState(GL_PRIMITIVE_RESTART_NV0x8558);
583 glPrimitiveRestartIndexNV__glewPrimitiveRestartIndexNV(65535);
584 }
585 }
586#endif
587 UpdateActiveConfig();
588}
589
590Renderer::~Renderer()
591{
592
593#if defined(HAVE_WX1) && HAVE_WX1
594 if (scrshotThread.joinable())
595 scrshotThread.join();
596#endif
597}
598
599void Renderer::Shutdown()
600{
601 delete g_framebuffer_manager;
602
603 g_Config.bRunning = false;
604 UpdateActiveConfig();
605
606 glDeleteBuffers__glewDeleteBuffers(1, &s_ShowEFBCopyRegions_VBO);
607 glDeleteVertexArrays__glewDeleteVertexArrays(1, &s_ShowEFBCopyRegions_VAO);
608 s_ShowEFBCopyRegions_VBO = 0;
609
610 delete s_pfont;
611 s_pfont = 0;
612 s_ShowEFBCopyRegions.Destroy();
613}
614
615void Renderer::Init()
616{
617 // Initialize the FramebufferManager
618 g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,
619 s_MSAASamples, s_MSAACoverageSamples);
620
621 s_pfont = new RasterFont();
622
623 ProgramShaderCache::CompileShader(s_ShowEFBCopyRegions,
624 "ATTRIN vec2 rawpos;\n"
625 "ATTRIN vec3 color0;\n"
626 "VARYOUT vec4 c;\n"
627 "void main(void) {\n"
628 " gl_Position = vec4(rawpos,0,1);\n"
629 " c = vec4(color0, 1.0);\n"
630 "}\n",
631 "VARYIN vec4 c;\n"
632 "COLOROUT(ocol0)\n"
633 "void main(void) {\n"
634 " ocol0 = c;\n"
635 "}\n");
636
637 // creating buffers
638 glGenBuffers__glewGenBuffers(1, &s_ShowEFBCopyRegions_VBO);
639 glGenVertexArrays__glewGenVertexArrays(1, &s_ShowEFBCopyRegions_VAO);
640 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, s_ShowEFBCopyRegions_VBO);
641 glBindVertexArray__glewBindVertexArray( s_ShowEFBCopyRegions_VAO );
642 glEnableVertexAttribArray__glewEnableVertexAttribArray(SHADER_POSITION_ATTRIB0);
643 glVertexAttribPointer__glewVertexAttribPointer(SHADER_POSITION_ATTRIB0, 2, GL_FLOAT0x1406, 0, sizeof(GLfloat)*5, NULL__null);
644 glEnableVertexAttribArray__glewEnableVertexAttribArray(SHADER_COLOR0_ATTRIB5);
645 glVertexAttribPointer__glewVertexAttribPointer(SHADER_COLOR0_ATTRIB5, 3, GL_FLOAT0x1406, 0, sizeof(GLfloat)*5, (GLfloat*)NULL__null+2);
646}
647
648// Create On-Screen-Messages
649void Renderer::DrawDebugInfo()
650{
651 // Reset viewport for drawing text
652 glViewport(0, 0, GLInterface->GetBackBufferWidth(), GLInterface->GetBackBufferHeight());
653 // Draw various messages on the screen, like FPS, statistics, etc.
654 char debugtext_buffer[8192];
655 char *p = debugtext_buffer;
656 p[0] = 0;
657
658 if (g_ActiveConfig.bShowFPS)
659 p+=sprintf(p, "FPS: %d\n", s_fps);
660
661 if (SConfig::GetInstance().m_ShowLag)
662 p+=sprintf(p, "Lag: %llu\n", Movie::g_currentLagCount);
663
664 if (g_ActiveConfig.bShowInputDisplay)
665 p+=sprintf(p, "%s", Movie::GetInputDisplay().c_str());
666
667 if (g_ActiveConfig.bShowEFBCopyRegions)
668 {
669 // Set Line Size
670 glLineWidth(3.0f);
671
672 // 2*Coords + 3*Color
673 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, s_ShowEFBCopyRegions_VBO);
674 glBufferData__glewBufferData(GL_ARRAY_BUFFER0x8892, stats.efb_regions.size() * sizeof(GLfloat) * (2+3)*2*6, NULL__null, GL_STREAM_DRAW0x88E0);
675 GLfloat *Vertices = (GLfloat*)glMapBuffer__glewMapBuffer(GL_ARRAY_BUFFER0x8892, GL_WRITE_ONLY0x88B9);
676
677 // Draw EFB copy regions rectangles
678 int a = 0;
679 GLfloat color[3] = {0.0f, 1.0f, 1.0f};
680
681 for (std::vector<EFBRectangle>::const_iterator it = stats.efb_regions.begin();
682 it != stats.efb_regions.end(); ++it)
683 {
684 GLfloat halfWidth = EFB_WIDTH / 2.0f;
685 GLfloat halfHeight = EFB_HEIGHT / 2.0f;
686 GLfloat x = (GLfloat) -1.0f + ((GLfloat)it->left / halfWidth);
687 GLfloat y = (GLfloat) 1.0f - ((GLfloat)it->top / halfHeight);
688 GLfloat x2 = (GLfloat) -1.0f + ((GLfloat)it->right / halfWidth);
689 GLfloat y2 = (GLfloat) 1.0f - ((GLfloat)it->bottom / halfHeight);
690
691 Vertices[a++] = x;
692 Vertices[a++] = y;
693 Vertices[a++] = color[0];
694 Vertices[a++] = color[1];
695 Vertices[a++] = color[2];
696
697 Vertices[a++] = x2;
698 Vertices[a++] = y;
699 Vertices[a++] = color[0];
700 Vertices[a++] = color[1];
701 Vertices[a++] = color[2];
702
703
704 Vertices[a++] = x2;
705 Vertices[a++] = y;
706 Vertices[a++] = color[0];
707 Vertices[a++] = color[1];
708 Vertices[a++] = color[2];
709
710 Vertices[a++] = x2;
711 Vertices[a++] = y2;
712 Vertices[a++] = color[0];
713 Vertices[a++] = color[1];
714 Vertices[a++] = color[2];
715
716
717 Vertices[a++] = x2;
718 Vertices[a++] = y2;
719 Vertices[a++] = color[0];
720 Vertices[a++] = color[1];
721 Vertices[a++] = color[2];
722
723 Vertices[a++] = x;
724 Vertices[a++] = y2;
725 Vertices[a++] = color[0];
726 Vertices[a++] = color[1];
727 Vertices[a++] = color[2];
728
729
730 Vertices[a++] = x;
731 Vertices[a++] = y2;
732 Vertices[a++] = color[0];
733 Vertices[a++] = color[1];
734 Vertices[a++] = color[2];
735
736 Vertices[a++] = x;
737 Vertices[a++] = y;
738 Vertices[a++] = color[0];
739 Vertices[a++] = color[1];
740 Vertices[a++] = color[2];
741
742
743 Vertices[a++] = x;
744 Vertices[a++] = y;
745 Vertices[a++] = color[0];
746 Vertices[a++] = color[1];
747 Vertices[a++] = color[2];
748
749 Vertices[a++] = x2;
750 Vertices[a++] = y2;
751 Vertices[a++] = color[0];
752 Vertices[a++] = color[1];
753 Vertices[a++] = color[2];
754
755
756 Vertices[a++] = x2;
757 Vertices[a++] = y;
758 Vertices[a++] = color[0];
759 Vertices[a++] = color[1];
760 Vertices[a++] = color[2];
761
762 Vertices[a++] = x;
763 Vertices[a++] = y2;
764 Vertices[a++] = color[0];
765 Vertices[a++] = color[1];
766 Vertices[a++] = color[2];
767
768 // TO DO: build something nicer here
769 GLfloat temp = color[0];
770 color[0] = color[1];
771 color[1] = color[2];
772 color[2] = temp;
773 }
774 glUnmapBuffer__glewUnmapBuffer(GL_ARRAY_BUFFER0x8892);
775
776 s_ShowEFBCopyRegions.Bind();
777 glBindVertexArray__glewBindVertexArray( s_ShowEFBCopyRegions_VAO );
778 glDrawArrays(GL_LINES0x0001, 0, stats.efb_regions.size() * 2*6);
779
780 // Restore Line Size
781 SetLineWidth();
782
783 // Clear stored regions
784 stats.efb_regions.clear();
785 }
786
787 if (g_ActiveConfig.bOverlayStats)
788 p = Statistics::ToString(p);
789
790 if (g_ActiveConfig.bOverlayProjStats)
791 p = Statistics::ToStringProj(p);
792
793 // Render a shadow, and then the text.
794 if (p != debugtext_buffer)
795 {
796 Renderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
797 Renderer::RenderText(debugtext_buffer, 20, 20, 0xFF00FFFF);
798 }
799}
800
801void Renderer::RenderText(const char *text, int left, int top, u32 color)
802{
803 const int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth();
804 const int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight();
805
806 s_pfont->printMultilineText(text,
807 left * 2.0f / (float)nBackbufferWidth - 1,
808 1 - top * 2.0f / (float)nBackbufferHeight,
809 0, nBackbufferWidth, nBackbufferHeight, color);
810
811 GL_REPORT_ERRORD()(void)0;
812}
813
814TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
815{
816 TargetRectangle result;
817 result.left = EFBToScaledX(rc.left);
818 result.top = EFBToScaledY(EFB_HEIGHT - rc.top);
819 result.right = EFBToScaledX(rc.right);
820 result.bottom = EFBToScaledY(EFB_HEIGHT - rc.bottom);
821 return result;
822}
823
824// Function: This function handles the OpenGL glScissor() function
825// ----------------------------
826// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
827// case 0x52 > SetScissorRect()
828// ----------------------------
829// bpmem.scissorTL.x, y = 342x342
830// bpmem.scissorBR.x, y = 981x821
831// Renderer::GetTargetHeight() = the fixed ini file setting
832// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
833// therefore the width and height are (scissorBR + 1) - scissorTL
834void Renderer::SetScissorRect(const TargetRectangle& rc)
835{
836 glScissor(rc.left, rc.bottom, rc.GetWidth(), rc.GetHeight());
837}
838
839void Renderer::SetColorMask()
840{
841 // Only enable alpha channel if it's supported by the current EFB format
842 GLenum ColorMask = GL_FALSE0, AlphaMask = GL_FALSE0;
843 if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL)
844 {
845 if (bpmem.blendmode.colorupdate)
846 ColorMask = GL_TRUE1;
847 if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241))
848 AlphaMask = GL_TRUE1;
849 }
850 glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask);
851}
852
853void ClearEFBCache()
854{
855 for (u32 i = 0; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT; ++i)
856 s_efbCacheValid[0][i] = false;
857
858 for (u32 i = 0; i < EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT; ++i)
859 s_efbCacheValid[1][i] = false;
860}
861
862void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const u32* data)
863{
864 u32 cacheType = (type == PEEK_Z ? 0 : 1);
865
866 if (!s_efbCache[cacheType][cacheRectIdx].size())
867 s_efbCache[cacheType][cacheRectIdx].resize(EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE);
868
869 u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
870 u32 efbPixelRcHeight = efbPixelRc.bottom - efbPixelRc.top;
871 u32 efbPixelRcWidth = efbPixelRc.right - efbPixelRc.left;
872
873 for (u32 yCache = 0; yCache < efbPixelRcHeight; ++yCache)
874 {
875 u32 yEFB = efbPixelRc.top + yCache;
876 u32 yPixel = (EFBToScaledY(EFB_HEIGHT - yEFB) + EFBToScaledY(EFB_HEIGHT - yEFB - 1)) / 2;
877 u32 yData = yPixel - targetPixelRc.bottom;
878
879 for (u32 xCache = 0; xCache < efbPixelRcWidth; ++xCache)
880 {
881 u32 xEFB = efbPixelRc.left + xCache;
882 u32 xPixel = (EFBToScaledX(xEFB) + EFBToScaledX(xEFB + 1)) / 2;
883 u32 xData = xPixel - targetPixelRc.left;
884 s_efbCache[cacheType][cacheRectIdx][yCache * EFB_CACHE_RECT_SIZE + xCache] = data[yData * targetPixelRcWidth + xData];
885 }
886 }
887
888 s_efbCacheValid[cacheType][cacheRectIdx] = true;
889}
890
891// This function allows the CPU to directly access the EFB.
892// There are EFB peeks (which will read the color or depth of a pixel)
893// and EFB pokes (which will change the color or depth of a pixel).
894//
895// The behavior of EFB peeks can only be modified by:
896// - GX_PokeAlphaRead
897// The behavior of EFB pokes can be modified by:
898// - GX_PokeAlphaMode (TODO)
899// - GX_PokeAlphaUpdate (TODO)
900// - GX_PokeBlendMode (TODO)
901// - GX_PokeColorUpdate (TODO)
902// - GX_PokeDither (TODO)
903// - GX_PokeDstAlpha (TODO)
904// - GX_PokeZMode (TODO)
905u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
906{
907 if (!g_ActiveConfig.bEFBAccessEnable)
908 return 0;
909
910 u32 cacheRectIdx = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_WIDTH
911 + (x / EFB_CACHE_RECT_SIZE);
912
913 // Get the rectangular target region containing the EFB pixel
914 EFBRectangle efbPixelRc;
915 efbPixelRc.left = (x / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
916 efbPixelRc.top = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE;
917 efbPixelRc.right = std::min(efbPixelRc.left + EFB_CACHE_RECT_SIZE, (u32)EFB_WIDTH);
918 efbPixelRc.bottom = std::min(efbPixelRc.top + EFB_CACHE_RECT_SIZE, (u32)EFB_HEIGHT);
919
920 TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
921 u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left;
922 u32 targetPixelRcHeight = targetPixelRc.top - targetPixelRc.bottom;
923
924 // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
925 switch (type)
926 {
927 case PEEK_Z:
928 {
929 u32 z;
930
931 if (!s_efbCacheValid[0][cacheRectIdx])
932 {
933 if (s_MSAASamples > 1)
934 {
935 // Resolve our rectangle.
936 FramebufferManager::GetEFBDepthTexture(efbPixelRc);
937 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetResolvedFramebuffer());
938 }
939
940 u32* depthMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
941
942 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
943 GL_DEPTH_COMPONENT0x1902, GL_UNSIGNED_INT0x1405, depthMap);
944 GL_REPORT_ERRORD()(void)0;
945
946 UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap);
947
948 delete[] depthMap;
949 }
950
951 u32 xRect = x % EFB_CACHE_RECT_SIZE;
952 u32 yRect = y % EFB_CACHE_RECT_SIZE;
953 z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
954
955 // Scale the 32-bit value returned by glReadPixels to a 24-bit
956 // value (GC uses a 24-bit Z-buffer).
957 // TODO: in RE0 this value is often off by one, which causes lighting to disappear
958 if(bpmem.zcontrol.pixel_format == PIXELFMT_RGB565_Z162)
959 {
960 // if Z is in 16 bit format you must return a 16 bit integer
961 z = z >> 16;
962 }
963 else
964 {
965 z = z >> 8;
966 }
967 return z;
968 }
969
970 case PEEK_COLOR: // GXPeekARGB
971 {
972 // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
973
974 // Tested in Killer 7, the first 8bits represent the alpha value which is used to
975 // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
976 // Wind Waker is also using it for the pictograph to determine the color of each pixel
977
978 u32 color;
979
980 if (!s_efbCacheValid[1][cacheRectIdx])
981 {
982 if (s_MSAASamples > 1)
983 {
984 // Resolve our rectangle.
985 FramebufferManager::GetEFBColorTexture(efbPixelRc);
986 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetResolvedFramebuffer());
987 }
988
989 u32* colorMap = new u32[targetPixelRcWidth * targetPixelRcHeight];
990
991#ifdef USE_GLES3
992 // XXX: Swap colours
993 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
994 GL_RGBA0x1908, GL_UNSIGNED_BYTE0x1401, colorMap);
995#else
996 glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight,
997 GL_BGRA0x80E1, GL_UNSIGNED_INT_8_8_8_8_REV0x8367, colorMap);
998#endif
999 GL_REPORT_ERRORD()(void)0;
1000
1001 UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap);
1002
1003 delete[] colorMap;
1004 }
1005
1006 u32 xRect = x % EFB_CACHE_RECT_SIZE;
1007 u32 yRect = y % EFB_CACHE_RECT_SIZE;
1008 color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect];
1009
1010 // check what to do with the alpha channel (GX_PokeAlphaRead)
1011 PixelEngine::UPEAlphaReadReg alpha_read_mode;
1012 PixelEngine::Read16((u16&)alpha_read_mode, PE_ALPHAREAD);
1013
1014 if (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241)
1015 {
1016 color = RGBA8ToRGBA6ToRGBA8(color);
1017 }
1018 else if (bpmem.zcontrol.pixel_format == PIXELFMT_RGB565_Z162)
1019 {
1020 color = RGBA8ToRGB565ToRGBA8(color);
1021 }
1022 if(bpmem.zcontrol.pixel_format != PIXELFMT_RGBA6_Z241)
1023 {
1024 color |= 0xFF000000;
1025 }
1026 if(alpha_read_mode.ReadMode == 2) return color; // GX_READ_NONE
1027 else if(alpha_read_mode.ReadMode == 1) return (color | 0xFF000000); // GX_READ_FF
1028 else /*if(alpha_read_mode.ReadMode == 0)*/ return (color & 0x00FFFFFF); // GX_READ_00
1029 }
1030
1031 case POKE_COLOR:
1032 case POKE_Z:
1033 // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
1034 // the exact location. Note: EFB pokes are susceptible to Z-buffering
1035 // and perhaps blending.
1036 //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
1037 break;
1038
1039 default:
1040 break;
1041 }
1042
1043 return 0;
1044}
1045
1046// Called from VertexShaderManager
1047void Renderer::UpdateViewport(Matrix44& vpCorrection)
1048{
1049 // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
1050 // [0] = width/2
1051 // [1] = height/2
1052 // [2] = 16777215 * (farz - nearz)
1053 // [3] = xorig + width/2 + 342
1054 // [4] = yorig + height/2 + 342
1055 // [5] = 16777215 * farz
1056
1057 int scissorXOff = bpmem.scissorOffset.x * 2;
1058 int scissorYOff = bpmem.scissorOffset.y * 2;
1059
1060 // TODO: ceil, floor or just cast to int?
1061 int X = EFBToScaledX((int)ceil(xfregs.viewport.xOrig - xfregs.viewport.wd - (float)scissorXOff));
1062 int Y = EFBToScaledY((int)ceil((float)EFB_HEIGHT - xfregs.viewport.yOrig + xfregs.viewport.ht + (float)scissorYOff));
1063 int Width = EFBToScaledX((int)ceil(2.0f * xfregs.viewport.wd));
1064 int Height = EFBToScaledY((int)ceil(-2.0f * xfregs.viewport.ht));
1065 double GLNear = (xfregs.viewport.farZ - xfregs.viewport.zRange) / 16777216.0f;
1066 double GLFar = xfregs.viewport.farZ / 16777216.0f;
1067 if (Width < 0)
1068 {
1069 X += Width;
1070 Width *= -1;
1071 }
1072 if (Height < 0)
1073 {
1074 Y += Height;
1075 Height *= -1;
1076 }
1077
1078 // OpenGL does not require any viewport correct
1079 Matrix44::LoadIdentity(vpCorrection);
1080
1081 // Update the view port
1082 glViewport(X, Y, Width, Height);
1083 glDepthRangef__glewDepthRangef(GLNear, GLFar);
1084}
1085
1086void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
1087{
1088 ResetAPIState();
1089
1090 // color
1091 GLboolean const
1092 color_mask = colorEnable ? GL_TRUE1 : GL_FALSE0,
1093 alpha_mask = alphaEnable ? GL_TRUE1 : GL_FALSE0;
1094 glColorMask(color_mask, color_mask, color_mask, alpha_mask);
1095
1096 glClearColor(
1097 float((color >> 16) & 0xFF) / 255.0f,
1098 float((color >> 8) & 0xFF) / 255.0f,
1099 float((color >> 0) & 0xFF) / 255.0f,
1100 float((color >> 24) & 0xFF) / 255.0f);
1101
1102 // depth
1103 glDepthMask(zEnable ? GL_TRUE1 : GL_FALSE0);
1104
1105 glClearDepthf__glewClearDepthf(float(z & 0xFFFFFF) / float(0xFFFFFF));
1106
1107 // Update rect for clearing the picture
1108 glEnable(GL_SCISSOR_TEST0x0C11);
1109
1110 TargetRectangle const targetRc = ConvertEFBRectangle(rc);
1111 glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
1112
1113 // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
1114 glClear(GL_COLOR_BUFFER_BIT0x00004000 | GL_DEPTH_BUFFER_BIT0x00000100);
1115
1116 RestoreAPIState();
1117
1118 ClearEFBCache();
1119}
1120
1121void Renderer::ReinterpretPixelData(unsigned int convtype)
1122{
1123 if (convtype == 0 || convtype == 2)
1124 {
1125 FramebufferManager::ReinterpretPixelData(convtype);
1126 }
1127 else
1128 {
1129 ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 1129, "Trying to reinterpret pixel data with unsupported conversion type %d"
, convtype); } } while (0)
;
1130 }
1131}
1132
1133void Renderer::SetBlendMode(bool forceUpdate)
1134{
1135 // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
1136 // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
1137 bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z241;
1138
1139 bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha;
1140 bool useDualSource = useDstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
1141
1142 const GLenum glSrcFactors[8] =
1143 {
1144 GL_ZERO0,
1145 GL_ONE1,
1146 GL_DST_COLOR0x0306,
1147 GL_ONE_MINUS_DST_COLOR0x0307,
1148 (useDualSource) ? GL_SRC1_ALPHA0x8589 : (GLenum)GL_SRC_ALPHA0x0302,
1149 (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA0x88FB : (GLenum)GL_ONE_MINUS_SRC_ALPHA0x0303,
1150 (target_has_alpha) ? GL_DST_ALPHA0x0304 : (GLenum)GL_ONE1,
1151 (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA0x0305 : (GLenum)GL_ZERO0
1152 };
1153 const GLenum glDestFactors[8] =
1154 {
1155 GL_ZERO0,
1156 GL_ONE1,
1157 GL_SRC_COLOR0x0300,
1158 GL_ONE_MINUS_SRC_COLOR0x0301,
1159 (useDualSource) ? GL_SRC1_ALPHA0x8589 : (GLenum)GL_SRC_ALPHA0x0302,
1160 (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA0x88FB : (GLenum)GL_ONE_MINUS_SRC_ALPHA0x0303,
1161 (target_has_alpha) ? GL_DST_ALPHA0x0304 : (GLenum)GL_ONE1,
1162 (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA0x0305 : (GLenum)GL_ZERO0
1163 };
1164
1165 // blend mode bit mask
1166 // 0 - blend enable
1167 // 1 - dst alpha enabled
1168 // 2 - reverse subtract enable (else add)
1169 // 3-5 - srcRGB function
1170 // 6-8 - dstRGB function
1171
1172 u32 newval = useDualSource << 1;
1173 newval |= bpmem.blendmode.subtract << 2;
1174
1175 if (bpmem.blendmode.subtract)
1176 newval |= 0x0049; // enable blending src 1 dst 1
1177 else if (bpmem.blendmode.blendenable)
1178 {
1179 newval |= 1; // enable blending
1180 newval |= bpmem.blendmode.srcfactor << 3;
1181 newval |= bpmem.blendmode.dstfactor << 6;
1182 }
1183
1184 u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode;
1185
1186 if (changes & 1)
1187 // blend enable change
1188 (newval & 1) ? glEnable(GL_BLEND0x0BE2) : glDisable(GL_BLEND0x0BE2);
1189
1190 if (changes & 4)
1191 {
1192 // subtract enable change
1193 GLenum equation = newval & 4 ? GL_FUNC_REVERSE_SUBTRACT0x800B : GL_FUNC_ADD0x8006;
1194 GLenum equationAlpha = useDualSource ? GL_FUNC_ADD0x8006 : equation;
1195
1196 glBlendEquationSeparate__glewBlendEquationSeparate(equation, equationAlpha);
1197 }
1198
1199 if (changes & 0x1FA)
1200 {
1201 u32 srcidx = (newval >> 3) & 7;
1202 u32 dstidx = (newval >> 6) & 7;
1203 GLenum srcFactor = glSrcFactors[srcidx];
1204 GLenum dstFactor = glDestFactors[dstidx];
1205
1206 // adjust alpha factors
1207 if (useDualSource)
1208 {
1209 srcidx = GX_BL_ONE1;
1210 dstidx = GX_BL_ZERO0;
1211 }
1212 else
1213 {
1214 // we can't use GL_DST_COLOR or GL_ONE_MINUS_DST_COLOR for source in alpha channel so use their alpha equivalent instead
1215 if (srcidx == GX_BL_DSTCLR2) srcidx = GX_BL_DSTALPHA6;
1216 if (srcidx == GX_BL_INVDSTCLR3) srcidx = GX_BL_INVDSTALPHA7;
1217
1218 // we can't use GL_SRC_COLOR or GL_ONE_MINUS_SRC_COLOR for destination in alpha channel so use their alpha equivalent instead
1219 if (dstidx == GX_BL_SRCCLR2) dstidx = GX_BL_SRCALPHA4;
1220 if (dstidx == GX_BL_INVSRCCLR3) dstidx = GX_BL_INVSRCALPHA5;
1221 }
1222 GLenum srcFactorAlpha = glSrcFactors[srcidx];
1223 GLenum dstFactorAlpha = glDestFactors[dstidx];
1224 // blend RGB change
1225 glBlendFuncSeparate__glewBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha);
1226 }
1227 s_blendMode = newval;
1228}
1229
1230void DumpFrame(const std::vector<u8>& data, int w, int h)
1231{
1232#if defined(HAVE_LIBAV) || defined(_WIN32)
1233 if (g_ActiveConfig.bDumpFrames && !data.empty())
1234 {
1235 AVIDump::AddFrame(&data[0], w, h);
1236 }
1237#endif
1238}
1239
1240// This function has the final picture. We adjust the aspect ratio here.
1241void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma)
1242{
1243 static int w = 0, h = 0;
1244 if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
1245 {
1246 DumpFrame(frame_data, w, h);
1247 Core::Callback_VideoCopiedToXFB(false);
1248 return;
1249 }
1250
1251 if (field == FIELD_LOWER) xfbAddr -= fbWidth * 2;
1252 u32 xfbCount = 0;
1253 const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
1254 if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0))
1255 {
1256 DumpFrame(frame_data, w, h);
1257 Core::Callback_VideoCopiedToXFB(false);
1258 return;
1259 }
1260
1261 ResetAPIState();
1262
1263 PostProcessing::Update(s_backbuffer_width, s_backbuffer_height);
1264 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
1265 TargetRectangle flipped_trc = GetTargetRectangle();
1266
1267 // Flip top and bottom for some reason; TODO: Fix the code to suck less?
1268 int tmp = flipped_trc.top;
1269 flipped_trc.top = flipped_trc.bottom;
1270 flipped_trc.bottom = tmp;
1271
1272 GL_REPORT_ERRORD()(void)0;
1273
1274 // Copy the framebuffer to screen.
1275
1276 const XFBSourceBase* xfbSource = NULL__null;
1277
1278 if(g_ActiveConfig.bUseXFB)
1279 {
1280 // Render to the real/postprocessing buffer now.
1281 PostProcessing::BindTargetFramebuffer();
1282
1283 // draw each xfb source
1284 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, FramebufferManager::GetXFBFramebuffer());
1285
1286 for (u32 i = 0; i < xfbCount; ++i)
1287 {
1288 xfbSource = xfbSourceList[i];
1289
1290 MathUtil::Rectangle<float> drawRc;
1291
1292 if (g_ActiveConfig.bUseRealXFB)
1293 {
1294 drawRc.top = flipped_trc.top;
1295 drawRc.bottom = flipped_trc.bottom;
1296 drawRc.left = flipped_trc.left;
1297 drawRc.right = flipped_trc.right;
1298 }
1299 else
1300 {
1301 // use virtual xfb with offset
1302 int xfbHeight = xfbSource->srcHeight;
1303 int xfbWidth = xfbSource->srcWidth;
1304 int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2);
1305
1306 drawRc.top = flipped_trc.top - hOffset * flipped_trc.GetHeight() / fbHeight;
1307 drawRc.bottom = flipped_trc.top - (hOffset + xfbHeight) * flipped_trc.GetHeight() / fbHeight;
1308 drawRc.left = flipped_trc.left + (flipped_trc.GetWidth() - xfbWidth * flipped_trc.GetWidth() / fbWidth)/2;
1309 drawRc.right = flipped_trc.left + (flipped_trc.GetWidth() + xfbWidth * flipped_trc.GetWidth() / fbWidth)/2;
1310
1311 // The following code disables auto stretch. Kept for reference.
1312 // scale draw area for a 1 to 1 pixel mapping with the draw target
1313 //float vScale = (float)fbHeight / (float)flipped_trc.GetHeight();
1314 //float hScale = (float)fbWidth / (float)flipped_trc.GetWidth();
1315 //drawRc.top *= vScale;
1316 //drawRc.bottom *= vScale;
1317 //drawRc.left *= hScale;
1318 //drawRc.right *= hScale;
1319 }
1320 // Tell the OSD Menu about the current internal resolution
1321 OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight();
1322
1323 MathUtil::Rectangle<float> sourceRc;
1324 sourceRc.left = xfbSource->sourceRc.left;
1325 sourceRc.right = xfbSource->sourceRc.right;
1326 sourceRc.top = xfbSource->sourceRc.top;
1327 sourceRc.bottom = xfbSource->sourceRc.bottom;
1328
1329 xfbSource->Draw(sourceRc, drawRc, 0, 0);
1330 }
1331 }
1332 else
1333 {
1334 TargetRectangle targetRc = ConvertEFBRectangle(rc);
1335
1336 // for msaa mode, we must resolve the efb content to non-msaa
1337 FramebufferManager::ResolveAndGetRenderTarget(rc);
1338
1339 // Render to the real/postprocessing buffer now. (resolve have changed this in msaa mode)
1340 PostProcessing::BindTargetFramebuffer();
1341
1342 // always the non-msaa fbo
1343 GLuint fb = s_MSAASamples>1?FramebufferManager::GetResolvedFramebuffer():FramebufferManager::GetEFBFramebuffer();
1344
1345 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, fb);
1346 glBlitFramebuffer__glewBlitFramebuffer(targetRc.left, targetRc.bottom, targetRc.right, targetRc.top,
1347 flipped_trc.left, flipped_trc.bottom, flipped_trc.right, flipped_trc.top,
1348 GL_COLOR_BUFFER_BIT0x00004000, GL_LINEAR0x2601);
1349 }
1350
1351 PostProcessing::BlitToScreen();
1352
1353 glBindFramebuffer__glewBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, 0);
1354
1355 // Save screenshot
1356 if (s_bScreenshot)
1357 {
1358 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1359 SaveScreenshot(s_sScreenshotName, flipped_trc);
1360 // Reset settings
1361 s_sScreenshotName.clear();
1362 s_bScreenshot = false;
1363 }
1364
1365 // Frame dumps are handled a little differently in Windows
1366 // Frame dumping disabled entirely on GLES3
1367#ifndef USE_GLES3
1368#if defined _WIN32 || defined HAVE_LIBAV
1369 if (g_ActiveConfig.bDumpFrames)
1370 {
1371 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1372 if (frame_data.empty() || w != flipped_trc.GetWidth() ||
1373 h != flipped_trc.GetHeight())
1374 {
1375 w = flipped_trc.GetWidth();
1376 h = flipped_trc.GetHeight();
1377 frame_data.resize(3 * w * h);
1378 }
1379 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1380 glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_BGR0x80E0, GL_UNSIGNED_BYTE0x1401, &frame_data[0]);
1381 if (GL_REPORT_ERROR() == GL_NO_ERROR0 && w > 0 && h > 0)
1382 {
1383 if (!bLastFrameDumped)
1384 {
1385 #ifdef _WIN32
1386 bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h);
1387 #else
1388 bAVIDumping = AVIDump::Start(w, h);
1389 #endif
1390 if (!bAVIDumping)
1391 OSD::AddMessage("AVIDump Start failed", 2000);
1392 else
1393 {
1394 OSD::AddMessage(StringFromFormat(
1395 "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)",
1396 File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h).c_str(), 2000);
1397 }
1398 }
1399 if (bAVIDumping)
1400 {
1401 #ifndef _WIN32
1402 FlipImageData(&frame_data[0], w, h);
1403 #endif
1404
1405 AVIDump::AddFrame(&frame_data[0], w, h);
1406 }
1407
1408 bLastFrameDumped = true;
1409 }
1410 else
1411 NOTICE_LOG(VIDEO, "Error reading framebuffer")do { { if (LogTypes::LNOTICE <= 3) GenericLog(LogTypes::LNOTICE
, LogTypes::VIDEO, "/home/anal/dolphin-emu/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp"
, 1411, "Error reading framebuffer"); } } while (0)
;
1412 }
1413 else
1414 {
1415 if (bLastFrameDumped && bAVIDumping)
1416 {
1417 std::vector<u8>().swap(frame_data);
1418 w = h = 0;
1419 AVIDump::Stop();
1420 bAVIDumping = false;
1421 OSD::AddMessage("Stop dumping frames", 2000);
1422 }
1423 bLastFrameDumped = false;
1424 }
1425#else
1426 if (g_ActiveConfig.bDumpFrames)
1427 {
1428 std::lock_guard<std::mutex> lk(s_criticalScreenshot);
1429 std::string movie_file_name;
1430 w = GetTargetRectangle().GetWidth();
1431 h = GetTargetRectangle().GetHeight();
1432 frame_data.resize(3 * w * h);
1433 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1434 glReadPixels(GetTargetRectangle().left, GetTargetRectangle().bottom, w, h, GL_BGR0x80E0, GL_UNSIGNED_BYTE0x1401, &frame_data[0]);
1435 if (GL_REPORT_ERROR() == GL_NO_ERROR0)
1436 {
1437 if (!bLastFrameDumped)
1438 {
1439 movie_file_name = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump.raw";
1440 pFrameDump.Open(movie_file_name, "wb");
1441 if (!pFrameDump)
1442 OSD::AddMessage("Error opening framedump.raw for writing.", 2000);
1443 else
1444 {
1445 OSD::AddMessage(StringFromFormat("Dumping Frames to \"%s\" (%dx%d RGB24)", movie_file_name.c_str(), w, h).c_str(), 2000);
1446 }
1447 }
1448 if (pFrameDump)
1449 {
1450 FlipImageData(&frame_data[0], w, h);
1451 pFrameDump.WriteBytes(&frame_data[0], w * 3 * h);
1452 pFrameDump.Flush();
1453 }
1454 bLastFrameDumped = true;
1455 }
1456 }
1457 else
1458 {
1459 if (bLastFrameDumped)
1460 pFrameDump.Close();
1461 bLastFrameDumped = false;
1462 }
1463#endif
1464#endif
1465 // Finish up the current frame, print some stats
1466
1467 SetWindowSize(fbWidth, fbHeight);
1468
1469 GLInterface->Update(); // just updates the render window position and the backbuffer size
1470
1471 bool xfbchanged = false;
1472
1473 if (FramebufferManagerBase::LastXfbWidth() != fbWidth || FramebufferManagerBase::LastXfbHeight() != fbHeight)
1474 {
1475 xfbchanged = true;
1476 unsigned int const last_w = (fbWidth < 1 || fbWidth > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbWidth;
1477 unsigned int const last_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight;
1478 FramebufferManagerBase::SetLastXfbWidth(last_w);
1479 FramebufferManagerBase::SetLastXfbHeight(last_h);
1480 }
1481
1482 bool WindowResized = false;
1483 int W = (int)GLInterface->GetBackBufferWidth();
1484 int H = (int)GLInterface->GetBackBufferHeight();
1485 if (W != s_backbuffer_width || H != s_backbuffer_height || s_LastEFBScale != g_ActiveConfig.iEFBScale)
1486 {
1487 WindowResized = true;
1488 s_backbuffer_width = W;
1489 s_backbuffer_height = H;
1490 s_LastEFBScale = g_ActiveConfig.iEFBScale;
1491 }
1492
1493 if (xfbchanged || WindowResized || (s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode))
1494 {
1495 UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
1496
1497 if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode)
1498 {
1499 s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
1500 s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
1501 s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
1502 ApplySSAASettings();
1503
1504 delete g_framebuffer_manager;
1505 g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,
1506 s_MSAASamples, s_MSAACoverageSamples);
1507 }
1508 }
1509
1510 if (XFBWrited)
1511 s_fps = UpdateFPSCounter();
1512 // ---------------------------------------------------------------------
1513 GL_REPORT_ERRORD()(void)0;
1514
1515 glEnable(GL_BLEND0x0BE2);
1516 glBlendFunc(GL_SRC_ALPHA0x0302, GL_ONE_MINUS_SRC_ALPHA0x0303);
1517
1518 DrawDebugInfo();
1519 DrawDebugText();
1520
1521 GL_REPORT_ERRORD()(void)0;
1522
1523 // Do our OSD callbacks
1524 OSD::DoCallbacks(OSD::OSD_ONFRAME);
1525 OSD::DrawMessages();
1526 GL_REPORT_ERRORD()(void)0;
1527
1528 // Copy the rendered frame to the real window
1529 GLInterface->Swap();
1530
1531 GL_REPORT_ERRORD()(void)0;
1532
1533 // Clear framebuffer
1534 if(!g_ActiveConfig.bAnaglyphStereo)
1535 {
1536 glClearColor(0, 0, 0, 0);
1537 glClear(GL_COLOR_BUFFER_BIT0x00004000);
1538 }
1539
1540 GL_REPORT_ERRORD()(void)0;
1541
1542 if(s_vsync != g_ActiveConfig.IsVSync())
1543 {
1544 s_vsync = g_ActiveConfig.IsVSync();
1545 GLInterface->SwapInterval(s_vsync);
1546 }
1547
1548 // Clean out old stuff from caches. It's not worth it to clean out the shader caches.
1549 DLCache::ProgressiveCleanup();
1550 TextureCache::Cleanup();
1551
1552 frameCount++;
1553
1554 GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true){if (((GFXDebuggerToPauseAtNext & NEXT_FRAME) && --
GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) GFXDebuggerToPause
(true);}
;
1555
1556 // Begin new frame
1557 // Set default viewport and scissor, for the clear to work correctly
1558 // New frame
1559 stats.ResetFrame();
1560
1561 // Render to the framebuffer.
1562 FramebufferManager::SetFramebuffer(0);
1563
1564 GL_REPORT_ERRORD()(void)0;
1565
1566 RestoreAPIState();
1567
1568 GL_REPORT_ERRORD()(void)0;
1569 g_Config.iSaveTargetId = 0;
1570
1571 UpdateActiveConfig();
1572 TextureCache::OnConfigChanged(g_ActiveConfig);
1573
1574 // For testing zbuffer targets.
1575 // Renderer::SetZBufferRender();
1576 // SaveTexture("tex.tga", GL_TEXTURE_2D, s_FakeZTarget,
1577 // GetTargetWidth(), GetTargetHeight());
1578 Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB));
1579 XFBWrited = false;
1580
1581 // Invalidate EFB cache
1582 ClearEFBCache();
1583}
1584
1585// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
1586void Renderer::ResetAPIState()
1587{
1588 // Gets us to a reasonably sane state where it's possible to do things like
1589 // image copies with textured quads, etc.
1590 glDisable(GL_SCISSOR_TEST0x0C11);
1591 glDisable(GL_DEPTH_TEST0x0B71);
1592 glDisable(GL_CULL_FACE0x0B44);
1593 glDisable(GL_BLEND0x0BE2);
1594 glDepthMask(GL_FALSE0);
1595 glColorMask(GL_TRUE1, GL_TRUE1, GL_TRUE1, GL_TRUE1);
1596}
1597
1598void Renderer::RestoreAPIState()
1599{
1600 // Gets us back into a more game-like state.
1601 glEnable(GL_SCISSOR_TEST0x0C11);
1602 SetGenerationMode();
1603 BPFunctions::SetScissor();
1604 SetColorMask();
1605 SetDepthMode();
1606 SetBlendMode(true);
1607 VertexShaderManager::SetViewportChanged();
1608
1609#ifndef USE_GLES3
1610 glPolygonMode(GL_FRONT_AND_BACK0x0408, g_ActiveConfig.bWireFrame ? GL_LINE0x1B01 : GL_FILL0x1B02);
1611#endif
1612
1613 VertexManager *vm = (OGL::VertexManager*)g_vertex_manager;
1614 glBindBuffer__glewBindBuffer(GL_ARRAY_BUFFER0x8892, vm->m_vertex_buffers);
1615 vm->m_last_vao = 0;
1616
1617 TextureCache::SetStage();
1618}
1619
1620void Renderer::SetGenerationMode()
1621{
1622 // none, ccw, cw, ccw
1623 if (bpmem.genMode.cullmode > 0)
1624 {
1625 glEnable(GL_CULL_FACE0x0B44);
1626 glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW0x0901 : GL_CW0x0900);
1627 }
1628 else
1629 glDisable(GL_CULL_FACE0x0B44);
1630}
1631
1632void Renderer::SetDepthMode()
1633{
1634 const GLenum glCmpFuncs[8] =
1635 {
1636 GL_NEVER0x0200,
1637 GL_LESS0x0201,
1638 GL_EQUAL0x0202,
1639 GL_LEQUAL0x0203,
1640 GL_GREATER0x0204,
1641 GL_NOTEQUAL0x0205,
1642 GL_GEQUAL0x0206,
1643 GL_ALWAYS0x0207
1644 };
1645
1646 if (bpmem.zmode.testenable)
1647 {
1648 glEnable(GL_DEPTH_TEST0x0B71);
1649 glDepthMask(bpmem.zmode.updateenable ? GL_TRUE1 : GL_FALSE0);
1650 glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
1651 }
1652 else
1653 {
1654 // if the test is disabled write is disabled too
1655 // TODO: When PE performance metrics are being emulated via occlusion queries, we should (probably?) enable depth test with depth function ALWAYS here
1656 glDisable(GL_DEPTH_TEST0x0B71);
1657 glDepthMask(GL_FALSE0);
1658 }
1659}
1660
1661void Renderer::SetLogicOpMode()
1662{
1663
1664 // Logic ops aren't available in GLES3/GLES2
1665#ifndef USE_GLES3
1666 const GLenum glLogicOpCodes[16] =
1667 {
1668 GL_CLEAR0x1500,
1669 GL_AND0x1501,
1670 GL_AND_REVERSE0x1502,
1671 GL_COPY0x1503,
1672 GL_AND_INVERTED0x1504,
1673 GL_NOOP0x1505,
1674 GL_XOR0x1506,
1675 GL_OR0x1507,
1676 GL_NOR0x1508,
1677 GL_EQUIV0x1509,
1678 GL_INVERT0x150A,
1679 GL_OR_REVERSE0x150B,
1680 GL_COPY_INVERTED0x150C,
1681 GL_OR_INVERTED0x150D,
1682 GL_NAND0x150E,
1683 GL_SET0x150F
1684 };
1685
1686 if (bpmem.blendmode.logicopenable)
1687 {
1688 glEnable(GL_COLOR_LOGIC_OP0x0BF2);
1689 glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
1690 }
1691 else
1692 {
1693 glDisable(GL_COLOR_LOGIC_OP0x0BF2);
1694 }
1695#endif
1696}
1697
1698void Renderer::SetDitherMode()
1699{
1700 if (bpmem.blendmode.dither)
1701 glEnable(GL_DITHER0x0BD0);
1702 else
1703 glDisable(GL_DITHER0x0BD0);
1704}
1705
1706void Renderer::SetLineWidth()
1707{
1708 float fratio = xfregs.viewport.wd != 0 ?
1709 ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f;
1710 if (bpmem.lineptwidth.linesize > 0)
1711 // scale by ratio of widths
1712 glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f);
1713#ifndef USE_GLES3
1714 if (bpmem.lineptwidth.pointsize > 0)
1715 glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
1716#endif
1717}
1718
1719void Renderer::SetSamplerState(int stage, int texindex)
1720{
1721 auto const& tex = bpmem.tex[texindex];
1722 auto const& tm0 = tex.texMode0[stage];
1723 auto const& tm1 = tex.texMode1[stage];
1724
1725 g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1);
1726}
1727
1728void Renderer::SetInterlacingMode()
1729{
1730 // TODO
1731}
1732
1733void Renderer::FlipImageData(u8 *data, int w, int h)
1734{
1735 // Flip image upside down. Damn OpenGL.
1736 for (int y = 0; y < h / 2; y++)
1737 {
1738 for(int x = 0; x < w; x++)
1739 {
1740 std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]);
1741 std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]);
1742 std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]);
1743 }
1744 }
1745}
1746
1747}
1748
1749// TODO: remove
1750extern bool g_aspect_wide;
1751
1752#if defined(HAVE_WX1) && HAVE_WX1
1753void TakeScreenshot(ScrStrct* threadStruct)
1754{
1755 // These will contain the final image size
1756 float FloatW = (float)threadStruct->W;
1757 float FloatH = (float)threadStruct->H;
1758
1759 // Handle aspect ratio for the final ScrStrct to look exactly like what's on screen.
1760 if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
1761 {
1762 bool use16_9 = g_aspect_wide;
1763
1764 // Check for force-settings and override.
1765 if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9)
1766 use16_9 = true;
1767 else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3)
1768 use16_9 = false;
1769
1770 float Ratio = (FloatW / FloatH) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f));
1771
1772 // If ratio > 1 the picture is too wide and we have to limit the width.
1773 if (Ratio > 1)
1774 FloatW /= Ratio;
1775 // ratio == 1 or the image is too high, we have to limit the height.
1776 else
1777 FloatH *= Ratio;
1778
1779 // This is a bit expensive on high resolutions
1780 threadStruct->img->Rescale((int)FloatW, (int)FloatH, wxIMAGE_QUALITY_HIGH);
1781 }
1782
1783 // Save the screenshot and finally kill the wxImage object
1784 // This is really expensive when saving to PNG, but not at all when using BMP
1785 threadStruct->img->SaveFile(StrToWxStr(threadStruct->filename),
1786 wxBITMAP_TYPE_PNG);
1787 threadStruct->img->Destroy();
1788
1789 // Show success messages
1790 OSD::AddMessage(StringFromFormat("Saved %i x %i %s", (int)FloatW, (int)FloatH,
1791 threadStruct->filename.c_str()).c_str(), 2000);
1792 delete threadStruct;
1793}
1794#endif
1795
1796namespace OGL
1797{
1798
1799bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle &back_rc)
1800{
1801 u32 W = back_rc.GetWidth();
1802 u32 H = back_rc.GetHeight();
1803 u8 *data = (u8 *)malloc((sizeof(u8) * 3 * W * H));
1804 glPixelStorei(GL_PACK_ALIGNMENT0x0D05, 1);
1805
1806 glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGB0x1907, GL_UNSIGNED_BYTE0x1401, data);
1807
1808 // Show failure message
1809 if (GL_REPORT_ERROR() != GL_NO_ERROR0)
1810 {
1811 free(data);
1812 OSD::AddMessage("Error capturing or saving screenshot.", 2000);
1813 return false;
1814 }
1815
1816 // Turn image upside down
1817 FlipImageData(data, W, H);
1818
1819#if defined(HAVE_WX1) && HAVE_WX1
1820 // Create wxImage
1821 wxImage *a = new wxImage(W, H, data);
1822
1823 if (scrshotThread.joinable())
1824 scrshotThread.join();
1825
1826 ScrStrct *threadStruct = new ScrStrct;
1827 threadStruct->filename = filename;
1828 threadStruct->img = a;
1829 threadStruct->H = H; threadStruct->W = W;
1830
1831 scrshotThread = std::thread(TakeScreenshot, threadStruct);
1832#ifdef _WIN32
1833 SetThreadPriority(scrshotThread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL);
1834#endif
1835 bool result = true;
1836
1837 OSD::AddMessage("Saving Screenshot... ", 2000);
1838
1839#else
1840 bool result = SaveTGA(filename.c_str(), W, H, data);
1841 free(data);
1842#endif
1843
1844 return result;
1845}
1846
1847}