Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/RSDKv5/RSDK/Graphics/EGL/EGLRenderDevice.cpp
1163 views
1
#ifdef _INTELLISENSE
2
#ifdef _INTELLISENSE_NX
3
#undef __unix__
4
#undef __linux__
5
#endif
6
#include <glad/glad.h>
7
#include "EGLRenderDevice.hpp"
8
//#include "RetroEngine.hpp"
9
#endif
10
11
#include <chrono>
12
13
#if RETRO_PLATFORM == RETRO_SWITCH
14
#define _GLVERSION "#version 330 core\n#define in_V in\n#define in_F in\n"
15
16
#define _glVPrecision ""
17
#define _glFPrecision ""
18
19
#define _YOFF 16
20
#define _UOFF 8
21
#define _VOFF 0
22
#elif RETRO_PLATFORM == RETRO_ANDROID
23
#define _GLVERSION \
24
"#version 100\n#extension GL_OES_standard_derivatives : enable\n#define in_V attribute\n#define out varying\n#define in_F varying\n"
25
26
#define GL_BGRA GL_RGBA
27
#define GL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_BYTE
28
29
char _glVPrecision[30]; // len("precision mediump float;\n") -> 25
30
char _glFPrecision[30]; // len("precision mediump float;\n") -> 25
31
32
#define _YOFF 0
33
#define _UOFF 8
34
#define _VOFF 16
35
#endif
36
37
#if RETRO_REV02
38
#define _GLDEFINE "#define RETRO_REV02 (1)\n"
39
#else
40
#define _GLDEFINE "\n"
41
#endif
42
43
const GLchar *backupVertex = R"aa(
44
in_V vec3 in_pos;
45
in_V vec2 in_UV;
46
out vec4 ex_color;
47
out vec2 ex_UV;
48
49
void main()
50
{
51
gl_Position = vec4(in_pos, 1.0);
52
ex_color = vec4(1.0, 1.0, 1.0, 1.0);
53
ex_UV = in_UV;
54
}
55
)aa";
56
57
const GLchar *backupFragment = R"aa(
58
in_F vec2 ex_UV;
59
in_F vec4 ex_color;
60
61
uniform sampler2D texDiffuse;
62
63
void main()
64
{
65
gl_FragColor = texture2D(texDiffuse, ex_UV);
66
}
67
)aa";
68
69
EGLDisplay RenderDevice::display;
70
EGLContext RenderDevice::context;
71
EGLSurface RenderDevice::surface;
72
EGLConfig RenderDevice::config;
73
74
#if RETRO_PLATFORM == RETRO_SWITCH
75
NWindow *RenderDevice::window;
76
#elif RETRO_PLATFORM == RETRO_ANDROID
77
ANativeWindow *RenderDevice::window;
78
#endif
79
80
GLuint RenderDevice::VAO;
81
GLuint RenderDevice::VBO;
82
83
GLuint RenderDevice::screenTextures[SCREEN_COUNT];
84
GLuint RenderDevice::imageTexture;
85
86
#if RETRO_PLATFORM == RETRO_ANDROID
87
#include <ratio>
88
#include <chrono>
89
std::chrono::steady_clock::time_point lastFrame;
90
// Lock at 60 fps on Android because refresh rate is all over the place
91
using FramePeriod = std::chrono::duration<double, std::ratio<1, 60>>;
92
FramePeriod targetFreq;
93
#endif
94
95
int32 RenderDevice::monitorIndex;
96
97
uint32 *RenderDevice::videoBuffer;
98
99
bool32 RenderDevice::isInitialized = false;
100
101
bool RenderDevice::Init()
102
{
103
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
104
if (!display) {
105
PrintLog(PRINT_NORMAL, "[EGL] Could not connect to display: %d", eglGetError());
106
return false;
107
}
108
109
eglInitialize(display, nullptr, nullptr);
110
111
#if RETRO_PLATFORM == RETRO_SWITCH
112
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
113
PrintLog(PRINT_NORMAL, "[EGL] eglBindApi failure: %d", eglGetError());
114
return false;
115
}
116
#elif RETRO_PLATFORM == RETRO_ANDROID
117
#endif
118
119
EGLint numConfigs;
120
// clang-format off
121
static const EGLint framebufferAttributeList[] = {
122
#if RETRO_PLATFORM == RETRO_SWITCH
123
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
124
#else
125
EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
126
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
127
#endif
128
EGL_RED_SIZE, 8,
129
EGL_GREEN_SIZE, 8,
130
EGL_BLUE_SIZE, 8,
131
EGL_NONE
132
};
133
// clang-format on
134
eglChooseConfig(display, framebufferAttributeList, &config, 1, &numConfigs);
135
if (numConfigs == 0) {
136
PrintLog(PRINT_NORMAL, "[EGL] No configs found: %d", eglGetError());
137
return false;
138
}
139
140
if (!SetupRendering())
141
return false;
142
if (!isRunning) {
143
if (!AudioDevice::Init())
144
return false;
145
InitInputDevices();
146
}
147
isInitialized = true;
148
return true;
149
}
150
151
bool RenderDevice::SetupRendering()
152
{
153
#if RETRO_PLATFORM == RETRO_SWITCH
154
window = nwindowGetDefault();
155
nwindowSetDimensions(window, 1920, 1080);
156
#elif RETRO_PLATFORM == RETRO_ANDROID
157
EGLint format;
158
if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
159
PrintLog(PRINT_NORMAL, "[EGL] EGL_NATIVE_VISUAL_ID fetch failed: %d", eglGetError());
160
return false;
161
}
162
if (!window) {
163
#if RETRO_REV02
164
if (SKU::userCore)
165
SKU::userCore->focusState = 1;
166
#else
167
engine.focusState = 1;
168
#endif
169
return true; // lie so we can properly swtup later
170
}
171
ANativeWindow_setBuffersGeometry(window, 0, 0, format);
172
SwappyGL_setAutoSwapInterval(false);
173
SwappyGL_setSwapIntervalNS(SWAPPY_SWAP_60FPS);
174
SwappyGL_setMaxAutoSwapIntervalNS(SWAPPY_SWAP_60FPS);
175
#endif
176
177
surface = eglCreateWindowSurface(display, config, window, nullptr);
178
if (!surface) {
179
PrintLog(PRINT_NORMAL, "[EGL] Surface creation failed: %d", eglGetError());
180
return false;
181
}
182
183
#if RETRO_PLATFORM == RETRO_SWITCH
184
// clang-format off
185
static const int32 listCount = 1;
186
static const EGLint attributeListList[listCount][7] = { {
187
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
188
EGL_CONTEXT_MAJOR_VERSION, 4,
189
EGL_CONTEXT_MINOR_VERSION, 3,
190
EGL_NONE
191
} };
192
int32 i = 0;
193
// clang-format on
194
#elif RETRO_PLATFORM == RETRO_ANDROID
195
static const int32 listCount = 1;
196
static const EGLint attributeListList[listCount][3] = { { EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE } }; // lol. lmao
197
int32 i = 0;
198
#endif
199
200
context = eglCreateContext(display, config, EGL_NO_CONTEXT, (EGLint *)attributeListList[i]);
201
while (!context) {
202
PrintLog(PRINT_NORMAL, "[EGL] Context creation failed: %d", eglGetError());
203
if (++i < listCount) {
204
PrintLog(PRINT_NORMAL, "[EGL] Trying next context...");
205
context = eglCreateContext(display, config, EGL_NO_CONTEXT, (EGLint *)attributeListList[i]);
206
}
207
else
208
return false;
209
}
210
211
eglMakeCurrent(display, surface, surface, context);
212
eglQueryContext(display, context, EGL_CONTEXT_CLIENT_VERSION, &i);
213
PrintLog(PRINT_NORMAL, "[EGL] Context client version: %d", i);
214
215
GetDisplays();
216
217
if (!InitGraphicsAPI() || !InitShaders())
218
return false;
219
220
int32 size = videoSettings.pixWidth >= SCREEN_YSIZE ? videoSettings.pixWidth : SCREEN_YSIZE;
221
if (scanlines)
222
free(scanlines);
223
scanlines = (ScanlineInfo *)malloc(size * sizeof(ScanlineInfo));
224
memset(scanlines, 0, size * sizeof(ScanlineInfo));
225
226
videoSettings.windowState = WINDOWSTATE_ACTIVE;
227
videoSettings.dimMax = 1.0;
228
videoSettings.dimPercent = 1.0;
229
230
return true;
231
}
232
233
void RenderDevice::GetDisplays()
234
{
235
236
displayCount = 1;
237
GetWindowSize(&displayWidth[0], &displayHeight[0]);
238
// reacting to me lying
239
displayInfo.displays = (decltype(displayInfo.displays))malloc(sizeof(displayInfo.displays->internal));
240
displayInfo.displays[0].width = displayWidth[0];
241
displayInfo.displays[0].height = displayHeight[0];
242
displayInfo.displays[0].refresh_rate = videoSettings.refreshRate;
243
}
244
245
bool RenderDevice::InitGraphicsAPI()
246
{
247
#if RETRO_PLATFORM == RETRO_SWITCH
248
if (!gladLoadGL()) {
249
PrintLog(PRINT_NORMAL, "[EGL] gladLoadGL failure");
250
return false;
251
}
252
#else
253
GLint range[2], precision;
254
255
glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_FLOAT, range, &precision);
256
if (!precision)
257
strcpy(_glVPrecision, "precision mediump float;\n");
258
else
259
strcpy(_glVPrecision, "precision highp float;\n");
260
261
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);
262
if (!precision)
263
strcpy(_glFPrecision, "precision mediump float;\n");
264
else
265
strcpy(_glFPrecision, "precision highp float;\n");
266
267
#endif
268
glClearColor(0.0, 0.0, 0.0, 1.0);
269
glDisable(GL_DEPTH_TEST);
270
glDisable(GL_DITHER);
271
glDisable(GL_BLEND);
272
glDisable(GL_SCISSOR_TEST);
273
glDisable(GL_CULL_FACE);
274
275
// setup buffers
276
#if RETRO_PLATFORM == RETRO_SWITCH
277
glGenVertexArrays(1, &VAO);
278
glBindVertexArray(VAO);
279
#endif
280
281
glGenBuffers(1, &VBO);
282
glBindBuffer(GL_ARRAY_BUFFER, VBO);
283
glBufferData(GL_ARRAY_BUFFER, sizeof(RenderVertex) * (!RETRO_REV02 ? 24 : 60), NULL, GL_DYNAMIC_DRAW);
284
285
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(RenderVertex), 0);
286
glEnableVertexAttribArray(0);
287
// glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(RenderVertex), (void *)offsetof(RenderVertex, color));
288
// glEnableVertexAttribArray(1);
289
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(RenderVertex), (void *)offsetof(RenderVertex, tex));
290
glEnableVertexAttribArray(1);
291
292
#if RETRO_PLATFORM == RETRO_SWITCH
293
videoSettings.fsWidth = 1920;
294
videoSettings.fsHeight = 1080;
295
#elif RETRO_PLATFORM == RETRO_ANDROID
296
customSettings.maxPixWidth = 0;
297
videoSettings.fsWidth = 0;
298
videoSettings.fsHeight = 0;
299
#endif
300
301
// EGL should only be fullscreen only apps
302
#if false
303
if (videoSettings.windowed || !videoSettings.exclusiveFS) {
304
if (videoSettings.windowed) {
305
viewSize.x = videoSettings.windowWidth;
306
viewSize.y = videoSettings.windowHeight;
307
}
308
else {
309
viewSize.x = displayWidth[monitorIndex];
310
viewSize.y = displayHeight[monitorIndex];
311
}
312
}
313
else
314
#endif
315
{
316
int32 bufferWidth = videoSettings.fsWidth;
317
int32 bufferHeight = videoSettings.fsHeight;
318
if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {
319
bufferWidth = displayWidth[monitorIndex];
320
bufferHeight = displayHeight[monitorIndex];
321
}
322
viewSize.x = bufferWidth;
323
viewSize.y = bufferHeight;
324
}
325
326
int32 maxPixHeight = 0;
327
#if !RETRO_USE_ORIGINAL_CODE
328
int32 screenWidth = 0;
329
#endif
330
for (int32 s = 0; s < SCREEN_COUNT; ++s) {
331
if (videoSettings.pixHeight > maxPixHeight)
332
maxPixHeight = videoSettings.pixHeight;
333
334
screens[s].size.y = videoSettings.pixHeight;
335
336
float viewAspect = viewSize.x / viewSize.y;
337
#if !RETRO_USE_ORIGINAL_CODE
338
screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;
339
#else
340
int32 screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;
341
#endif
342
if (screenWidth < videoSettings.pixWidth)
343
screenWidth = videoSettings.pixWidth;
344
345
#if !RETRO_USE_ORIGINAL_CODE
346
if (customSettings.maxPixWidth && screenWidth > customSettings.maxPixWidth)
347
screenWidth = customSettings.maxPixWidth;
348
#else
349
if (screenWidth > DEFAULT_PIXWIDTH)
350
screenWidth = DEFAULT_PIXWIDTH;
351
#endif
352
353
memset(&screens[s].frameBuffer, 0, sizeof(screens[s].frameBuffer));
354
SetScreenSize(s, screenWidth, screens[s].size.y);
355
}
356
357
pixelSize.x = screens[0].size.x;
358
pixelSize.y = screens[0].size.y;
359
float pixAspect = pixelSize.x / pixelSize.y;
360
361
#if RETRO_PLATFORM == RETRO_ANDROID
362
auto* jni = GetJNISetup();
363
jni->env->CallVoidMethod(jni->thiz, setPixSize, (int)pixelSize.x, (int)pixelSize.y);
364
#endif
365
366
Vector2 viewportPos{};
367
Vector2 viewportSize{ displayWidth[0], displayHeight[0] };
368
369
if ((viewSize.x / viewSize.y) <= (pixAspect + 0.1)) {
370
if ((pixAspect - 0.1) > (viewSize.x / viewSize.y)) {
371
viewSize.y = (pixelSize.y / pixelSize.x) * viewSize.x;
372
viewportPos.y = (displayHeight[0] >> 1) - (viewSize.y * 0.5);
373
viewportSize.y = viewSize.y;
374
}
375
}
376
else {
377
viewSize.x = pixAspect * viewSize.y;
378
viewportPos.x = (displayWidth[0] >> 1) - ((pixAspect * viewSize.y) * 0.5);
379
viewportSize.x = (pixAspect * viewSize.y);
380
}
381
382
#if !RETRO_USE_ORIGINAL_CODE
383
if (screenWidth <= 512 && maxPixHeight <= 256) {
384
#else
385
if (maxPixHeight <= 256) {
386
#endif
387
textureSize.x = 512.0;
388
textureSize.y = 256.0;
389
}
390
else {
391
textureSize.x = 1024.0;
392
textureSize.y = 512.0;
393
}
394
395
glViewport(viewportPos.x, viewportPos.y, viewportSize.x, viewportSize.y);
396
397
glActiveTexture(GL_TEXTURE0);
398
glGenTextures(SCREEN_COUNT, screenTextures);
399
400
for (int32 i = 0; i < SCREEN_COUNT; ++i) {
401
glBindTexture(GL_TEXTURE_2D, screenTextures[i]);
402
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureSize.x, textureSize.y, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
403
404
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
405
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
406
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
407
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
408
}
409
glGenTextures(1, &imageTexture);
410
glBindTexture(GL_TEXTURE_2D, imageTexture);
411
#if RETRO_PLATFORM == RETRO_SWITCH
412
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
413
#else
414
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
415
#endif
416
417
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
418
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
419
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
420
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
421
422
if (videoBuffer)
423
delete[] videoBuffer;
424
videoBuffer = new uint32[RETRO_VIDEO_TEXTURE_W * RETRO_VIDEO_TEXTURE_H];
425
426
lastShaderID = -1;
427
InitVertexBuffer();
428
engine.inFocus = 1;
429
videoSettings.viewportX = viewportPos.x;
430
videoSettings.viewportY = viewportPos.y;
431
videoSettings.viewportW = 1.0 / viewSize.x;
432
videoSettings.viewportH = 1.0 / viewSize.y;
433
434
// PrintLog(PRINT_NORMAL, "%d %d %f %f %d %d %d %d %f %f", displayWidth[0], displayHeight[0], pixelSize.x, pixelSize.y, viewportPos.x,
435
// viewportPos.y,
436
// viewportSize.x, viewportSize.y, viewSize.x, viewSize.y);
437
438
return true;
439
}
440
441
// CUSTOM BUFFER FOR SHENANIGAN PURPOSES
442
// GL hates us and it's coordinate system is reverse of DX
443
// for shader output equivalency, we havee to flip everything
444
// X and Y are negated, some verts are specifically moved to match
445
// U and V are 0/1s and flipped from what it was originally
446
// clang-format off
447
#if RETRO_REV02
448
const RenderVertex rsdkGLVertexBuffer[60] = {
449
// 1 Screen (0)
450
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
451
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
452
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
453
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
454
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
455
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
456
457
// 2 Screens - Bordered (Top Screen) (6)
458
{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
459
{ { +0.5, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
460
{ { -0.5, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
461
{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
462
{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
463
{ { -0.5, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
464
465
// 2 Screens - Bordered (Bottom Screen) (12)
466
{ { +0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
467
{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
468
{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
469
{ { +0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
470
{ { -0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
471
{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
472
473
// 2 Screens - Stretched (Top Screen) (18)
474
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
475
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
476
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
477
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
478
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
479
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
480
481
// 2 Screens - Stretched (Bottom Screen) (24)
482
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
483
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
484
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
485
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
486
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
487
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
488
489
// 4 Screens (Top-Left) (30)
490
{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
491
{ { 0.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
492
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
493
{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
494
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
495
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
496
497
// 4 Screens (Top-Right) (36)
498
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
499
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
500
{ { 0.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
501
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
502
{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
503
{ { 0.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
504
505
// 4 Screens (Bottom-Right) (42)
506
{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
507
{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
508
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
509
{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
510
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
511
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
512
513
// 4 Screens (Bottom-Left) (48)
514
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
515
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
516
{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
517
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
518
{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
519
{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
520
521
// Image/Video (54)
522
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
523
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
524
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
525
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
526
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
527
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } }
528
};
529
#else
530
const RenderVertex rsdkGLVertexBuffer[24] =
531
{
532
// 1 Screen (0)
533
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
534
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
535
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
536
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
537
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
538
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
539
540
// 2 Screens - Stretched (Top Screen) (6)
541
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
542
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
543
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
544
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
545
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
546
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
547
548
// 2 Screens - Stretched (Bottom Screen) (12)
549
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
550
{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
551
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
552
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
553
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
554
{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
555
556
// Image/Video (18)
557
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
558
{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },
559
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },
560
{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },
561
{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },
562
{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } }
563
};
564
#endif
565
566
567
void RenderDevice::InitVertexBuffer()
568
{
569
RenderVertex vertBuffer[sizeof(rsdkGLVertexBuffer) / sizeof(RenderVertex)];
570
memcpy(vertBuffer, rsdkGLVertexBuffer, sizeof(rsdkGLVertexBuffer));
571
572
float x = 0.5 / (float)viewSize.x;
573
float y = 0.5 / (float)viewSize.y;
574
575
// ignore the last 6 verts, they're scaled to the 1024x512 textures already!
576
int32 vertCount = (RETRO_REV02 ? 60 : 24) - 6;
577
for (int32 v = 0; v < vertCount; ++v) {
578
RenderVertex *vertex = &vertBuffer[v];
579
vertex->pos.x = vertex->pos.x + x;
580
vertex->pos.y = vertex->pos.y - y;
581
582
if (vertex->tex.x)
583
vertex->tex.x = screens[0].size.x * (1.0 / textureSize.x);
584
585
if (vertex->tex.y)
586
vertex->tex.y = screens[0].size.y * (1.0 / textureSize.y);
587
}
588
589
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(RenderVertex) * (!RETRO_REV02 ? 24 : 60), vertBuffer);
590
}
591
592
void RenderDevice::InitFPSCap() {
593
#if RETRO_PLATFORM == RETRO_ANDROID
594
lastFrame = std::chrono::steady_clock::now();
595
targetFreq = FramePeriod{1}; // One frame (1/60Hz)
596
#endif
597
}
598
599
bool RenderDevice::CheckFPSCap() {
600
#if RETRO_PLATFORM == RETRO_ANDROID
601
if (lastFrame + targetFreq < std::chrono::steady_clock::now())
602
return true;
603
604
return false;
605
#else
606
return true; // FPS cap using VSync
607
#endif
608
}
609
void RenderDevice::UpdateFPSCap() {
610
#if RETRO_PLATFORM == RETRO_ANDROID
611
lastFrame = std::chrono::steady_clock::now();
612
#endif
613
}
614
615
void RenderDevice::CopyFrameBuffer()
616
{
617
if (!isInitialized)
618
return;
619
620
for (int32 s = 0; s < videoSettings.screenCount; ++s) {
621
glBindTexture(GL_TEXTURE_2D, screenTextures[s]);
622
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, screens[s].pitch, SCREEN_YSIZE, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, screens[s].frameBuffer);
623
}
624
}
625
626
bool RenderDevice::ProcessEvents()
627
{
628
// events aren't processed by EGL
629
#if RETRO_PLATFORM == RETRO_ANDROID
630
// unless you're android!!
631
int32 events;
632
struct android_poll_source *source;
633
while (ALooper_pollAll(0, NULL, &events, (void **)&source) >= 0) {
634
if (source)
635
source->process(app, source);
636
637
if (app->destroyRequested) {
638
isRunning = false;
639
return false;
640
}
641
}
642
643
if (videoSettings.windowState == WINDOWSTATE_INACTIVE) {
644
Release(true);
645
}
646
else if (videoSettings.windowState == WINDOWSTATE_ACTIVE && !RenderDevice::isInitialized && RenderDevice::window) {
647
Release(true);
648
Init();
649
}
650
#endif
651
return true;
652
}
653
654
void RenderDevice::FlipScreen()
655
{
656
if (!isInitialized)
657
return;
658
659
if (lastShaderID != videoSettings.shaderID) {
660
lastShaderID = videoSettings.shaderID;
661
662
SetLinear(shaderList[videoSettings.shaderID].linear);
663
664
if (videoSettings.shaderSupport)
665
glUseProgram(shaderList[videoSettings.shaderID].programID);
666
}
667
668
if (windowRefreshDelay > 0) {
669
windowRefreshDelay--;
670
if (!windowRefreshDelay)
671
UpdateGameWindow();
672
return;
673
}
674
675
glClear(GL_COLOR_BUFFER_BIT);
676
677
if (videoSettings.shaderSupport) {
678
glUniform2fv(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "textureSize"), 1, &textureSize.x);
679
glUniform2fv(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "pixelSize"), 1, &pixelSize.x);
680
glUniform2fv(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "viewSize"), 1, &viewSize.x);
681
glUniform1f(glGetUniformLocation(shaderList[videoSettings.shaderID].programID, "screenDim"), videoSettings.dimMax * videoSettings.dimPercent);
682
}
683
684
int32 startVert = 0;
685
switch (videoSettings.screenCount) {
686
default:
687
case 0:
688
#if RETRO_REV02
689
startVert = 54;
690
#else
691
startVert = 18;
692
#endif
693
glBindTexture(GL_TEXTURE_2D, imageTexture);
694
glDrawArrays(GL_TRIANGLES, startVert, 6);
695
696
break;
697
698
case 1:
699
glBindTexture(GL_TEXTURE_2D, screenTextures[0]);
700
glDrawArrays(GL_TRIANGLES, 0, 6);
701
break;
702
703
case 2:
704
#if RETRO_REV02
705
startVert = startVertex_2P[0];
706
#else
707
startVert = 6;
708
#endif
709
glBindTexture(GL_TEXTURE_2D, screenTextures[0]);
710
glDrawArrays(GL_TRIANGLES, startVert, 6);
711
712
#if RETRO_REV02
713
startVert = startVertex_2P[1];
714
#else
715
startVert = 12;
716
#endif
717
glBindTexture(GL_TEXTURE_2D, screenTextures[1]);
718
glDrawArrays(GL_TRIANGLES, startVert, 6);
719
break;
720
721
#if RETRO_REV02
722
case 3:
723
glBindTexture(GL_TEXTURE_2D, screenTextures[0]);
724
glDrawArrays(GL_TRIANGLES, startVertex_3P[0], 6);
725
726
glBindTexture(GL_TEXTURE_2D, screenTextures[1]);
727
glDrawArrays(GL_TRIANGLES, startVertex_3P[1], 6);
728
729
glBindTexture(GL_TEXTURE_2D, screenTextures[2]);
730
glDrawArrays(GL_TRIANGLES, startVertex_3P[2], 6);
731
break;
732
733
case 4:
734
glBindTexture(GL_TEXTURE_2D, screenTextures[0]);
735
glDrawArrays(GL_TRIANGLES, 30, 6);
736
737
glBindTexture(GL_TEXTURE_2D, screenTextures[1]);
738
glDrawArrays(GL_TRIANGLES, 36, 6);
739
740
glBindTexture(GL_TEXTURE_2D, screenTextures[2]);
741
glDrawArrays(GL_TRIANGLES, 42, 6);
742
743
glBindTexture(GL_TEXTURE_2D, screenTextures[3]);
744
glDrawArrays(GL_TRIANGLES, 48, 6);
745
break;
746
#endif
747
}
748
749
#if RETRO_PLATFORM != RETRO_ANDROID
750
if (!eglSwapBuffers(display, surface)) {
751
PrintLog(PRINT_NORMAL, "[EGL] Failed to swap buffers: %d", eglGetError());
752
}
753
#else
754
if (!SwappyGL_swap(display, surface)) {
755
if (SwappyGL_isEnabled()) {
756
PrintLog(PRINT_NORMAL, "[EGL] Failed to swap buffers: %d", eglGetError());
757
}
758
}
759
#endif
760
}
761
762
void RenderDevice::Release(bool32 isRefresh)
763
{
764
if (display != EGL_NO_DISPLAY) {
765
glDeleteTextures(SCREEN_COUNT, screenTextures);
766
glDeleteTextures(1, &imageTexture);
767
768
if (videoBuffer)
769
delete[] videoBuffer;
770
videoBuffer = NULL;
771
772
for (int32 i = 0; i < shaderCount; ++i) {
773
glDeleteProgram(shaderList[i].programID);
774
}
775
776
#if RETRO_PLATFORM == RETRO_SWITCH
777
glDeleteVertexArrays(1, &VAO);
778
glDeleteBuffers(1, &VBO);
779
#endif
780
781
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
782
eglDestroyContext(display, context);
783
eglDestroySurface(display, surface);
784
eglTerminate(display);
785
786
display = EGL_NO_DISPLAY;
787
surface = EGL_NO_SURFACE;
788
context = EGL_NO_CONTEXT;
789
790
isInitialized = false;
791
}
792
793
if (!isRefresh) {
794
shaderCount = 0;
795
#if RETRO_USE_MOD_LOADER
796
userShaderCount = 0;
797
#endif
798
799
if (displayInfo.displays)
800
free(displayInfo.displays);
801
displayInfo.displays = NULL;
802
803
if (scanlines)
804
free(scanlines);
805
scanlines = NULL;
806
}
807
}
808
809
bool RenderDevice::InitShaders()
810
{
811
videoSettings.shaderSupport = true;
812
int32 maxShaders = 0;
813
shaderCount = 0;
814
815
LoadShader("None", false);
816
LoadShader("Clean", true);
817
LoadShader("CRT-Yeetron", true);
818
LoadShader("CRT-Yee64", true);
819
820
#if RETRO_USE_MOD_LOADER
821
// a place for mods to load custom shaders
822
RunModCallbacks(MODCB_ONSHADERLOAD, NULL);
823
userShaderCount = shaderCount;
824
#endif
825
826
LoadShader("YUV-420", true);
827
LoadShader("YUV-422", true);
828
LoadShader("YUV-444", true);
829
LoadShader("RGB-Image", true);
830
maxShaders = shaderCount;
831
832
// no shaders == no support
833
if (!maxShaders) {
834
ShaderEntry *shader = &shaderList[0];
835
videoSettings.shaderSupport = false;
836
837
// let's load
838
maxShaders = 1;
839
shaderCount = 1;
840
841
GLint success;
842
char infoLog[0x1000];
843
844
GLuint vert, frag;
845
const GLchar *vchar[] = { _GLVERSION, _GLDEFINE, _glVPrecision, backupVertex };
846
vert = glCreateShader(GL_VERTEX_SHADER);
847
glShaderSource(vert, 4, vchar, NULL);
848
glCompileShader(vert);
849
850
const GLchar *fchar[] = { _GLVERSION, _GLDEFINE, _glFPrecision, backupFragment };
851
frag = glCreateShader(GL_FRAGMENT_SHADER);
852
glShaderSource(frag, 4, fchar, NULL);
853
glCompileShader(frag);
854
855
glGetShaderiv(vert, GL_COMPILE_STATUS, &success);
856
if (!success) {
857
glGetShaderInfoLog(vert, 0x1000, NULL, infoLog);
858
PrintLog(PRINT_NORMAL, "BACKUP vertex shader compiling failed:\n%s", infoLog);
859
}
860
861
glGetShaderiv(frag, GL_COMPILE_STATUS, &success);
862
if (!success) {
863
glGetShaderInfoLog(frag, 0x1000, NULL, infoLog);
864
PrintLog(PRINT_NORMAL, "BACKUP fragment shader compiling failed:\n%s", infoLog);
865
}
866
867
shader->programID = glCreateProgram();
868
glAttachShader(shader->programID, vert);
869
glAttachShader(shader->programID, frag);
870
871
glBindAttribLocation(shader->programID, 0, "in_pos");
872
//glBindAttribLocation(shader->programID, 1, "in_color");
873
glBindAttribLocation(shader->programID, 1, "in_UV");
874
875
glLinkProgram(shader->programID);
876
glDeleteShader(vert);
877
glDeleteShader(frag);
878
879
glUseProgram(shader->programID);
880
881
shader->linear = videoSettings.windowed ? false : shader->linear;
882
}
883
884
videoSettings.shaderID = MAX(videoSettings.shaderID >= maxShaders ? 0 : videoSettings.shaderID, 0);
885
SetLinear(shaderList[videoSettings.shaderID].linear || videoSettings.screenCount > 1);
886
887
return true;
888
}
889
890
void RenderDevice::LoadShader(const char *fileName, bool32 linear)
891
{
892
char fullFilePath[0x100];
893
FileInfo info;
894
895
for (int32 i = 0; i < shaderCount; ++i) {
896
if (strcmp(shaderList[i].name, fileName) == 0)
897
return;
898
}
899
900
if (shaderCount == SHADER_COUNT)
901
return;
902
903
ShaderEntry *shader = &shaderList[shaderCount];
904
shader->linear = linear;
905
sprintf_s(shader->name, sizeof(shader->name), "%s", fileName);
906
907
GLint success;
908
char infoLog[0x1000];
909
GLuint vert, frag;
910
sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/OGL/None.vs");
911
InitFileInfo(&info);
912
if (LoadFile(&info, fullFilePath, FMODE_RB)) {
913
uint8 *fileData = NULL;
914
AllocateStorage((void **)&fileData, info.fileSize + 1, DATASET_TMP, false);
915
ReadBytes(&info, fileData, info.fileSize);
916
fileData[info.fileSize] = 0;
917
CloseFile(&info);
918
919
const GLchar *glchar[] = { _GLVERSION, _GLDEFINE, _glVPrecision, (const GLchar *)fileData };
920
vert = glCreateShader(GL_VERTEX_SHADER);
921
glShaderSource(vert, 4, glchar, NULL);
922
glCompileShader(vert);
923
RemoveStorageEntry((void **)&fileData);
924
925
glGetShaderiv(vert, GL_COMPILE_STATUS, &success);
926
if (!success) {
927
glGetShaderInfoLog(vert, 0x1000, NULL, infoLog);
928
PrintLog(PRINT_NORMAL, "Vertex shader compiling failed:\n%s", infoLog);
929
return;
930
}
931
}
932
else
933
return;
934
935
sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/OGL/%s.fs", fileName);
936
InitFileInfo(&info);
937
if (LoadFile(&info, fullFilePath, FMODE_RB)) {
938
uint8 *fileData = NULL;
939
AllocateStorage((void **)&fileData, info.fileSize + 1, DATASET_TMP, false);
940
ReadBytes(&info, fileData, info.fileSize);
941
fileData[info.fileSize] = 0;
942
CloseFile(&info);
943
944
const GLchar *glchar[] = { _GLVERSION, _GLDEFINE, _glFPrecision, (const GLchar *)fileData };
945
frag = glCreateShader(GL_FRAGMENT_SHADER);
946
glShaderSource(frag, 4, glchar, NULL);
947
glCompileShader(frag);
948
RemoveStorageEntry((void **)&fileData);
949
950
glGetShaderiv(frag, GL_COMPILE_STATUS, &success);
951
if (!success) {
952
glGetShaderInfoLog(frag, 0x1000, NULL, infoLog);
953
PrintLog(PRINT_NORMAL, "Fragment shader compiling failed:\n%s", infoLog);
954
return;
955
}
956
}
957
else
958
return;
959
960
shader->programID = glCreateProgram();
961
glAttachShader(shader->programID, vert);
962
glAttachShader(shader->programID, frag);
963
964
glBindAttribLocation(shader->programID, 0, "in_pos");
965
//glBindAttribLocation(shader->programID, 1, "in_color");
966
glBindAttribLocation(shader->programID, 1, "in_UV");
967
968
glLinkProgram(shader->programID);
969
glGetProgramiv(shader->programID, GL_LINK_STATUS, &success);
970
if (!success) {
971
glGetProgramInfoLog(shader->programID, 0x1000, NULL, infoLog);
972
PrintLog(PRINT_NORMAL, "OpenGL shader linking failed:\n%s", infoLog);
973
return;
974
}
975
glDeleteShader(vert);
976
glDeleteShader(frag);
977
shaderCount++;
978
};
979
980
void RenderDevice::RefreshWindow()
981
{
982
// do nothing probably
983
// there's literally 0 moment where this is needed
984
}
985
986
void RenderDevice::GetWindowSize(int32 *width, int32 *height)
987
{
988
#if RETRO_PLATFORM == RETRO_ANDROID
989
if (width)
990
eglQuerySurface(display, surface, EGL_WIDTH, width);
991
if (height)
992
eglQuerySurface(display, surface, EGL_HEIGHT, height);
993
#elif RETRO_PLATFORM == RETRO_SWITCH
994
if (width)
995
*width = 1920;
996
if (height)
997
*height = 1080;
998
#endif
999
}
1000
1001
void RenderDevice::SetupImageTexture(int32 width, int32 height, uint8 *imagePixels)
1002
{
1003
if (imagePixels && isInitialized) {
1004
glBindTexture(GL_TEXTURE_2D, imageTexture);
1005
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, imagePixels);
1006
}
1007
}
1008
1009
void RenderDevice::SetupVideoTexture_YUV420(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,
1010
int32 strideV)
1011
{
1012
if (!isInitialized)
1013
return;
1014
uint32 *pixels = videoBuffer;
1015
uint32 *preY = pixels;
1016
int32 pitch = RETRO_VIDEO_TEXTURE_W - width;
1017
if (videoSettings.shaderSupport) {
1018
for (int32 y = 0; y < height; ++y) {
1019
for (int32 x = 0; x < width; ++x) {
1020
*pixels++ = (yPlane[x] << _YOFF) | 0xFF000000;
1021
}
1022
1023
pixels += pitch;
1024
yPlane += strideY;
1025
}
1026
1027
pixels = preY;
1028
pitch = RETRO_VIDEO_TEXTURE_W - (width >> 1);
1029
for (int32 y = 0; y < (height >> 1); ++y) {
1030
for (int32 x = 0; x < (width >> 1); ++x) {
1031
*pixels++ |= (vPlane[x] << _VOFF) | (uPlane[x] << _UOFF) | 0xFF000000;
1032
}
1033
1034
pixels += pitch;
1035
uPlane += strideU;
1036
vPlane += strideV;
1037
}
1038
}
1039
else {
1040
// No shader support means no YUV support! at least use the brightness to show it in grayscale!
1041
for (int32 y = 0; y < height; ++y) {
1042
for (int32 x = 0; x < width; ++x) {
1043
int32 brightness = yPlane[x];
1044
*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;
1045
}
1046
1047
pixels += pitch;
1048
yPlane += strideY;
1049
}
1050
}
1051
1052
glBindTexture(GL_TEXTURE_2D, imageTexture);
1053
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, videoBuffer);
1054
}
1055
1056
void RenderDevice::SetupVideoTexture_YUV422(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,
1057
int32 strideV)
1058
{
1059
if (!isInitialized)
1060
return;
1061
uint32 *pixels = videoBuffer;
1062
uint32 *preY = pixels;
1063
int32 pitch = RETRO_VIDEO_TEXTURE_W - width;
1064
1065
if (videoSettings.shaderSupport) {
1066
for (int32 y = 0; y < height; ++y) {
1067
for (int32 x = 0; x < width; ++x) {
1068
*pixels++ = (yPlane[x] << _YOFF) | 0xFF000000;
1069
}
1070
1071
pixels += pitch;
1072
yPlane += strideY;
1073
}
1074
1075
pixels = preY;
1076
pitch = RETRO_VIDEO_TEXTURE_W - (width >> 1);
1077
for (int32 y = 0; y < height; ++y) {
1078
for (int32 x = 0; x < (width >> 1); ++x) {
1079
*pixels++ |= (vPlane[x] << _VOFF) | (uPlane[x] << _UOFF) | 0xFF000000;
1080
}
1081
1082
pixels += pitch;
1083
uPlane += strideU;
1084
vPlane += strideV;
1085
}
1086
}
1087
else {
1088
// No shader support means no YUV support! at least use the brightness to show it in grayscale!
1089
for (int32 y = 0; y < height; ++y) {
1090
for (int32 x = 0; x < width; ++x) {
1091
int32 brightness = yPlane[x];
1092
*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;
1093
}
1094
1095
pixels += pitch;
1096
yPlane += strideY;
1097
}
1098
}
1099
1100
glBindTexture(GL_TEXTURE_2D, imageTexture);
1101
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, videoBuffer);
1102
}
1103
void RenderDevice::SetupVideoTexture_YUV444(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,
1104
int32 strideV)
1105
{
1106
if (!isInitialized)
1107
return;
1108
uint32 *pixels = videoBuffer;
1109
int32 pitch = RETRO_VIDEO_TEXTURE_W - width;
1110
if (videoSettings.shaderSupport) {
1111
for (int32 y = 0; y < height; ++y) {
1112
int32 pos1 = yPlane - vPlane;
1113
int32 pos2 = uPlane - vPlane;
1114
uint8 *pixV = vPlane;
1115
for (int32 x = 0; x < width; ++x) {
1116
*pixels++ = (pixV[0] << _VOFF) | (pixV[pos2] << _UOFF) | (pixV[pos1] << _YOFF) | 0xFF000000;
1117
pixV++;
1118
}
1119
1120
pixels += pitch;
1121
yPlane += strideY;
1122
uPlane += strideU;
1123
vPlane += strideV;
1124
}
1125
}
1126
else {
1127
// No shader support means no YUV support! at least use the brightness to show it in grayscale!
1128
for (int32 y = 0; y < height; ++y) {
1129
for (int32 x = 0; x < width; ++x) {
1130
int32 brightness = yPlane[x];
1131
*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;
1132
}
1133
1134
pixels += pitch;
1135
yPlane += strideY;
1136
}
1137
}
1138
1139
glBindTexture(GL_TEXTURE_2D, imageTexture);
1140
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, RETRO_VIDEO_TEXTURE_W, RETRO_VIDEO_TEXTURE_H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, videoBuffer);
1141
}
1142
1143
void RenderDevice::SetLinear(bool32 linear)
1144
{
1145
if (!isInitialized)
1146
return;
1147
for (int32 i = 0; i < SCREEN_COUNT; ++i) {
1148
glBindTexture(GL_TEXTURE_2D, screenTextures[i]);
1149
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
1150
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
1151
}
1152
}
1153
1154