1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../../SDL_internal.h"
22
23#if SDL_VIDEO_RENDER_VITA_GLES2 && !SDL_RENDER_DISABLED
24
25#include "SDL_assert.h"
26#include "SDL_hints.h"
27#include "SDL_opengles2.h"
28#include "../SDL_sysrender.h"
29#include "../../video/SDL_blit.h"
30#include "SDL_shaders_gles2vita.h"
31
32//#include <psp2/gxm.h>
33//#include <psp2/types.h>
34//#include <psp2/kernel/sysmem.h>
35
36/* To prevent unnecessary window recreation,
37 * these should match the defaults selected in SDL_GL_ResetAttributes
38 */
39#define RENDERER_CONTEXT_MAJOR 2
40#define RENDERER_CONTEXT_MINOR 0
41
42/* Used to re-create the window with OpenGL ES capability */
43extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
44
45/*************************************************************************************************
46 * Context structures *
47 *************************************************************************************************/
48
49typedef struct VITA_GLES2_FBOList VITA_GLES2_FBOList;
50
51struct VITA_GLES2_FBOList
52{
53 Uint32 w, h;
54 GLuint FBO;
55 VITA_GLES2_FBOList *next;
56};
57
58typedef struct VITA_GLES2_TextureData
59{
60 GLenum texture;
61 GLenum texture_type;
62 GLenum pixel_format;
63 GLenum pixel_type;
64 void *pixel_data;
65 int pitch;
66 /* YUV texture support */
67 SDL_bool yuv;
68 SDL_bool nv12;
69 GLenum texture_v;
70 GLenum texture_u;
71 VITA_GLES2_FBOList *fbo;
72} VITA_GLES2_TextureData;
73
74typedef struct VITA_GLES2_ShaderCacheEntry
75{
76 GLuint id;
77 VITA_GLES2_ShaderType type;
78 const VITA_GLES2_ShaderInstance *instance;
79 int references;
80 struct VITA_GLES2_ShaderCacheEntry *prev;
81 struct VITA_GLES2_ShaderCacheEntry *next;
82} VITA_GLES2_ShaderCacheEntry;
83
84typedef struct VITA_GLES2_ShaderCache
85{
86 int count;
87 VITA_GLES2_ShaderCacheEntry *head;
88} VITA_GLES2_ShaderCache;
89
90typedef struct VITA_GLES2_ProgramCacheEntry
91{
92 GLuint id;
93 VITA_GLES2_ShaderCacheEntry *vertex_shader;
94 VITA_GLES2_ShaderCacheEntry *fragment_shader;
95 GLuint uniform_locations[16];
96 Uint32 color;
97 GLfloat projection[4][4];
98 struct VITA_GLES2_ProgramCacheEntry *prev;
99 struct VITA_GLES2_ProgramCacheEntry *next;
100} VITA_GLES2_ProgramCacheEntry;
101
102typedef struct VITA_GLES2_ProgramCache
103{
104 int count;
105 VITA_GLES2_ProgramCacheEntry *head;
106 VITA_GLES2_ProgramCacheEntry *tail;
107} VITA_GLES2_ProgramCache;
108
109typedef enum
110{
111 VITA_GLES2_ATTRIBUTE_POSITION = 0,
112 VITA_GLES2_ATTRIBUTE_TEXCOORD = 1,
113 VITA_GLES2_ATTRIBUTE_ANGLE = 2,
114 VITA_GLES2_ATTRIBUTE_CENTER = 3,
115} VITA_GLES2_Attribute;
116
117typedef enum
118{
119 VITA_GLES2_UNIFORM_PROJECTION,
120 VITA_GLES2_UNIFORM_TEXTURE,
121 VITA_GLES2_UNIFORM_COLOR,
122 VITA_GLES2_UNIFORM_TEXTURE_U,
123 VITA_GLES2_UNIFORM_TEXTURE_V
124} VITA_GLES2_Uniform;
125
126typedef enum
127{
128 VITA_GLES2_IMAGESOURCE_INVALID,
129 VITA_GLES2_IMAGESOURCE_SOLID,
130 VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR,
131 VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB,
132 VITA_GLES2_IMAGESOURCE_TEXTURE_RGB,
133 VITA_GLES2_IMAGESOURCE_TEXTURE_BGR,
134 VITA_GLES2_IMAGESOURCE_TEXTURE_YUV,
135 VITA_GLES2_IMAGESOURCE_TEXTURE_NV12,
136 VITA_GLES2_IMAGESOURCE_TEXTURE_NV21,
137 VITA_GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES
138} VITA_GLES2_ImageSource;
139
140typedef struct
141{
142 SDL_Rect viewport;
143 SDL_bool viewport_dirty;
144 SDL_Texture *texture;
145 SDL_Texture *target;
146 SDL_BlendMode blend;
147 SDL_bool cliprect_enabled_dirty;
148 SDL_bool cliprect_enabled;
149 SDL_bool cliprect_dirty;
150 SDL_Rect cliprect;
151 SDL_bool texturing;
152 SDL_bool is_copy_ex;
153 Uint32 color;
154 Uint32 clear_color;
155 int drawablew;
156 int drawableh;
157 VITA_GLES2_ProgramCacheEntry *program;
158 GLfloat projection[4][4];
159} VITA_GLES2_DrawStateCache;
160
161typedef struct VITA_GLES2_RenderData
162{
163 SDL_GLContext *context;
164
165 SDL_bool debug_enabled;
166
167#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
168#include "SDL_gles2funcs.h"
169#undef SDL_PROC
170
171 VITA_GLES2_FBOList *framebuffers;
172 GLuint window_framebuffer;
173
174 int shader_format_count;
175 GLenum *shader_formats;
176 VITA_GLES2_ShaderCache shader_cache;
177 VITA_GLES2_ProgramCache program_cache;
178 Uint8 clear_r, clear_g, clear_b, clear_a;
179
180 GLuint vertex_buffers[8];
181 size_t vertex_buffer_size[8];
182 int current_vertex_buffer;
183 VITA_GLES2_DrawStateCache drawstate;
184} VITA_GLES2_RenderData;
185
186#define VITA_GLES2_MAX_CACHED_PROGRAMS 8
187
188static const float inv255f = 1.0f / 255.0f;
189
190
191SDL_FORCE_INLINE const char*
192GL_TranslateError (GLenum error)
193{
194#define GL_ERROR_TRANSLATE(e) case e: return #e;
195 switch (error) {
196 GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
197 GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
198 GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
199 GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
200 GL_ERROR_TRANSLATE(GL_NO_ERROR)
201 default:
202 return "UNKNOWN";
203}
204#undef GL_ERROR_TRANSLATE
205}
206
207SDL_FORCE_INLINE void
208GL_ClearErrors(SDL_Renderer *renderer)
209{
210 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *) renderer->driverdata;
211
212 if (!data->debug_enabled) {
213 return;
214 }
215 while (data->glGetError() != GL_NO_ERROR) {
216 /* continue; */
217 }
218}
219
220SDL_FORCE_INLINE int
221GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
222{
223 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *) renderer->driverdata;
224 int ret = 0;
225
226 if (!data->debug_enabled) {
227 return 0;
228 }
229 /* check gl errors (can return multiple errors) */
230 for (;;) {
231 GLenum error = data->glGetError();
232 if (error != GL_NO_ERROR) {
233 if (prefix == NULL || prefix[0] == '\0') {
234 prefix = "generic";
235 }
236 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
237 ret = -1;
238 } else {
239 break;
240 }
241 }
242 return ret;
243}
244
245#if 0
246#define GL_CheckError(prefix, renderer)
247#else
248#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
249#endif
250
251/*************************************************************************************************
252 * Renderer state APIs *
253 *************************************************************************************************/
254
255static int VITA_GLES2_LoadFunctions(VITA_GLES2_RenderData * data)
256{
257#define SDL_PROC(ret,func,params) data->func=func;
258#include "SDL_gles2funcs.h"
259#undef SDL_PROC
260 return 0;
261}
262
263static VITA_GLES2_FBOList *
264VITA_GLES2_GetFBO(VITA_GLES2_RenderData *data, Uint32 w, Uint32 h)
265{
266 VITA_GLES2_FBOList *result = data->framebuffers;
267 while ((result) && ((result->w != w) || (result->h != h)) ) {
268 result = result->next;
269 }
270 if (result == NULL) {
271 result = SDL_malloc(sizeof(VITA_GLES2_FBOList));
272 result->w = w;
273 result->h = h;
274 data->glGenFramebuffers(1, &result->FBO);
275 result->next = data->framebuffers;
276 data->framebuffers = result;
277 }
278 return result;
279}
280
281static int
282VITA_GLES2_ActivateRenderer(SDL_Renderer * renderer)
283{
284 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
285
286 if (SDL_GL_GetCurrentContext() != data->context) {
287 /* Null out the current program to ensure we set it again */
288 data->drawstate.program = NULL;
289
290 if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
291 return -1;
292 }
293 }
294
295 GL_ClearErrors(renderer);
296
297 return 0;
298}
299
300static void
301VITA_GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
302{
303 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
304
305 if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
306 /* According to Apple documentation, we need to finish drawing NOW! */
307 data->glFinish();
308 }
309}
310
311static int
312VITA_GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
313{
314 SDL_GL_GetDrawableSize(renderer->window, w, h);
315 return 0;
316}
317
318static GLenum GetBlendFunc(SDL_BlendFactor factor)
319{
320 switch (factor) {
321 case SDL_BLENDFACTOR_ZERO:
322 return GL_ZERO;
323 case SDL_BLENDFACTOR_ONE:
324 return GL_ONE;
325 case SDL_BLENDFACTOR_SRC_COLOR:
326 return GL_SRC_COLOR;
327 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
328 return GL_ONE_MINUS_SRC_COLOR;
329 case SDL_BLENDFACTOR_SRC_ALPHA:
330 return GL_SRC_ALPHA;
331 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
332 return GL_ONE_MINUS_SRC_ALPHA;
333 case SDL_BLENDFACTOR_DST_COLOR:
334 return GL_DST_COLOR;
335 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
336 return GL_ONE_MINUS_DST_COLOR;
337 case SDL_BLENDFACTOR_DST_ALPHA:
338 return GL_DST_ALPHA;
339 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
340 return GL_ONE_MINUS_DST_ALPHA;
341 default:
342 return GL_INVALID_ENUM;
343 }
344}
345
346static GLenum GetBlendEquation(SDL_BlendOperation operation)
347{
348 switch (operation) {
349 case SDL_BLENDOPERATION_ADD:
350 return GL_FUNC_ADD;
351 case SDL_BLENDOPERATION_SUBTRACT:
352 return GL_FUNC_SUBTRACT;
353 case SDL_BLENDOPERATION_REV_SUBTRACT:
354 return GL_FUNC_REVERSE_SUBTRACT;
355 default:
356 return GL_INVALID_ENUM;
357 }
358}
359
360static SDL_bool
361VITA_GLES2_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
362{
363 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
364 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
365 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
366 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
367 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
368 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
369
370 if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
371 GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
372 GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
373 GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
374 GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
375 GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
376 return SDL_FALSE;
377 }
378 return SDL_TRUE;
379}
380
381
382static void
383VITA_GLES2_EvictShader(VITA_GLES2_RenderData *data, VITA_GLES2_ShaderCacheEntry *entry)
384{
385 /* Unlink the shader from the cache */
386 if (entry->next) {
387 entry->next->prev = entry->prev;
388 }
389 if (entry->prev) {
390 entry->prev->next = entry->next;
391 }
392 if (data->shader_cache.head == entry) {
393 data->shader_cache.head = entry->next;
394 }
395 --data->shader_cache.count;
396
397 /* Deallocate the shader */
398 data->glDeleteShader(entry->id);
399 SDL_free(entry);
400}
401
402static VITA_GLES2_ProgramCacheEntry *
403VITA_GLES2_CacheProgram(VITA_GLES2_RenderData *data, VITA_GLES2_ShaderCacheEntry *vertex,
404 VITA_GLES2_ShaderCacheEntry *fragment)
405{
406 VITA_GLES2_ProgramCacheEntry *entry;
407 VITA_GLES2_ShaderCacheEntry *shaderEntry;
408 GLint linkSuccessful;
409
410 /* Check if we've already cached this program */
411 entry = data->program_cache.head;
412 while (entry) {
413 if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) {
414 break;
415 }
416 entry = entry->next;
417 }
418 if (entry) {
419 if (data->program_cache.head != entry) {
420 if (entry->next) {
421 entry->next->prev = entry->prev;
422 }
423 if (entry->prev) {
424 entry->prev->next = entry->next;
425 }
426 entry->prev = NULL;
427 entry->next = data->program_cache.head;
428 data->program_cache.head->prev = entry;
429 data->program_cache.head = entry;
430 }
431 return entry;
432 }
433
434 /* Create a program cache entry */
435 entry = (VITA_GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(VITA_GLES2_ProgramCacheEntry));
436 if (!entry) {
437 SDL_OutOfMemory();
438 return NULL;
439 }
440 entry->vertex_shader = vertex;
441 entry->fragment_shader = fragment;
442
443 /* Create the program and link it */
444 entry->id = data->glCreateProgram();
445 data->glAttachShader(entry->id, vertex->id);
446 data->glAttachShader(entry->id, fragment->id);
447 data->glBindAttribLocation(entry->id, VITA_GLES2_ATTRIBUTE_POSITION, "a_position");
448 data->glBindAttribLocation(entry->id, VITA_GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
449 data->glBindAttribLocation(entry->id, VITA_GLES2_ATTRIBUTE_ANGLE, "a_angle");
450 data->glBindAttribLocation(entry->id, VITA_GLES2_ATTRIBUTE_CENTER, "a_center");
451 data->glLinkProgram(entry->id);
452 data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
453 if (!linkSuccessful) {
454 data->glDeleteProgram(entry->id);
455 SDL_free(entry);
456 SDL_SetError("Failed to link shader program");
457 return NULL;
458 }
459
460 /* Predetermine locations of uniform variables */
461 entry->uniform_locations[VITA_GLES2_UNIFORM_PROJECTION] =
462 data->glGetUniformLocation(entry->id, "u_projection");
463 entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE_V] =
464 data->glGetUniformLocation(entry->id, "u_texture_v");
465 entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE_U] =
466 data->glGetUniformLocation(entry->id, "u_texture_u");
467 entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE] =
468 data->glGetUniformLocation(entry->id, "u_texture");
469 entry->uniform_locations[VITA_GLES2_UNIFORM_COLOR] =
470 data->glGetUniformLocation(entry->id, "u_color");
471
472 entry->color = 0;
473
474 data->glUseProgram(entry->id);
475 if (entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE_V] != -1) {
476 data->glUniform1i(entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE_V], 2); /* always texture unit 2. */
477 }
478 if (entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE_U] != -1) {
479 data->glUniform1i(entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE_U], 1); /* always texture unit 1. */
480 }
481 if (entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE] != -1) {
482 data->glUniform1i(entry->uniform_locations[VITA_GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */
483 }
484 if (entry->uniform_locations[VITA_GLES2_UNIFORM_PROJECTION] != -1) {
485 data->glUniformMatrix4fv(entry->uniform_locations[VITA_GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
486 }
487 if (entry->uniform_locations[VITA_GLES2_UNIFORM_COLOR] != -1) {
488 data->glUniform4f(entry->uniform_locations[VITA_GLES2_UNIFORM_COLOR], 0.0f, 0.0f, 0.0f, 0.0f);
489 }
490
491 /* Cache the linked program */
492 if (data->program_cache.head) {
493 entry->next = data->program_cache.head;
494 data->program_cache.head->prev = entry;
495 } else {
496 data->program_cache.tail = entry;
497 }
498 data->program_cache.head = entry;
499 ++data->program_cache.count;
500
501 /* Increment the refcount of the shaders we're using */
502 ++vertex->references;
503 ++fragment->references;
504
505 /* Evict the last entry from the cache if we exceed the limit */
506 if (data->program_cache.count > VITA_GLES2_MAX_CACHED_PROGRAMS) {
507 shaderEntry = data->program_cache.tail->vertex_shader;
508 if (--shaderEntry->references <= 0) {
509 VITA_GLES2_EvictShader(data, shaderEntry);
510 }
511 shaderEntry = data->program_cache.tail->fragment_shader;
512 if (--shaderEntry->references <= 0) {
513 VITA_GLES2_EvictShader(data, shaderEntry);
514 }
515 data->glDeleteProgram(data->program_cache.tail->id);
516 data->program_cache.tail = data->program_cache.tail->prev;
517 if (data->program_cache.tail != NULL) {
518 SDL_free(data->program_cache.tail->next);
519 data->program_cache.tail->next = NULL;
520 }
521 --data->program_cache.count;
522 }
523 return entry;
524}
525
526static VITA_GLES2_ShaderCacheEntry *
527VITA_GLES2_CacheShader(VITA_GLES2_RenderData *data, VITA_GLES2_ShaderType type)
528{
529 const VITA_GLES2_Shader *shader;
530 const VITA_GLES2_ShaderInstance *instance = NULL;
531 VITA_GLES2_ShaderCacheEntry *entry = NULL;
532 GLint compileSuccessful = GL_FALSE;
533 int i, j;
534
535 /* Find the corresponding shader */
536 shader = VITA_GLES2_GetShader(type);
537 if (!shader) {
538 SDL_SetError("No shader matching the requested characteristics was found");
539 return NULL;
540 }
541
542 /* Find a matching shader instance that's supported on this hardware */
543 for (i = 0; i < shader->instance_count && !instance; ++i) {
544 for (j = 0; j < data->shader_format_count && !instance; ++j) {
545 if (!shader->instances[i]) {
546 continue;
547 }
548 if (shader->instances[i]->format != data->shader_formats[j]) {
549 continue;
550 }
551 instance = shader->instances[i];
552 }
553 }
554 if (!instance) {
555 SDL_SetError("The specified shader cannot be loaded on the current platform");
556 return NULL;
557 }
558
559 /* Check if we've already cached this shader */
560 entry = data->shader_cache.head;
561 while (entry) {
562 if (entry->instance == instance) {
563 break;
564 }
565 entry = entry->next;
566 }
567 if (entry) {
568 return entry;
569 }
570
571 /* Create a shader cache entry */
572 entry = (VITA_GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(VITA_GLES2_ShaderCacheEntry));
573 if (!entry) {
574 SDL_OutOfMemory();
575 return NULL;
576 }
577 entry->type = type;
578 entry->instance = instance;
579
580 /* Compile or load the selected shader instance */
581 entry->id = data->glCreateShader(instance->type);
582 if (instance->format == (GLenum)-1) {
583 data->glShaderSource(entry->id, 1, (const char **)(char *)&instance->data, NULL);
584 data->glCompileShader(entry->id);
585 data->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful);
586 } else {
587 data->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
588 compileSuccessful = GL_TRUE;
589 }
590 if (!compileSuccessful) {
591 SDL_bool isstack = SDL_FALSE;
592 char *info = NULL;
593 int length = 0;
594
595 data->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
596 if (length > 0) {
597 info = SDL_small_alloc(char, length, &isstack);
598 if (info) {
599 data->glGetShaderInfoLog(entry->id, length, &length, info);
600 }
601 }
602 if (info) {
603 SDL_SetError("Failed to load the shader: %s", info);
604 SDL_small_free(info, isstack);
605 } else {
606 SDL_SetError("Failed to load the shader");
607 }
608 data->glDeleteShader(entry->id);
609 SDL_free(entry);
610 return NULL;
611 }
612
613 /* Link the shader entry in at the front of the cache */
614 if (data->shader_cache.head) {
615 entry->next = data->shader_cache.head;
616 data->shader_cache.head->prev = entry;
617 }
618 data->shader_cache.head = entry;
619 ++data->shader_cache.count;
620 return entry;
621}
622
623static int
624VITA_GLES2_SelectProgram(VITA_GLES2_RenderData *data, VITA_GLES2_ImageSource source, int w, int h)
625{
626 VITA_GLES2_ShaderCacheEntry *vertex = NULL;
627 VITA_GLES2_ShaderCacheEntry *fragment = NULL;
628 VITA_GLES2_ShaderType vtype, ftype;
629 VITA_GLES2_ProgramCacheEntry *program;
630
631 /* Select an appropriate shader pair for the specified modes */
632 vtype = VITA_GLES2_SHADER_VERTEX_DEFAULT;
633 switch (source) {
634 case VITA_GLES2_IMAGESOURCE_SOLID:
635 ftype = VITA_GLES2_SHADER_FRAGMENT_SOLID_SRC;
636 break;
637 case VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR:
638 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC;
639 break;
640 case VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB:
641 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC;
642 break;
643 case VITA_GLES2_IMAGESOURCE_TEXTURE_RGB:
644 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC;
645 break;
646 case VITA_GLES2_IMAGESOURCE_TEXTURE_BGR:
647 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC;
648 break;
649 case VITA_GLES2_IMAGESOURCE_TEXTURE_YUV:
650 switch (SDL_GetYUVConversionModeForResolution(w, h)) {
651 case SDL_YUV_CONVERSION_JPEG:
652 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG_SRC;
653 break;
654 case SDL_YUV_CONVERSION_BT601:
655 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601_SRC;
656 break;
657 case SDL_YUV_CONVERSION_BT709:
658 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709_SRC;
659 break;
660 default:
661 SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
662 goto fault;
663 }
664 break;
665 case VITA_GLES2_IMAGESOURCE_TEXTURE_NV12:
666 switch (SDL_GetYUVConversionModeForResolution(w, h)) {
667 case SDL_YUV_CONVERSION_JPEG:
668 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_NV12_JPEG_SRC;
669 break;
670 case SDL_YUV_CONVERSION_BT601:
671 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_NV12_BT601_SRC;
672 break;
673 case SDL_YUV_CONVERSION_BT709:
674 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_NV12_BT709_SRC;
675 break;
676 default:
677 SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
678 goto fault;
679 }
680 break;
681 case VITA_GLES2_IMAGESOURCE_TEXTURE_NV21:
682 switch (SDL_GetYUVConversionModeForResolution(w, h)) {
683 case SDL_YUV_CONVERSION_JPEG:
684 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG_SRC;
685 break;
686 case SDL_YUV_CONVERSION_BT601:
687 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601_SRC;
688 break;
689 case SDL_YUV_CONVERSION_BT709:
690 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709_SRC;
691 break;
692 default:
693 SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
694 goto fault;
695 }
696 break;
697 case VITA_GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES:
698 ftype = VITA_GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES_SRC;
699 break;
700 default:
701 goto fault;
702 }
703
704 /* Load the requested shaders */
705 vertex = VITA_GLES2_CacheShader(data, vtype);
706 if (!vertex) {
707 goto fault;
708 }
709 fragment = VITA_GLES2_CacheShader(data, ftype);
710 if (!fragment) {
711 goto fault;
712 }
713
714 /* Check if we need to change programs at all */
715 if (data->drawstate.program &&
716 data->drawstate.program->vertex_shader == vertex &&
717 data->drawstate.program->fragment_shader == fragment) {
718 return 0;
719 }
720
721 /* Generate a matching program */
722 program = VITA_GLES2_CacheProgram(data, vertex, fragment);
723 if (!program) {
724 goto fault;
725 }
726
727 /* Select that program in OpenGL */
728 data->glUseProgram(program->id);
729
730 /* Set the current program */
731 data->drawstate.program = program;
732
733 /* Clean up and return */
734 return 0;
735fault:
736 if (vertex && vertex->references <= 0) {
737 VITA_GLES2_EvictShader(data, vertex);
738 }
739 if (fragment && fragment->references <= 0) {
740 VITA_GLES2_EvictShader(data, fragment);
741 }
742 data->drawstate.program = NULL;
743 return -1;
744}
745
746static int
747VITA_GLES2_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
748{
749 return 0; /* nothing to do in this backend. */
750}
751
752static int
753VITA_GLES2_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
754{
755
756 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 4, &cmd->data.draw.first);
757
758 int i;
759
760 if (!verts) {
761 return -1;
762 }
763
764 cmd->data.draw.count = count;
765 for (i = 0; i < count; i++) {
766 *(verts++) = 0.5f + points[i].x;
767 *(verts++) = 0.5f + points[i].y;
768 }
769
770 return 0;
771}
772
773static int
774VITA_GLES2_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
775{
776 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 4, &cmd->data.draw.first);
777
778 int i;
779
780 if (!verts) {
781 return -1;
782 }
783
784 cmd->data.draw.count = count;
785
786 for (i = 0; i < count; i++) {
787 const SDL_FRect *rect = &rects[i];
788 const GLfloat minx = rect->x;
789 const GLfloat maxx = rect->x + rect->w;
790 const GLfloat miny = rect->y;
791 const GLfloat maxy = rect->y + rect->h;
792 *(verts++) = minx;
793 *(verts++) = miny;
794 *(verts++) = maxx;
795 *(verts++) = miny;
796 *(verts++) = minx;
797 *(verts++) = maxy;
798 *(verts++) = maxx;
799 *(verts++) = maxy;
800 }
801
802 return 0;
803}
804
805static int
806VITA_GLES2_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
807 const SDL_Rect * srcrect, const SDL_FRect * dstrect)
808{
809 GLfloat minx, miny, maxx, maxy;
810 GLfloat minu, maxu, minv, maxv;
811 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 4, &cmd->data.draw.first);
812
813 if (!verts) {
814 return -1;
815 }
816
817 cmd->data.draw.count = 1;
818
819 minx = dstrect->x;
820 miny = dstrect->y;
821 maxx = dstrect->x + dstrect->w;
822 maxy = dstrect->y + dstrect->h;
823
824 minu = (GLfloat) srcrect->x / texture->w;
825 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
826 minv = (GLfloat) srcrect->y / texture->h;
827 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
828
829 *(verts++) = minx;
830 *(verts++) = miny;
831 *(verts++) = maxx;
832 *(verts++) = miny;
833 *(verts++) = minx;
834 *(verts++) = maxy;
835 *(verts++) = maxx;
836 *(verts++) = maxy;
837
838 *(verts++) = minu;
839 *(verts++) = minv;
840 *(verts++) = maxu;
841 *(verts++) = minv;
842 *(verts++) = minu;
843 *(verts++) = maxv;
844 *(verts++) = maxu;
845 *(verts++) = maxv;
846
847 return 0;
848}
849
850static int
851VITA_GLES2_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
852 const SDL_Rect * srcquad, const SDL_FRect * dstrect,
853 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
854{
855 /* render expects cos value - 1 (see VITA_GLES2_VertexSrc_Default_) */
856 const float radian_angle = (float)(M_PI * (360.0 - angle) / 180.0);
857 const GLfloat s = (GLfloat) SDL_sin(radian_angle);
858 const GLfloat c = (GLfloat) SDL_cos(radian_angle) - 1.0f;
859 const GLfloat centerx = center->x + dstrect->x;
860 const GLfloat centery = center->y + dstrect->y;
861 GLfloat minx, miny, maxx, maxy;
862 GLfloat minu, maxu, minv, maxv;
863 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 32 * sizeof (GLfloat), 4, &cmd->data.draw.first);
864
865 if (!verts) {
866 return -1;
867 }
868
869 if (flip & SDL_FLIP_HORIZONTAL) {
870 minx = dstrect->x + dstrect->w;
871 maxx = dstrect->x;
872 } else {
873 minx = dstrect->x;
874 maxx = dstrect->x + dstrect->w;
875 }
876
877 if (flip & SDL_FLIP_VERTICAL) {
878 miny = dstrect->y + dstrect->h;
879 maxy = dstrect->y;
880 } else {
881 miny = dstrect->y;
882 maxy = dstrect->y + dstrect->h;
883 }
884
885 minu = ((GLfloat) srcquad->x) / ((GLfloat) texture->w);
886 maxu = ((GLfloat) (srcquad->x + srcquad->w)) / ((GLfloat) texture->w);
887 minv = ((GLfloat) srcquad->y) / ((GLfloat) texture->h);
888 maxv = ((GLfloat) (srcquad->y + srcquad->h)) / ((GLfloat) texture->h);
889
890
891 cmd->data.draw.count = 1;
892
893 *(verts++) = minx;
894 *(verts++) = miny;
895 *(verts++) = maxx;
896 *(verts++) = miny;
897 *(verts++) = minx;
898 *(verts++) = maxy;
899 *(verts++) = maxx;
900 *(verts++) = maxy;
901
902 *(verts++) = minu;
903 *(verts++) = minv;
904 *(verts++) = maxu;
905 *(verts++) = minv;
906 *(verts++) = minu;
907 *(verts++) = maxv;
908 *(verts++) = maxu;
909 *(verts++) = maxv;
910
911 *(verts++) = s;
912 *(verts++) = c;
913 *(verts++) = s;
914 *(verts++) = c;
915 *(verts++) = s;
916 *(verts++) = c;
917 *(verts++) = s;
918 *(verts++) = c;
919
920 *(verts++) = centerx;
921 *(verts++) = centery;
922 *(verts++) = centerx;
923 *(verts++) = centery;
924 *(verts++) = centerx;
925 *(verts++) = centery;
926 *(verts++) = centerx;
927 *(verts++) = centery;
928
929 return 0;
930}
931
932static int
933SetDrawState(VITA_GLES2_RenderData *data, const SDL_RenderCommand *cmd, const VITA_GLES2_ImageSource imgsrc)
934{
935 const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
936 const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
937 SDL_Texture *texture = cmd->data.draw.texture;
938 const SDL_BlendMode blend = cmd->data.draw.blend;
939 VITA_GLES2_ProgramCacheEntry *program;
940
941 SDL_assert((texture != NULL) == (imgsrc != VITA_GLES2_IMAGESOURCE_SOLID));
942
943 if (data->drawstate.viewport_dirty) {
944 const SDL_Rect *viewport = &data->drawstate.viewport;
945 data->glViewport(viewport->x,
946 data->drawstate.target ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
947 viewport->w, viewport->h);
948 if (viewport->w && viewport->h) {
949 data->drawstate.projection[0][0] = 2.0f / viewport->w;
950 data->drawstate.projection[1][1] = (data->drawstate.target ? 2.0f : -2.0f) / viewport->h;
951 data->drawstate.projection[3][1] = data->drawstate.target ? -1.0f : 1.0f;
952 }
953 data->drawstate.viewport_dirty = SDL_FALSE;
954 }
955
956 if (data->drawstate.cliprect_enabled_dirty) {
957 if (!data->drawstate.cliprect_enabled) {
958 data->glDisable(GL_SCISSOR_TEST);
959 } else {
960 data->glEnable(GL_SCISSOR_TEST);
961 }
962 data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
963 }
964
965 if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
966 const SDL_Rect *viewport = &data->drawstate.viewport;
967 const SDL_Rect *rect = &data->drawstate.cliprect;
968 data->glScissor(viewport->x + rect->x,
969 data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
970 rect->w, rect->h);
971 data->drawstate.cliprect_dirty = SDL_FALSE;
972 }
973
974 if (texture != data->drawstate.texture) {
975 if ((texture != NULL) != data->drawstate.texturing) {
976 if (texture == NULL) {
977 data->glDisableVertexAttribArray((GLenum) VITA_GLES2_ATTRIBUTE_TEXCOORD);
978 data->drawstate.texturing = SDL_FALSE;
979 } else {
980 data->glEnableVertexAttribArray((GLenum) VITA_GLES2_ATTRIBUTE_TEXCOORD);
981 data->drawstate.texturing = SDL_TRUE;
982 }
983 }
984
985 if (texture) {
986 VITA_GLES2_TextureData *tdata = (VITA_GLES2_TextureData *) texture->driverdata;
987 if (tdata->yuv) {
988 data->glActiveTexture(GL_TEXTURE2);
989 data->glBindTexture(tdata->texture_type, tdata->texture_v);
990
991 data->glActiveTexture(GL_TEXTURE1);
992 data->glBindTexture(tdata->texture_type, tdata->texture_u);
993
994 data->glActiveTexture(GL_TEXTURE0);
995 } else if (tdata->nv12) {
996 data->glActiveTexture(GL_TEXTURE1);
997 data->glBindTexture(tdata->texture_type, tdata->texture_u);
998
999 data->glActiveTexture(GL_TEXTURE0);
1000 }
1001 data->glBindTexture(tdata->texture_type, tdata->texture);
1002 }
1003
1004 data->drawstate.texture = texture;
1005 }
1006
1007 if (texture) {
1008 data->glVertexAttribPointer(VITA_GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 8)));
1009 }
1010
1011 if (VITA_GLES2_SelectProgram(data, imgsrc, texture ? texture->w : 0, texture ? texture->h : 0) < 0) {
1012 return -1;
1013 }
1014
1015 program = data->drawstate.program;
1016
1017 if (program->uniform_locations[VITA_GLES2_UNIFORM_PROJECTION] != -1) {
1018 if (SDL_memcmp(program->projection, data->drawstate.projection, sizeof (data->drawstate.projection)) != 0) {
1019 data->glUniformMatrix4fv(program->uniform_locations[VITA_GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)data->drawstate.projection);
1020 SDL_memcpy(program->projection, data->drawstate.projection, sizeof (data->drawstate.projection));
1021 }
1022 }
1023
1024 if (program->uniform_locations[VITA_GLES2_UNIFORM_COLOR] != -1) {
1025 if (data->drawstate.color != program->color) {
1026 const Uint8 r = (data->drawstate.color >> 16) & 0xFF;
1027 const Uint8 g = (data->drawstate.color >> 8) & 0xFF;
1028 const Uint8 b = (data->drawstate.color >> 0) & 0xFF;
1029 const Uint8 a = (data->drawstate.color >> 24) & 0xFF;
1030 data->glUniform4f(program->uniform_locations[VITA_GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
1031 program->color = data->drawstate.color;
1032 }
1033 }
1034
1035 if (blend != data->drawstate.blend) {
1036 if (blend == SDL_BLENDMODE_NONE) {
1037 data->glDisable(GL_BLEND);
1038 } else {
1039 data->glEnable(GL_BLEND);
1040 data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
1041 GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
1042 GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
1043 GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
1044 data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
1045 GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
1046 }
1047 data->drawstate.blend = blend;
1048 }
1049
1050 /* all drawing commands use this */
1051 data->glVertexAttribPointer(VITA_GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) cmd->data.draw.first);
1052
1053 if (is_copy_ex != was_copy_ex) {
1054 if (is_copy_ex) {
1055 data->glEnableVertexAttribArray((GLenum) VITA_GLES2_ATTRIBUTE_ANGLE);
1056 data->glEnableVertexAttribArray((GLenum) VITA_GLES2_ATTRIBUTE_CENTER);
1057 } else {
1058 data->glDisableVertexAttribArray((GLenum) VITA_GLES2_ATTRIBUTE_ANGLE);
1059 data->glDisableVertexAttribArray((GLenum) VITA_GLES2_ATTRIBUTE_CENTER);
1060 }
1061 data->drawstate.is_copy_ex = is_copy_ex;
1062 }
1063
1064 if (is_copy_ex) {
1065 data->glVertexAttribPointer(VITA_GLES2_ATTRIBUTE_ANGLE, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 16)));
1066 data->glVertexAttribPointer(VITA_GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 24)));
1067 }
1068
1069 return 0;
1070}
1071
1072static int
1073SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
1074{
1075 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *) renderer->driverdata;
1076 VITA_GLES2_ImageSource sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR;
1077 SDL_Texture *texture = cmd->data.draw.texture;
1078
1079 /* Pick an appropriate shader */
1080 if (renderer->target) {
1081 /* Check if we need to do color mapping between the source and render target textures */
1082 if (renderer->target->format != texture->format) {
1083 switch (texture->format) {
1084 case SDL_PIXELFORMAT_ARGB8888:
1085 switch (renderer->target->format) {
1086 case SDL_PIXELFORMAT_ABGR8888:
1087 case SDL_PIXELFORMAT_BGR888:
1088 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB;
1089 break;
1090 case SDL_PIXELFORMAT_RGB888:
1091 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR;
1092 break;
1093 }
1094 break;
1095 case SDL_PIXELFORMAT_ABGR8888:
1096 switch (renderer->target->format) {
1097 case SDL_PIXELFORMAT_ARGB8888:
1098 case SDL_PIXELFORMAT_RGB888:
1099 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB;
1100 break;
1101 case SDL_PIXELFORMAT_BGR888:
1102 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR;
1103 break;
1104 }
1105 break;
1106 case SDL_PIXELFORMAT_RGB888:
1107 switch (renderer->target->format) {
1108 case SDL_PIXELFORMAT_ABGR8888:
1109 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB;
1110 break;
1111 case SDL_PIXELFORMAT_ARGB8888:
1112 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_BGR;
1113 break;
1114 case SDL_PIXELFORMAT_BGR888:
1115 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB;
1116 break;
1117 }
1118 break;
1119 case SDL_PIXELFORMAT_BGR888:
1120 switch (renderer->target->format) {
1121 case SDL_PIXELFORMAT_ABGR8888:
1122 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_BGR;
1123 break;
1124 case SDL_PIXELFORMAT_ARGB8888:
1125 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_RGB;
1126 break;
1127 case SDL_PIXELFORMAT_RGB888:
1128 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB;
1129 break;
1130 }
1131 break;
1132 case SDL_PIXELFORMAT_IYUV:
1133 case SDL_PIXELFORMAT_YV12:
1134 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_YUV;
1135 break;
1136 case SDL_PIXELFORMAT_NV12:
1137 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_NV12;
1138 break;
1139 case SDL_PIXELFORMAT_NV21:
1140 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_NV21;
1141 break;
1142 case SDL_PIXELFORMAT_EXTERNAL_OES:
1143 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
1144 break;
1145 default:
1146 return SDL_SetError("Unsupported texture format");
1147 }
1148 } else {
1149 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
1150 }
1151 } else {
1152 switch (texture->format) {
1153 case SDL_PIXELFORMAT_ARGB8888:
1154 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ARGB;
1155 break;
1156 case SDL_PIXELFORMAT_ABGR8888:
1157 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_ABGR;
1158 break;
1159 case SDL_PIXELFORMAT_RGB888:
1160 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_RGB;
1161 break;
1162 case SDL_PIXELFORMAT_BGR888:
1163 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_BGR;
1164 break;
1165 case SDL_PIXELFORMAT_IYUV:
1166 case SDL_PIXELFORMAT_YV12:
1167 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_YUV;
1168 break;
1169 case SDL_PIXELFORMAT_NV12:
1170 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_NV12;
1171 break;
1172 case SDL_PIXELFORMAT_NV21:
1173 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_NV21;
1174 break;
1175 case SDL_PIXELFORMAT_EXTERNAL_OES:
1176 sourceType = VITA_GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES;
1177 break;
1178 default:
1179 return SDL_SetError("Unsupported texture format");
1180 }
1181 }
1182
1183 return SetDrawState(data, cmd, sourceType);
1184}
1185
1186static int
1187VITA_GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
1188{
1189 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *) renderer->driverdata;
1190 const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888));
1191 const int vboidx = data->current_vertex_buffer;
1192 const GLuint vbo = data->vertex_buffers[vboidx];
1193 size_t i;
1194
1195 if (VITA_GLES2_ActivateRenderer(renderer) < 0) {
1196 return -1;
1197 }
1198
1199 data->drawstate.target = renderer->target;
1200 if (!data->drawstate.target) {
1201 SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
1202 }
1203
1204 /* upload the new VBO data for this set of commands. */
1205 /* NULL/zero vertices could happen SetRenderTarget is the first render command */
1206 if (vertsize > 0 && vertices != NULL)
1207 {
1208 data->glBindBuffer(GL_ARRAY_BUFFER, vbo);
1209 if (data->vertex_buffer_size[vboidx] < vertsize) {
1210 data->glBufferData(GL_ARRAY_BUFFER, vertsize, vertices, GL_DYNAMIC_DRAW);
1211 data->vertex_buffer_size[vboidx] = vertsize;
1212 } else {
1213 data->glBufferSubData(GL_ARRAY_BUFFER, 0, vertsize, vertices);
1214 }
1215 }
1216
1217 /* cycle through a few VBOs so the GL has some time with the data before we replace it. */
1218 data->current_vertex_buffer++;
1219 if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) {
1220 data->current_vertex_buffer = 0;
1221 }
1222
1223 data->glDisable(GL_DEPTH_TEST);
1224 data->glDisable(GL_CULL_FACE);
1225
1226 while (cmd) {
1227 switch (cmd->command) {
1228 case SDL_RENDERCMD_SETDRAWCOLOR: {
1229 const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r;
1230 const Uint8 g = cmd->data.color.g;
1231 const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b;
1232 const Uint8 a = cmd->data.color.a;
1233 data->drawstate.color = ((a << 24) | (r << 16) | (g << 8) | b);
1234 break;
1235 }
1236
1237 case SDL_RENDERCMD_SETVIEWPORT: {
1238 SDL_Rect *viewport = &data->drawstate.viewport;
1239 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
1240 SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
1241 data->drawstate.viewport_dirty = SDL_TRUE;
1242 }
1243 break;
1244 }
1245
1246 case SDL_RENDERCMD_SETCLIPRECT: {
1247 const SDL_Rect *rect = &cmd->data.cliprect.rect;
1248 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
1249 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
1250 data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1251 }
1252
1253 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
1254 SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
1255 data->drawstate.cliprect_dirty = SDL_TRUE;
1256 }
1257 break;
1258 }
1259
1260 case SDL_RENDERCMD_CLEAR: {
1261 const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r;
1262 const Uint8 g = cmd->data.color.g;
1263 const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b;
1264 const Uint8 a = cmd->data.color.a;
1265 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
1266 if (color != data->drawstate.clear_color) {
1267 const GLfloat fr = ((GLfloat) r) * inv255f;
1268 const GLfloat fg = ((GLfloat) g) * inv255f;
1269 const GLfloat fb = ((GLfloat) b) * inv255f;
1270 const GLfloat fa = ((GLfloat) a) * inv255f;
1271 data->glClearColor(fr, fg, fb, fa);
1272 data->drawstate.clear_color = color;
1273 }
1274
1275 if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
1276 data->glDisable(GL_SCISSOR_TEST);
1277 data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
1278 }
1279
1280 data->glClear(GL_COLOR_BUFFER_BIT);
1281 break;
1282 }
1283
1284 case SDL_RENDERCMD_DRAW_POINTS: {
1285 if (SetDrawState(data, cmd, VITA_GLES2_IMAGESOURCE_SOLID) == 0) {
1286 data->glDrawArrays(GL_POINTS, 0, (GLsizei) cmd->data.draw.count);
1287 }
1288 break;
1289 }
1290
1291 case SDL_RENDERCMD_DRAW_LINES: {
1292 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
1293 const size_t count = cmd->data.draw.count;
1294 if (SetDrawState(data, cmd, VITA_GLES2_IMAGESOURCE_SOLID) == 0) {
1295 if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
1296 /* GL_LINE_LOOP takes care of the final segment */
1297 data->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) (count - 1));
1298 } else {
1299 data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
1300 /* We need to close the endpoint of the line */
1301 data->glDrawArrays(GL_POINTS, (GLsizei) (count - 1), 1);
1302 }
1303 }
1304 break;
1305 }
1306
1307 case SDL_RENDERCMD_FILL_RECTS: {
1308 const size_t count = cmd->data.draw.count;
1309 size_t offset = 0;
1310 if (SetDrawState(data, cmd, VITA_GLES2_IMAGESOURCE_SOLID) == 0) {
1311 for (i = 0; i < count; ++i, offset += 4) {
1312 data->glDrawArrays(GL_TRIANGLE_STRIP, (GLsizei) offset, 4);
1313 }
1314 }
1315 break;
1316 }
1317
1318 case SDL_RENDERCMD_COPY:
1319 case SDL_RENDERCMD_COPY_EX: {
1320 if (SetCopyState(renderer, cmd) == 0) {
1321 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1322 }
1323 break;
1324 }
1325
1326 case SDL_RENDERCMD_NO_OP:
1327 break;
1328 }
1329
1330 cmd = cmd->next;
1331 }
1332
1333 return GL_CheckError("", renderer);
1334}
1335
1336static void
1337VITA_GLES2_DestroyRenderer(SDL_Renderer *renderer)
1338{
1339 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1340
1341 /* Deallocate everything */
1342 if (data) {
1343 VITA_GLES2_ActivateRenderer(renderer);
1344
1345 {
1346 VITA_GLES2_ShaderCacheEntry *entry;
1347 VITA_GLES2_ShaderCacheEntry *next;
1348 entry = data->shader_cache.head;
1349 while (entry) {
1350 data->glDeleteShader(entry->id);
1351 next = entry->next;
1352 SDL_free(entry);
1353 entry = next;
1354 }
1355 }
1356 {
1357 VITA_GLES2_ProgramCacheEntry *entry;
1358 VITA_GLES2_ProgramCacheEntry *next;
1359 entry = data->program_cache.head;
1360 while (entry) {
1361 data->glDeleteProgram(entry->id);
1362 next = entry->next;
1363 SDL_free(entry);
1364 entry = next;
1365 }
1366 }
1367
1368 if (data->context) {
1369 while (data->framebuffers) {
1370 VITA_GLES2_FBOList *nextnode = data->framebuffers->next;
1371 data->glDeleteFramebuffers(1, &data->framebuffers->FBO);
1372 GL_CheckError("", renderer);
1373 SDL_free(data->framebuffers);
1374 data->framebuffers = nextnode;
1375 }
1376
1377 data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
1378 GL_CheckError("", renderer);
1379
1380 SDL_GL_DeleteContext(data->context);
1381 }
1382
1383 SDL_free(data->shader_formats);
1384 SDL_free(data);
1385 }
1386 SDL_free(renderer);
1387}
1388
1389static int
1390VITA_GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1391{
1392 VITA_GLES2_RenderData *renderdata = (VITA_GLES2_RenderData *)renderer->driverdata;
1393 VITA_GLES2_TextureData *data;
1394 GLenum format;
1395 GLenum type;
1396 GLenum scaleMode;
1397
1398 VITA_GLES2_ActivateRenderer(renderer);
1399
1400 renderdata->drawstate.texture = NULL; /* we trash this state. */
1401
1402 /* Determine the corresponding GLES texture format params */
1403 switch (texture->format)
1404 {
1405 case SDL_PIXELFORMAT_ARGB8888:
1406 case SDL_PIXELFORMAT_ABGR8888:
1407 case SDL_PIXELFORMAT_RGB888:
1408 case SDL_PIXELFORMAT_BGR888:
1409 format = GL_RGBA;
1410 type = GL_UNSIGNED_BYTE;
1411 break;
1412 case SDL_PIXELFORMAT_IYUV:
1413 case SDL_PIXELFORMAT_YV12:
1414 case SDL_PIXELFORMAT_NV12:
1415 case SDL_PIXELFORMAT_NV21:
1416 format = GL_LUMINANCE;
1417 type = GL_UNSIGNED_BYTE;
1418 break;
1419 default:
1420 return SDL_SetError("Texture format not supported");
1421 }
1422
1423 if (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES &&
1424 texture->access != SDL_TEXTUREACCESS_STATIC) {
1425 return SDL_SetError("Unsupported texture access for SDL_PIXELFORMAT_EXTERNAL_OES");
1426 }
1427
1428 /* Allocate a texture struct */
1429 data = (VITA_GLES2_TextureData *)SDL_calloc(1, sizeof(VITA_GLES2_TextureData));
1430 if (!data) {
1431 return SDL_OutOfMemory();
1432 }
1433 data->texture = 0;
1434 data->texture_type = GL_TEXTURE_2D;
1435 data->pixel_format = format;
1436 data->pixel_type = type;
1437 data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
1438 data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
1439 data->texture_u = 0;
1440 data->texture_v = 0;
1441 scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
1442
1443 /* Allocate a blob for image renderdata */
1444 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
1445 size_t size;
1446 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
1447 size = texture->h * data->pitch;
1448 if (data->yuv) {
1449 /* Need to add size for the U and V planes */
1450 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
1451 } else if (data->nv12) {
1452 /* Need to add size for the U/V plane */
1453 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
1454 }
1455 data->pixel_data = SDL_calloc(1, size);
1456 if (!data->pixel_data) {
1457 SDL_free(data);
1458 return SDL_OutOfMemory();
1459 }
1460 }
1461
1462 /* Allocate the texture */
1463 GL_CheckError("", renderer);
1464
1465 if (data->yuv) {
1466 renderdata->glGenTextures(1, &data->texture_v);
1467 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1468 return -1;
1469 }
1470 renderdata->glActiveTexture(GL_TEXTURE2);
1471 renderdata->glBindTexture(data->texture_type, data->texture_v);
1472 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1473 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1474 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1475 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1476 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
1477
1478 renderdata->glGenTextures(1, &data->texture_u);
1479 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1480 return -1;
1481 }
1482 renderdata->glActiveTexture(GL_TEXTURE1);
1483 renderdata->glBindTexture(data->texture_type, data->texture_u);
1484 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1485 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1486 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1487 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1488 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
1489 if (GL_CheckError("glTexImage2D()", renderer) < 0) {
1490 return -1;
1491 }
1492 } else if (data->nv12) {
1493 renderdata->glGenTextures(1, &data->texture_u);
1494 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1495 return -1;
1496 }
1497 renderdata->glActiveTexture(GL_TEXTURE1);
1498 renderdata->glBindTexture(data->texture_type, data->texture_u);
1499 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1500 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1501 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1502 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1503 renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
1504 if (GL_CheckError("glTexImage2D()", renderer) < 0) {
1505 return -1;
1506 }
1507 }
1508
1509 renderdata->glGenTextures(1, &data->texture);
1510 if (GL_CheckError("glGenTexures()", renderer) < 0) {
1511 return -1;
1512 }
1513 texture->driverdata = data;
1514 renderdata->glActiveTexture(GL_TEXTURE0);
1515 renderdata->glBindTexture(data->texture_type, data->texture);
1516 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
1517 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
1518 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1519 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1520 if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) {
1521 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
1522 if (GL_CheckError("glTexImage2D()", renderer) < 0) {
1523 return -1;
1524 }
1525 }
1526
1527 if (texture->access == SDL_TEXTUREACCESS_TARGET) {
1528 data->fbo = VITA_GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
1529 } else {
1530 data->fbo = NULL;
1531 }
1532
1533 return GL_CheckError("", renderer);
1534}
1535
1536static int
1537VITA_GLES2_TexSubImage2D(VITA_GLES2_RenderData *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp)
1538{
1539 Uint8 *blob = NULL;
1540 Uint8 *src;
1541 int src_pitch;
1542 int y;
1543
1544 if ((width == 0) || (height == 0) || (bpp == 0)) {
1545 return 0; /* nothing to do */
1546 }
1547
1548 /* Reformat the texture data into a tightly packed array */
1549 src_pitch = width * bpp;
1550 src = (Uint8 *)pixels;
1551 if (pitch != src_pitch) {
1552 blob = (Uint8 *)SDL_malloc(src_pitch * height);
1553 if (!blob) {
1554 return SDL_OutOfMemory();
1555 }
1556 src = blob;
1557 for (y = 0; y < height; ++y)
1558 {
1559 SDL_memcpy(src, pixels, src_pitch);
1560 src += src_pitch;
1561 pixels = (Uint8 *)pixels + pitch;
1562 }
1563 src = blob;
1564 }
1565
1566 data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
1567 if (blob) {
1568 SDL_free(blob);
1569 }
1570 return 0;
1571}
1572
1573static int
1574VITA_GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
1575 const void *pixels, int pitch)
1576{
1577 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1578 VITA_GLES2_TextureData *tdata = (VITA_GLES2_TextureData *)texture->driverdata;
1579
1580 VITA_GLES2_ActivateRenderer(renderer);
1581
1582 /* Bail out if we're supposed to update an empty rectangle */
1583 if (rect->w <= 0 || rect->h <= 0) {
1584 return 0;
1585 }
1586
1587 data->drawstate.texture = NULL; /* we trash this state. */
1588
1589 /* Create a texture subimage with the supplied data */
1590 data->glBindTexture(tdata->texture_type, tdata->texture);
1591 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1592 rect->x,
1593 rect->y,
1594 rect->w,
1595 rect->h,
1596 tdata->pixel_format,
1597 tdata->pixel_type,
1598 pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
1599
1600 if (tdata->yuv) {
1601 /* Skip to the correct offset into the next texture */
1602 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
1603 if (texture->format == SDL_PIXELFORMAT_YV12) {
1604 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1605 } else {
1606 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1607 }
1608 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1609 rect->x / 2,
1610 rect->y / 2,
1611 (rect->w + 1) / 2,
1612 (rect->h + 1) / 2,
1613 tdata->pixel_format,
1614 tdata->pixel_type,
1615 pixels, (pitch + 1) / 2, 1);
1616
1617
1618 /* Skip to the correct offset into the next texture */
1619 pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
1620 if (texture->format == SDL_PIXELFORMAT_YV12) {
1621 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1622 } else {
1623 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1624 }
1625 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1626 rect->x / 2,
1627 rect->y / 2,
1628 (rect->w + 1) / 2,
1629 (rect->h + 1) / 2,
1630 tdata->pixel_format,
1631 tdata->pixel_type,
1632 pixels, (pitch + 1) / 2, 1);
1633 } else if (tdata->nv12) {
1634 /* Skip to the correct offset into the next texture */
1635 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
1636 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1637 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1638 rect->x / 2,
1639 rect->y / 2,
1640 (rect->w + 1) / 2,
1641 (rect->h + 1) / 2,
1642 GL_LUMINANCE_ALPHA,
1643 GL_UNSIGNED_BYTE,
1644 pixels, 2 * ((pitch + 1) / 2), 2);
1645 }
1646
1647 return GL_CheckError("glTexSubImage2D()", renderer);
1648}
1649
1650static int
1651VITA_GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
1652 const SDL_Rect * rect,
1653 const Uint8 *Yplane, int Ypitch,
1654 const Uint8 *Uplane, int Upitch,
1655 const Uint8 *Vplane, int Vpitch)
1656{
1657 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1658 VITA_GLES2_TextureData *tdata = (VITA_GLES2_TextureData *)texture->driverdata;
1659
1660 VITA_GLES2_ActivateRenderer(renderer);
1661
1662 /* Bail out if we're supposed to update an empty rectangle */
1663 if (rect->w <= 0 || rect->h <= 0) {
1664 return 0;
1665 }
1666
1667 data->drawstate.texture = NULL; /* we trash this state. */
1668
1669 data->glBindTexture(tdata->texture_type, tdata->texture_v);
1670 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1671 rect->x / 2,
1672 rect->y / 2,
1673 (rect->w + 1) / 2,
1674 (rect->h + 1) / 2,
1675 tdata->pixel_format,
1676 tdata->pixel_type,
1677 Vplane, Vpitch, 1);
1678
1679 data->glBindTexture(tdata->texture_type, tdata->texture_u);
1680 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1681 rect->x / 2,
1682 rect->y / 2,
1683 (rect->w + 1) / 2,
1684 (rect->h + 1) / 2,
1685 tdata->pixel_format,
1686 tdata->pixel_type,
1687 Uplane, Upitch, 1);
1688
1689 data->glBindTexture(tdata->texture_type, tdata->texture);
1690 VITA_GLES2_TexSubImage2D(data, tdata->texture_type,
1691 rect->x,
1692 rect->y,
1693 rect->w,
1694 rect->h,
1695 tdata->pixel_format,
1696 tdata->pixel_type,
1697 Yplane, Ypitch, 1);
1698
1699 return GL_CheckError("glTexSubImage2D()", renderer);
1700}
1701
1702static int
1703VITA_GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
1704 void **pixels, int *pitch)
1705{
1706 VITA_GLES2_TextureData *tdata = (VITA_GLES2_TextureData *)texture->driverdata;
1707
1708 /* Retrieve the buffer/pitch for the specified region */
1709 *pixels = (Uint8 *)tdata->pixel_data +
1710 (tdata->pitch * rect->y) +
1711 (rect->x * SDL_BYTESPERPIXEL(texture->format));
1712 *pitch = tdata->pitch;
1713
1714 return 0;
1715}
1716
1717static void
1718VITA_GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1719{
1720 VITA_GLES2_TextureData *tdata = (VITA_GLES2_TextureData *)texture->driverdata;
1721 SDL_Rect rect;
1722
1723 /* We do whole texture updates, at least for now */
1724 rect.x = 0;
1725 rect.y = 0;
1726 rect.w = texture->w;
1727 rect.h = texture->h;
1728 VITA_GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
1729}
1730
1731static void
1732VITA_GLES2_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
1733{
1734 VITA_GLES2_RenderData *renderdata = (VITA_GLES2_RenderData *) renderer->driverdata;
1735 VITA_GLES2_TextureData *data = (VITA_GLES2_TextureData *) texture->driverdata;
1736 GLenum glScaleMode = (scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
1737
1738 if (data->yuv) {
1739 renderdata->glActiveTexture(GL_TEXTURE2);
1740 renderdata->glBindTexture(data->texture_type, data->texture_v);
1741 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1742 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1743
1744 renderdata->glActiveTexture(GL_TEXTURE1);
1745 renderdata->glBindTexture(data->texture_type, data->texture_u);
1746 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1747 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1748 } else if (data->nv12) {
1749 renderdata->glActiveTexture(GL_TEXTURE1);
1750 renderdata->glBindTexture(data->texture_type, data->texture_u);
1751 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1752 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1753 }
1754
1755 renderdata->glActiveTexture(GL_TEXTURE0);
1756 renderdata->glBindTexture(data->texture_type, data->texture);
1757 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, glScaleMode);
1758 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, glScaleMode);
1759}
1760
1761static int
1762VITA_GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
1763{
1764 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *) renderer->driverdata;
1765 VITA_GLES2_TextureData *texturedata = NULL;
1766 GLenum status;
1767
1768 data->drawstate.viewport_dirty = SDL_TRUE;
1769
1770 if (texture == NULL) {
1771 data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
1772 } else {
1773 texturedata = (VITA_GLES2_TextureData *) texture->driverdata;
1774 data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
1775 /* TODO: check if texture pixel format allows this operation */
1776 data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
1777 /* Check FBO status */
1778 status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
1779 if (status != GL_FRAMEBUFFER_COMPLETE) {
1780 return SDL_SetError("glFramebufferTexture2D() failed");
1781 }
1782 }
1783 return 0;
1784}
1785
1786static void
1787VITA_GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1788{
1789 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1790 VITA_GLES2_TextureData *tdata = (VITA_GLES2_TextureData *)texture->driverdata;
1791
1792 VITA_GLES2_ActivateRenderer(renderer);
1793
1794 if (data->drawstate.texture == texture) {
1795 data->drawstate.texture = NULL;
1796 }
1797 if (data->drawstate.target == texture) {
1798 data->drawstate.target = NULL;
1799 }
1800
1801 /* Destroy the texture */
1802 if (tdata) {
1803 data->glDeleteTextures(1, &tdata->texture);
1804 if (tdata->texture_v) {
1805 data->glDeleteTextures(1, &tdata->texture_v);
1806 }
1807 if (tdata->texture_u) {
1808 data->glDeleteTextures(1, &tdata->texture_u);
1809 }
1810 SDL_free(tdata->pixel_data);
1811 SDL_free(tdata);
1812 texture->driverdata = NULL;
1813 }
1814}
1815
1816static int
1817VITA_GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1818 Uint32 pixel_format, void * pixels, int pitch)
1819{
1820 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1821 Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
1822 size_t buflen;
1823 void *temp_pixels;
1824 int temp_pitch;
1825 Uint8 *src, *dst, *tmp;
1826 int w, h, length, rows;
1827 int status;
1828
1829 temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
1830 buflen = rect->h * temp_pitch;
1831 if (buflen == 0) {
1832 return 0; /* nothing to do. */
1833 }
1834
1835 temp_pixels = SDL_malloc(buflen);
1836 if (!temp_pixels) {
1837 return SDL_OutOfMemory();
1838 }
1839
1840 SDL_GetRendererOutputSize(renderer, &w, &h);
1841
1842 data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
1843 rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
1844 if (GL_CheckError("glReadPixels()", renderer) < 0) {
1845 return -1;
1846 }
1847
1848 /* Flip the rows to be top-down if necessary */
1849 if (!renderer->target) {
1850 SDL_bool isstack;
1851 length = rect->w * SDL_BYTESPERPIXEL(temp_format);
1852 src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
1853 dst = (Uint8*)temp_pixels;
1854 tmp = SDL_small_alloc(Uint8, length, &isstack);
1855 rows = rect->h / 2;
1856 while (rows--) {
1857 SDL_memcpy(tmp, dst, length);
1858 SDL_memcpy(dst, src, length);
1859 SDL_memcpy(src, tmp, length);
1860 dst += temp_pitch;
1861 src -= temp_pitch;
1862 }
1863 SDL_small_free(tmp, isstack);
1864 }
1865
1866 status = SDL_ConvertPixels(rect->w, rect->h,
1867 temp_format, temp_pixels, temp_pitch,
1868 pixel_format, pixels, pitch);
1869 SDL_free(temp_pixels);
1870
1871 return status;
1872}
1873
1874static void
1875VITA_GLES2_RenderPresent(SDL_Renderer *renderer)
1876{
1877 /* Tell the video driver to swap buffers */
1878 SDL_GL_SwapWindow(renderer->window);
1879}
1880
1881
1882/*************************************************************************************************
1883 * Bind/unbinding of textures
1884 *************************************************************************************************/
1885static int VITA_GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
1886static int VITA_GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
1887
1888static int VITA_GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
1889{
1890 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1891 VITA_GLES2_TextureData *texturedata = (VITA_GLES2_TextureData *)texture->driverdata;
1892 VITA_GLES2_ActivateRenderer(renderer);
1893
1894 data->glBindTexture(texturedata->texture_type, texturedata->texture);
1895 data->drawstate.texture = texture;
1896
1897 if (texw) {
1898 *texw = 1.0;
1899 }
1900 if (texh) {
1901 *texh = 1.0;
1902 }
1903
1904 return 0;
1905}
1906
1907static int VITA_GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
1908{
1909 VITA_GLES2_RenderData *data = (VITA_GLES2_RenderData *)renderer->driverdata;
1910 VITA_GLES2_TextureData *texturedata = (VITA_GLES2_TextureData *)texture->driverdata;
1911 VITA_GLES2_ActivateRenderer(renderer);
1912
1913 data->glBindTexture(texturedata->texture_type, 0);
1914 data->drawstate.texture = NULL;
1915
1916 return 0;
1917}
1918
1919
1920/*************************************************************************************************
1921 * Renderer instantiation *
1922 *************************************************************************************************/
1923
1924static SDL_Renderer *
1925VITA_GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
1926{
1927 SDL_Renderer *renderer;
1928 VITA_GLES2_RenderData *data;
1929 GLint nFormats;
1930 GLboolean hasCompiler;
1931 GLint window_framebuffer;
1932 GLint value;
1933 Uint32 window_flags = 0;
1934
1935 window_flags = SDL_GetWindowFlags(window);
1936
1937 if (!(window_flags & SDL_WINDOW_OPENGL)) {
1938 if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
1939 goto error;
1940 }
1941 }
1942
1943 /* Create the renderer struct */
1944 renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
1945 if (!renderer) {
1946 SDL_OutOfMemory();
1947 goto error;
1948 }
1949
1950 data = (VITA_GLES2_RenderData *)SDL_calloc(1, sizeof(VITA_GLES2_RenderData));
1951 if (!data) {
1952 SDL_free(renderer);
1953 SDL_OutOfMemory();
1954 goto error;
1955 }
1956
1957 renderer->info = VITA_GLES2_RenderDriver.info;
1958 renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
1959 renderer->driverdata = data;
1960 renderer->window = window;
1961
1962 /* Create an OpenGL ES 2.0 context */
1963 data->context = SDL_GL_CreateContext(window);
1964 if (!data->context) {
1965 SDL_free(renderer);
1966 SDL_free(data);
1967 goto error;
1968 }
1969 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
1970 SDL_GL_DeleteContext(data->context);
1971 SDL_free(renderer);
1972 SDL_free(data);
1973 goto error;
1974 }
1975
1976 if (VITA_GLES2_LoadFunctions(data) < 0) {
1977 SDL_GL_DeleteContext(data->context);
1978 SDL_free(renderer);
1979 SDL_free(data);
1980 goto error;
1981 }
1982
1983 if (flags & SDL_RENDERER_PRESENTVSYNC) {
1984 SDL_GL_SetSwapInterval(1);
1985 } else {
1986 SDL_GL_SetSwapInterval(0);
1987 }
1988
1989 if (SDL_GL_GetSwapInterval() > 0) {
1990 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
1991 }
1992
1993 /* Check for debug output support */
1994 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
1995 (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
1996 data->debug_enabled = SDL_TRUE;
1997 }
1998
1999 value = 0;
2000 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
2001 renderer->info.max_texture_width = value;
2002 value = 0;
2003 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
2004 renderer->info.max_texture_height = value;
2005
2006 data->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
2007 hasCompiler = GL_TRUE;
2008 if (hasCompiler) {
2009 ++nFormats;
2010 }
2011
2012 data->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
2013 if (!data->shader_formats) {
2014 VITA_GLES2_DestroyRenderer(renderer);
2015 SDL_OutOfMemory();
2016 goto error;
2017 }
2018 data->shader_format_count = nFormats;
2019 data->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)data->shader_formats);
2020 if (hasCompiler) {
2021 data->shader_formats[nFormats - 1] = (GLenum)-1;
2022 }
2023
2024 /* we keep a few of these and cycle through them, so data can live for a few frames. */
2025 data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
2026
2027 data->framebuffers = NULL;
2028 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
2029 data->window_framebuffer = (GLuint)window_framebuffer;
2030
2031 /* Populate the function pointers for the module */
2032 renderer->WindowEvent = VITA_GLES2_WindowEvent;
2033 renderer->GetOutputSize = VITA_GLES2_GetOutputSize;
2034 renderer->SupportsBlendMode = VITA_GLES2_SupportsBlendMode;
2035 renderer->CreateTexture = VITA_GLES2_CreateTexture;
2036 renderer->UpdateTexture = VITA_GLES2_UpdateTexture;
2037 renderer->UpdateTextureYUV = VITA_GLES2_UpdateTextureYUV;
2038 renderer->LockTexture = VITA_GLES2_LockTexture;
2039 renderer->UnlockTexture = VITA_GLES2_UnlockTexture;
2040 renderer->SetTextureScaleMode = VITA_GLES2_SetTextureScaleMode;
2041 renderer->SetRenderTarget = VITA_GLES2_SetRenderTarget;
2042
2043 renderer->QueueSetViewport = VITA_GLES2_QueueSetViewport;
2044 renderer->QueueSetDrawColor = VITA_GLES2_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
2045 renderer->QueueDrawPoints = VITA_GLES2_QueueDrawPoints;
2046 renderer->QueueDrawLines = VITA_GLES2_QueueDrawPoints; /* lines and points queue vertices the same way. */
2047 renderer->QueueFillRects = VITA_GLES2_QueueFillRects;
2048 renderer->QueueCopy = VITA_GLES2_QueueCopy;
2049 renderer->QueueCopyEx = VITA_GLES2_QueueCopyEx;
2050 renderer->RunCommandQueue = VITA_GLES2_RunCommandQueue;
2051 renderer->RenderReadPixels = VITA_GLES2_RenderReadPixels;
2052 renderer->RenderPresent = VITA_GLES2_RenderPresent;
2053 renderer->DestroyTexture = VITA_GLES2_DestroyTexture;
2054 renderer->DestroyRenderer = VITA_GLES2_DestroyRenderer;
2055 renderer->GL_BindTexture = VITA_GLES2_BindTexture;
2056 renderer->GL_UnbindTexture = VITA_GLES2_UnbindTexture;
2057
2058// TODO. See shaders
2059// renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
2060// renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
2061// renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
2062// renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
2063
2064 /* Set up parameters for rendering */
2065 data->glActiveTexture(GL_TEXTURE0);
2066 data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
2067 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2068
2069 data->glEnableVertexAttribArray(VITA_GLES2_ATTRIBUTE_POSITION);
2070 data->glDisableVertexAttribArray(VITA_GLES2_ATTRIBUTE_TEXCOORD);
2071
2072 data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
2073
2074 data->drawstate.blend = SDL_BLENDMODE_INVALID;
2075 data->drawstate.color = 0xFFFFFFFF;
2076 data->drawstate.clear_color = 0xFFFFFFFF;
2077 data->drawstate.projection[3][0] = -1.0f;
2078 data->drawstate.projection[3][3] = 1.0f;
2079
2080 GL_CheckError("", renderer);
2081
2082 return renderer;
2083
2084error:
2085 return NULL;
2086}
2087
2088SDL_RenderDriver VITA_GLES2_RenderDriver = {
2089 VITA_GLES2_CreateRenderer,
2090 {
2091 "VITA gles2",
2092 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
2093 4,
2094 {
2095 SDL_PIXELFORMAT_ARGB8888,
2096 SDL_PIXELFORMAT_ABGR8888,
2097 SDL_PIXELFORMAT_RGB888,
2098 SDL_PIXELFORMAT_BGR888
2099 },
2100 0,
2101 0
2102 }
2103};
2104
2105#endif /* SDL_VIDEO_RENDER_VITA_GLES2 && !SDL_RENDER_DISABLED */
2106
2107/* vi: set ts=4 sw=4 expandtab: */
2108