Mercurial > sdl-ios-xcode
comparison src/render/opengles2/SDL_render_gles2.c @ 5204:523409574510
Added an OpenGL ES 2.0 renderer, contributed by itsnotabigtruck
This compiles, but it untested.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 06 Feb 2011 00:00:13 -0800 |
parents | |
children | 1f2b17f42fd0 |
comparison
equal
deleted
inserted
replaced
5203:01bced9a4cc1 | 5204:523409574510 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 2010 itsnotabigtruck. | |
4 | |
5 Permission is hereby granted, free of charge, to any person obtaining a | |
6 copy of this software and associated documentation files (the "Software"), | |
7 to deal in the Software without restriction, including without limitation | |
8 the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
9 and/or sell copies of the Software, and to permit persons to whom the | |
10 Software is furnished to do so, subject to the following conditions: | |
11 | |
12 The above copyright notice and this permission notice shall be included in | |
13 all copies or substantial portions of the Software. | |
14 | |
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
21 DEALINGS IN THE SOFTWARE. | |
22 */ | |
23 | |
24 #include "SDL_config.h" | |
25 | |
26 #if SDL_VIDEO_RENDER_OGL_ES2 | |
27 | |
28 #ifdef __IPHONEOS__ | |
29 #include <OpenGLES/ES2/gl.h> | |
30 #include <OpenGLES/ES2/glext.h> | |
31 #else | |
32 #include <GLES2/gl2.h> | |
33 #include <GLES2/gl2ext.h> | |
34 #endif | |
35 #include "../SDL_sysrender.h" | |
36 #include "SDL_shaders_gles2.h" | |
37 | |
38 /************************************************************************************************* | |
39 * Bootstrap data * | |
40 *************************************************************************************************/ | |
41 | |
42 static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags); | |
43 | |
44 SDL_RenderDriver GLES2_RenderDriver = { | |
45 GLES2_CreateRenderer, | |
46 { | |
47 "opengles2", | |
48 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), | |
49 #if GLES2_ASSUME_BGRA | |
50 11, | |
51 { | |
52 SDL_PIXELFORMAT_ABGR8888, | |
53 SDL_PIXELFORMAT_ABGR4444, | |
54 SDL_PIXELFORMAT_ABGR1555, | |
55 SDL_PIXELFORMAT_BGR565, | |
56 SDL_PIXELFORMAT_BGR24, | |
57 SDL_PIXELFORMAT_ARGB8888, | |
58 SDL_PIXELFORMAT_ARGB4444, | |
59 SDL_PIXELFORMAT_ARGB1555, | |
60 SDL_PIXELFORMAT_RGB565, | |
61 SDL_PIXELFORMAT_RGB24 | |
62 }, | |
63 #elif GLES2_ASSUME_BGRA8888 | |
64 7, | |
65 { | |
66 SDL_PIXELFORMAT_ABGR8888, | |
67 SDL_PIXELFORMAT_ABGR4444, | |
68 SDL_PIXELFORMAT_ABGR1555, | |
69 SDL_PIXELFORMAT_BGR565, | |
70 SDL_PIXELFORMAT_BGR24, | |
71 SDL_PIXELFORMAT_ARGB8888 | |
72 }, | |
73 #else | |
74 6, | |
75 { | |
76 SDL_PIXELFORMAT_ABGR8888, | |
77 SDL_PIXELFORMAT_ABGR4444, | |
78 SDL_PIXELFORMAT_ABGR1555, | |
79 SDL_PIXELFORMAT_BGR565, | |
80 SDL_PIXELFORMAT_BGR24 | |
81 }, | |
82 #endif | |
83 0, | |
84 0 | |
85 } | |
86 }; | |
87 | |
88 /************************************************************************************************* | |
89 * Context structures * | |
90 *************************************************************************************************/ | |
91 | |
92 typedef struct GLES2_TextureData | |
93 { | |
94 GLenum texture; | |
95 GLenum texture_type; | |
96 GLenum pixel_format; | |
97 GLenum pixel_type; | |
98 void *pixel_data; | |
99 size_t pitch; | |
100 } GLES2_TextureData; | |
101 | |
102 typedef struct GLES2_ShaderCacheEntry | |
103 { | |
104 GLuint id; | |
105 GLES2_ShaderType type; | |
106 const GLES2_ShaderInstance *instance; | |
107 int references; | |
108 struct GLES2_ShaderCacheEntry *prev; | |
109 struct GLES2_ShaderCacheEntry *next; | |
110 } GLES2_ShaderCacheEntry; | |
111 | |
112 typedef struct GLES2_ShaderCache | |
113 { | |
114 int count; | |
115 GLES2_ShaderCacheEntry *head; | |
116 } GLES2_ShaderCache; | |
117 | |
118 typedef struct GLES2_ProgramCacheEntry | |
119 { | |
120 GLuint id; | |
121 SDL_BlendMode blend_mode; | |
122 GLES2_ShaderCacheEntry *vertex_shader; | |
123 GLES2_ShaderCacheEntry *fragment_shader; | |
124 GLuint uniform_locations[16]; | |
125 struct GLES2_ProgramCacheEntry *prev; | |
126 struct GLES2_ProgramCacheEntry *next; | |
127 } GLES2_ProgramCacheEntry; | |
128 | |
129 typedef struct GLES2_ProgramCache | |
130 { | |
131 int count; | |
132 GLES2_ProgramCacheEntry *head; | |
133 GLES2_ProgramCacheEntry *tail; | |
134 } GLES2_ProgramCache; | |
135 | |
136 typedef enum | |
137 { | |
138 GLES2_ATTRIBUTE_POSITION = 0, | |
139 GLES2_ATTRIBUTE_TEXCOORD = 1 | |
140 } GLES2_Attribute; | |
141 | |
142 typedef enum | |
143 { | |
144 GLES2_UNIFORM_PROJECTION, | |
145 GLES2_UNIFORM_TEXTURE, | |
146 GLES2_UNIFORM_MODULATION, | |
147 GLES2_UNIFORM_COLOR, | |
148 GLES2_UNIFORM_COLORTABLE | |
149 } GLES2_Uniform; | |
150 | |
151 typedef enum | |
152 { | |
153 GLES2_IMAGESOURCE_SOLID, | |
154 GLES2_IMAGESOURCE_TEXTURE | |
155 } GLES2_ImageSource; | |
156 | |
157 typedef struct GLES2_DriverContext | |
158 { | |
159 SDL_GLContext *context; | |
160 int shader_format_count; | |
161 GLenum *shader_formats; | |
162 GLES2_ShaderCache shader_cache; | |
163 GLES2_ProgramCache program_cache; | |
164 GLES2_ProgramCacheEntry *current_program; | |
165 SDL_bool updateSize; | |
166 } GLES2_DriverContext; | |
167 | |
168 #define GLES2_MAX_CACHED_PROGRAMS 8 | |
169 | |
170 /************************************************************************************************* | |
171 * Renderer state APIs * | |
172 *************************************************************************************************/ | |
173 | |
174 static void GLES2_WindowEvent(SDL_Renderer * renderer, | |
175 const SDL_WindowEvent *event); | |
176 static int GLES2_ActivateRenderer(SDL_Renderer *renderer); | |
177 static int GLES2_DisplayModeChanged(SDL_Renderer *renderer); | |
178 static void GLES2_DestroyRenderer(SDL_Renderer *renderer); | |
179 | |
180 static SDL_GLContext SDL_CurrentContext = NULL; | |
181 | |
182 static int | |
183 GLES2_ActivateRenderer(SDL_Renderer * renderer) | |
184 { | |
185 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
186 SDL_Window *window = renderer->window; | |
187 | |
188 if (SDL_CurrentContext != rdata->context) { | |
189 /* Null out the current program to ensure we set it again */ | |
190 rdata->current_program = NULL; | |
191 | |
192 if (SDL_GL_MakeCurrent(window, rdata->context) < 0) { | |
193 return -1; | |
194 } | |
195 SDL_CurrentContext = rdata->context; | |
196 } | |
197 if (rdata->updateSize) { | |
198 int w, h; | |
199 | |
200 SDL_GetWindowSize(window, &w, &h); | |
201 glViewport(0, 0, w, h); | |
202 rdata->updateSize = SDL_FALSE; | |
203 } | |
204 return 0; | |
205 } | |
206 | |
207 static void | |
208 GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) | |
209 { | |
210 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
211 | |
212 if (event->event == SDL_WINDOWEVENT_RESIZED) { | |
213 /* Rebind the context to the window area */ | |
214 SDL_CurrentContext = NULL; | |
215 rdata->updateSize = SDL_TRUE; | |
216 } | |
217 } | |
218 | |
219 static void | |
220 GLES2_DestroyRenderer(SDL_Renderer *renderer) | |
221 { | |
222 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
223 GLES2_ProgramCacheEntry *entry; | |
224 GLES2_ProgramCacheEntry *next; | |
225 | |
226 GLES2_ActivateRenderer(renderer); | |
227 | |
228 /* Deallocate everything */ | |
229 entry = rdata->program_cache.head; | |
230 while (entry) | |
231 { | |
232 glDeleteShader(entry->vertex_shader->id); | |
233 glDeleteShader(entry->fragment_shader->id); | |
234 SDL_free(entry->vertex_shader); | |
235 SDL_free(entry->fragment_shader); | |
236 glDeleteProgram(entry->id); | |
237 next = entry->next; | |
238 SDL_free(entry); | |
239 entry = next; | |
240 } | |
241 SDL_GL_DeleteContext(rdata->context); | |
242 SDL_free(rdata->shader_formats); | |
243 SDL_free(renderer->driverdata); | |
244 SDL_free(renderer); | |
245 } | |
246 | |
247 /************************************************************************************************* | |
248 * Texture APIs * | |
249 *************************************************************************************************/ | |
250 | |
251 #define GL_BGR_EXT 0x80E0 | |
252 #define GL_BGRA_EXT 0x80E1 | |
253 | |
254 static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture); | |
255 static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture); | |
256 static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, | |
257 void **pixels, int *pitch); | |
258 static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture); | |
259 static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, | |
260 const void *pixels, int pitch); | |
261 | |
262 static int | |
263 GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) | |
264 { | |
265 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
266 GLES2_TextureData *tdata; | |
267 GLenum format; | |
268 GLenum type; | |
269 | |
270 GLES2_ActivateRenderer(renderer); | |
271 | |
272 /* Determine the corresponding GLES texture format params */ | |
273 switch (texture->format) | |
274 { | |
275 case SDL_PIXELFORMAT_BGR24: | |
276 format = GL_RGB; | |
277 type = GL_UNSIGNED_BYTE; | |
278 break; | |
279 case SDL_PIXELFORMAT_ABGR8888: | |
280 format = GL_RGBA; | |
281 type = GL_UNSIGNED_BYTE; | |
282 break; | |
283 case SDL_PIXELFORMAT_BGR565: | |
284 format = GL_RGB; | |
285 type = GL_UNSIGNED_SHORT_5_6_5; | |
286 break; | |
287 case SDL_PIXELFORMAT_ABGR1555: | |
288 format = GL_RGBA; | |
289 type = GL_UNSIGNED_SHORT_5_5_5_1; | |
290 break; | |
291 case SDL_PIXELFORMAT_ABGR4444: | |
292 format = GL_RGBA; | |
293 type = GL_UNSIGNED_SHORT_4_4_4_4; | |
294 break; | |
295 #if GLES2_ASSUME_BGRA || GLES2_ASSUME_BGRA8888 | |
296 case SDL_PIXELFORMAT_ARGB8888: | |
297 format = GL_BGRA_EXT; | |
298 type = GL_UNSIGNED_BYTE; | |
299 break; | |
300 #endif /* GLES2_ASSUME_BGRA || GLES2_ASSUME_BGRA8888 */ | |
301 #if GLES2_ASSUME_BGRA | |
302 case SDL_PIXELFORMAT_RGB24: | |
303 format = GL_BGR_EXT; | |
304 type = GL_UNSIGNED_BYTE; | |
305 break; | |
306 case SDL_PIXELFORMAT_RGB565: | |
307 format = GL_BGR_EXT; | |
308 type = GL_UNSIGNED_SHORT_5_6_5; | |
309 break; | |
310 case SDL_PIXELFORMAT_ARGB1555: | |
311 format = GL_BGRA_EXT; | |
312 type = GL_UNSIGNED_SHORT_5_5_5_1; | |
313 break; | |
314 case SDL_PIXELFORMAT_ARGB4444: | |
315 format = GL_BGRA_EXT; | |
316 type = GL_UNSIGNED_SHORT_4_4_4_4; | |
317 break; | |
318 #endif /* GLES2_ASSUME_BGRA */ | |
319 default: | |
320 SDL_SetError("Texture format not supported"); | |
321 return -1; | |
322 } | |
323 | |
324 /* Allocate a texture struct */ | |
325 tdata = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData)); | |
326 if (!tdata) | |
327 { | |
328 SDL_OutOfMemory(); | |
329 return -1; | |
330 } | |
331 tdata->texture = 0; | |
332 tdata->texture_type = GL_TEXTURE_2D; | |
333 tdata->pixel_format = format; | |
334 tdata->pixel_type = type; | |
335 | |
336 /* Allocate a blob for image data */ | |
337 if (texture->access == SDL_TEXTUREACCESS_STREAMING) | |
338 { | |
339 tdata->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); | |
340 tdata->pixel_data = SDL_malloc(tdata->pitch * texture->h); | |
341 if (!tdata->pixel_data) | |
342 { | |
343 SDL_OutOfMemory(); | |
344 SDL_free(tdata); | |
345 return -1; | |
346 } | |
347 } | |
348 | |
349 /* Allocate the texture */ | |
350 glGetError(); | |
351 glGenTextures(1, &tdata->texture); | |
352 glActiveTexture(GL_TEXTURE0); | |
353 glBindTexture(tdata->texture_type, tdata->texture); | |
354 glTexParameteri(tdata->texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
355 glTexParameteri(tdata->texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
356 glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
357 glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
358 glTexImage2D(tdata->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL); | |
359 if (glGetError() != GL_NO_ERROR) | |
360 { | |
361 SDL_SetError("Texture creation failed"); | |
362 glDeleteTextures(1, &tdata->texture); | |
363 SDL_free(tdata); | |
364 return -1; | |
365 } | |
366 texture->driverdata = tdata; | |
367 return 0; | |
368 } | |
369 | |
370 static void | |
371 GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) | |
372 { | |
373 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; | |
374 | |
375 GLES2_ActivateRenderer(renderer); | |
376 | |
377 /* Destroy the texture */ | |
378 if (tdata) | |
379 { | |
380 glDeleteTextures(1, &tdata->texture); | |
381 SDL_free(tdata->pixel_data); | |
382 SDL_free(tdata); | |
383 texture->driverdata = NULL; | |
384 } | |
385 } | |
386 | |
387 static int | |
388 GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, | |
389 void **pixels, int *pitch) | |
390 { | |
391 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; | |
392 | |
393 /* Retrieve the buffer/pitch for the specified region */ | |
394 *pixels = (Uint8 *)tdata->pixel_data + | |
395 (tdata->pitch * rect->y) + | |
396 (rect->x * SDL_BYTESPERPIXEL(texture->format)); | |
397 *pitch = tdata->pitch; | |
398 | |
399 return 0; | |
400 } | |
401 | |
402 static void | |
403 GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) | |
404 { | |
405 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; | |
406 | |
407 GLES2_ActivateRenderer(renderer); | |
408 | |
409 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
410 glActiveTexture(GL_TEXTURE0); | |
411 glBindTexture(tdata->texture_type, tdata->texture); | |
412 glTexSubImage2D(tdata->texture_type, 0, 0, 0, texture->w, texture->h, | |
413 tdata->pixel_format, tdata->pixel_type, tdata->pixel_data); | |
414 } | |
415 | |
416 static int | |
417 GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, | |
418 const void *pixels, int pitch) | |
419 { | |
420 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; | |
421 Uint8 *blob = NULL; | |
422 Uint8 *src; | |
423 int srcPitch; | |
424 Uint8 *dest; | |
425 int y; | |
426 | |
427 GLES2_ActivateRenderer(renderer); | |
428 | |
429 /* Bail out if we're supposed to update an empty rectangle */ | |
430 if (rect->w <= 0 || rect->h <= 0) | |
431 return 0; | |
432 | |
433 /* Reformat the texture data into a tightly packed array */ | |
434 srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format); | |
435 src = (Uint8 *)pixels; | |
436 if (pitch != srcPitch) | |
437 { | |
438 blob = (Uint8 *)SDL_malloc(srcPitch * rect->h); | |
439 if (!blob) | |
440 { | |
441 SDL_OutOfMemory(); | |
442 return -1; | |
443 } | |
444 src = blob; | |
445 for (y = 0; y < rect->h; ++y) | |
446 { | |
447 SDL_memcpy(src, pixels, srcPitch); | |
448 src += srcPitch; | |
449 pixels = (Uint8 *)pixels + pitch; | |
450 } | |
451 src = blob; | |
452 } | |
453 | |
454 /* Create a texture subimage with the supplied data */ | |
455 glGetError(); | |
456 glActiveTexture(GL_TEXTURE0); | |
457 glBindTexture(tdata->texture_type, tdata->texture); | |
458 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
459 glTexSubImage2D(tdata->texture_type, | |
460 0, | |
461 rect->x, | |
462 rect->y, | |
463 rect->w, | |
464 rect->h, | |
465 tdata->pixel_format, | |
466 tdata->pixel_type, | |
467 src); | |
468 if (glGetError() != GL_NO_ERROR) | |
469 { | |
470 SDL_SetError("Failed to update texture"); | |
471 return -1; | |
472 } | |
473 | |
474 /* Update the (streaming) texture buffer, in one pass if possible */ | |
475 if (tdata->pixel_data) | |
476 { | |
477 dest = (Uint8 *)tdata->pixel_data + | |
478 (tdata->pitch * rect->y) + | |
479 (SDL_BYTESPERPIXEL(texture->format) * rect->x); | |
480 if (rect->w == texture->w) | |
481 { | |
482 SDL_memcpy(dest, src, srcPitch * rect->h); | |
483 } | |
484 else | |
485 { | |
486 for (y = 0; y < rect->h; ++y) | |
487 { | |
488 SDL_memcpy(dest, src, srcPitch); | |
489 src += srcPitch; | |
490 dest += tdata->pitch; | |
491 } | |
492 } | |
493 } | |
494 | |
495 /* Clean up and return */ | |
496 SDL_free(blob); | |
497 return 0; | |
498 } | |
499 | |
500 /************************************************************************************************* | |
501 * Shader management functions * | |
502 *************************************************************************************************/ | |
503 | |
504 static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, | |
505 SDL_BlendMode blendMode); | |
506 static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry); | |
507 static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer, | |
508 GLES2_ShaderCacheEntry *vertex, | |
509 GLES2_ShaderCacheEntry *fragment, | |
510 SDL_BlendMode blendMode); | |
511 static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, | |
512 SDL_BlendMode blendMode); | |
513 static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer); | |
514 | |
515 static GLES2_ProgramCacheEntry * | |
516 GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, | |
517 GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode) | |
518 { | |
519 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
520 GLES2_ProgramCacheEntry *entry; | |
521 GLES2_ShaderCacheEntry *shaderEntry; | |
522 GLint linkSuccessful; | |
523 | |
524 /* Check if we've already cached this program */ | |
525 entry = rdata->program_cache.head; | |
526 while (entry) | |
527 { | |
528 if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) | |
529 break; | |
530 entry = entry->next; | |
531 } | |
532 if (entry) | |
533 { | |
534 if (rdata->program_cache.count > 1) | |
535 { | |
536 if (entry->next) | |
537 entry->next->prev = entry->prev; | |
538 if (entry->prev) | |
539 entry->prev->next = entry->next; | |
540 entry->prev = NULL; | |
541 entry->next = rdata->program_cache.head; | |
542 rdata->program_cache.head->prev = entry; | |
543 rdata->program_cache.head = entry; | |
544 } | |
545 return entry; | |
546 } | |
547 | |
548 /* Create a program cache entry */ | |
549 entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry)); | |
550 if (!entry) | |
551 { | |
552 SDL_OutOfMemory(); | |
553 return NULL; | |
554 } | |
555 entry->vertex_shader = vertex; | |
556 entry->fragment_shader = fragment; | |
557 entry->blend_mode = blendMode; | |
558 | |
559 /* Create the program and link it */ | |
560 glGetError(); | |
561 entry->id = glCreateProgram(); | |
562 glAttachShader(entry->id, vertex->id); | |
563 glAttachShader(entry->id, fragment->id); | |
564 glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position"); | |
565 glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord"); | |
566 glLinkProgram(entry->id); | |
567 glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful); | |
568 if (glGetError() != GL_NO_ERROR || !linkSuccessful) | |
569 { | |
570 SDL_SetError("Failed to link shader program"); | |
571 glDeleteProgram(entry->id); | |
572 SDL_free(entry); | |
573 return NULL; | |
574 } | |
575 | |
576 /* Predetermine locations of uniform variables */ | |
577 entry->uniform_locations[GLES2_UNIFORM_PROJECTION] = | |
578 glGetUniformLocation(entry->id, "u_projection"); | |
579 entry->uniform_locations[GLES2_UNIFORM_TEXTURE] = | |
580 glGetUniformLocation(entry->id, "u_texture"); | |
581 entry->uniform_locations[GLES2_UNIFORM_MODULATION] = | |
582 glGetUniformLocation(entry->id, "u_modulation"); | |
583 entry->uniform_locations[GLES2_UNIFORM_COLOR] = | |
584 glGetUniformLocation(entry->id, "u_color"); | |
585 entry->uniform_locations[GLES2_UNIFORM_COLORTABLE] = | |
586 glGetUniformLocation(entry->id, "u_colorTable"); | |
587 | |
588 /* Cache the linked program */ | |
589 if (rdata->program_cache.head) | |
590 { | |
591 entry->next = rdata->program_cache.head; | |
592 rdata->program_cache.head->prev = entry; | |
593 } | |
594 else | |
595 { | |
596 rdata->program_cache.tail = entry; | |
597 } | |
598 rdata->program_cache.head = entry; | |
599 ++rdata->program_cache.count; | |
600 | |
601 /* Increment the refcount of the shaders we're using */ | |
602 ++vertex->references; | |
603 ++fragment->references; | |
604 | |
605 /* Evict the last entry from the cache if we exceed the limit */ | |
606 if (rdata->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) | |
607 { | |
608 shaderEntry = rdata->program_cache.tail->vertex_shader; | |
609 if (--shaderEntry->references <= 0) | |
610 GLES2_EvictShader(renderer, shaderEntry); | |
611 shaderEntry = rdata->program_cache.tail->fragment_shader; | |
612 if (--shaderEntry->references <= 0) | |
613 GLES2_EvictShader(renderer, shaderEntry); | |
614 glDeleteProgram(rdata->program_cache.tail->id); | |
615 rdata->program_cache.tail = rdata->program_cache.tail->prev; | |
616 SDL_free(rdata->program_cache.tail->next); | |
617 rdata->program_cache.tail->next = NULL; | |
618 --rdata->program_cache.count; | |
619 } | |
620 return entry; | |
621 } | |
622 | |
623 static GLES2_ShaderCacheEntry * | |
624 GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode) | |
625 { | |
626 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
627 const GLES2_Shader *shader; | |
628 const GLES2_ShaderInstance *instance = NULL; | |
629 GLES2_ShaderCacheEntry *entry = NULL; | |
630 GLint compileSuccessful = GL_FALSE; | |
631 int i, j; | |
632 | |
633 /* Find the corresponding shader */ | |
634 shader = GLES2_GetShader(type, blendMode); | |
635 if (!shader) | |
636 { | |
637 SDL_SetError("No shader matching the requested characteristics was found"); | |
638 return NULL; | |
639 } | |
640 | |
641 /* Find a matching shader instance that's supported on this hardware */ | |
642 for (i = 0; i < shader->instance_count; ++i) | |
643 { | |
644 for (j = 0; j < rdata->shader_format_count; ++j) | |
645 { | |
646 if (!shader->instances) | |
647 continue; | |
648 if (shader->instances[i]->format != rdata->shader_formats[j]) | |
649 continue; | |
650 instance = shader->instances[i]; | |
651 break; | |
652 } | |
653 } | |
654 if (!instance) | |
655 { | |
656 SDL_SetError("The specified shader cannot be loaded on the current platform"); | |
657 return NULL; | |
658 } | |
659 | |
660 /* Check if we've already cached this shader */ | |
661 entry = rdata->shader_cache.head; | |
662 while (entry) | |
663 { | |
664 if (entry->instance == instance) | |
665 break; | |
666 entry = entry->next; | |
667 } | |
668 if (entry) | |
669 return entry; | |
670 | |
671 /* Create a shader cache entry */ | |
672 entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry)); | |
673 if (!entry) | |
674 { | |
675 SDL_OutOfMemory(); | |
676 return NULL; | |
677 } | |
678 entry->type = type; | |
679 entry->instance = instance; | |
680 | |
681 /* Compile or load the selected shader instance */ | |
682 glGetError(); | |
683 entry->id = glCreateShader(instance->type); | |
684 if (instance->format == (GLenum)-1) | |
685 { | |
686 glShaderSource(entry->id, 1, (const char **)&instance->data, &instance->length); | |
687 glCompileShader(entry->id); | |
688 glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful); | |
689 } | |
690 else | |
691 { | |
692 glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length); | |
693 compileSuccessful = GL_TRUE; | |
694 } | |
695 if (glGetError() != GL_NO_ERROR || !compileSuccessful) | |
696 { | |
697 SDL_SetError("Failed to load the specified shader"); | |
698 glDeleteShader(entry->id); | |
699 SDL_free(entry); | |
700 return NULL; | |
701 } | |
702 | |
703 /* Link the shader entry in at the front of the cache */ | |
704 if (rdata->shader_cache.head) | |
705 { | |
706 entry->next = rdata->shader_cache.head; | |
707 rdata->shader_cache.head->prev = entry; | |
708 } | |
709 rdata->shader_cache.head = entry; | |
710 ++rdata->shader_cache.count; | |
711 return entry; | |
712 } | |
713 | |
714 static void | |
715 GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry) | |
716 { | |
717 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
718 | |
719 /* Unlink the shader from the cache */ | |
720 if (entry->next) | |
721 entry->next->prev = entry->prev; | |
722 if (entry->prev) | |
723 entry->prev->next = entry->next; | |
724 if (rdata->shader_cache.head == entry) | |
725 rdata->shader_cache.head = entry->next; | |
726 --rdata->shader_cache.count; | |
727 | |
728 /* Deallocate the shader */ | |
729 glDeleteShader(entry->id); | |
730 SDL_free(entry); | |
731 } | |
732 | |
733 static int | |
734 GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode) | |
735 { | |
736 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
737 GLES2_ShaderCacheEntry *vertex = NULL; | |
738 GLES2_ShaderCacheEntry *fragment = NULL; | |
739 GLES2_ShaderType vtype, ftype; | |
740 GLES2_ProgramCacheEntry *program; | |
741 | |
742 /* Select an appropriate shader pair for the specified modes */ | |
743 vtype = GLES2_SHADER_VERTEX_DEFAULT; | |
744 switch (source) | |
745 { | |
746 case GLES2_IMAGESOURCE_SOLID: | |
747 ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC; | |
748 break; | |
749 case GLES2_IMAGESOURCE_TEXTURE: | |
750 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_SRC; | |
751 break; | |
752 } | |
753 | |
754 /* Load the requested shaders */ | |
755 vertex = GLES2_CacheShader(renderer, vtype, blendMode); | |
756 if (!vertex) | |
757 goto fault; | |
758 fragment = GLES2_CacheShader(renderer, ftype, blendMode); | |
759 if (!fragment) | |
760 goto fault; | |
761 | |
762 /* Check if we need to change programs at all */ | |
763 if (rdata->current_program && | |
764 rdata->current_program->vertex_shader == vertex && | |
765 rdata->current_program->fragment_shader == fragment) | |
766 return 0; | |
767 | |
768 /* Generate a matching program */ | |
769 program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode); | |
770 if (!program) | |
771 goto fault; | |
772 | |
773 /* Select that program in OpenGL */ | |
774 glGetError(); | |
775 glUseProgram(program->id); | |
776 if (glGetError() != GL_NO_ERROR) | |
777 { | |
778 SDL_SetError("Failed to select program"); | |
779 goto fault; | |
780 } | |
781 | |
782 /* Set the current program */ | |
783 rdata->current_program = program; | |
784 | |
785 /* Activate an orthographic projection */ | |
786 if (GLES2_SetOrthographicProjection(renderer) < 0) | |
787 goto fault; | |
788 | |
789 /* Clean up and return */ | |
790 return 0; | |
791 fault: | |
792 if (vertex && vertex->references <= 0) | |
793 GLES2_EvictShader(renderer, vertex); | |
794 if (fragment && fragment->references <= 0) | |
795 GLES2_EvictShader(renderer, fragment); | |
796 rdata->current_program = NULL; | |
797 return -1; | |
798 } | |
799 | |
800 static int | |
801 GLES2_SetOrthographicProjection(SDL_Renderer *renderer) | |
802 { | |
803 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
804 SDL_Window *window = renderer->window; | |
805 int w, h; | |
806 GLfloat projection[4][4]; | |
807 GLuint locProjection; | |
808 | |
809 /* Get the window width and height */ | |
810 SDL_GetWindowSize(window, &w, &h); | |
811 | |
812 /* Prepare an orthographic projection */ | |
813 projection[0][0] = 2.0f / w; | |
814 projection[0][1] = 0.0f; | |
815 projection[0][2] = 0.0f; | |
816 projection[0][3] = 0.0f; | |
817 projection[1][0] = 0.0f; | |
818 projection[1][1] = -2.0f / h; | |
819 projection[1][2] = 0.0f; | |
820 projection[1][3] = 0.0f; | |
821 projection[2][0] = 0.0f; | |
822 projection[2][1] = 0.0f; | |
823 projection[2][2] = 1.0f; | |
824 projection[2][3] = 0.0f; | |
825 projection[3][0] = -1.0f; | |
826 projection[3][1] = 1.0f; | |
827 projection[3][2] = 0.0f; | |
828 projection[3][3] = 1.0f; | |
829 | |
830 /* Set the projection matrix */ | |
831 locProjection = rdata->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION]; | |
832 glGetError(); | |
833 glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection); | |
834 if (glGetError() != GL_NO_ERROR) | |
835 { | |
836 SDL_SetError("Failed to set orthographic projection"); | |
837 return -1; | |
838 } | |
839 return 0; | |
840 } | |
841 | |
842 /************************************************************************************************* | |
843 * Rendering functions * | |
844 *************************************************************************************************/ | |
845 | |
846 static int GLES2_RenderClear(SDL_Renderer *renderer); | |
847 static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count); | |
848 static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count); | |
849 static int GLES2_RenderDrawRects(SDL_Renderer *renderer, const SDL_Rect **rects, int count); | |
850 static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect **rects, int count); | |
851 static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, | |
852 const SDL_Rect *dstrect); | |
853 static void GLES2_RenderPresent(SDL_Renderer *renderer); | |
854 | |
855 static int | |
856 GLES2_RenderClear(SDL_Renderer *renderer) | |
857 { | |
858 float r = (float)renderer->r / 255.0f; | |
859 float g = (float)renderer->g / 255.0f; | |
860 float b = (float)renderer->b / 255.0f; | |
861 float a = (float)renderer->a / 255.0f; | |
862 | |
863 GLES2_ActivateRenderer(renderer); | |
864 | |
865 /* Clear the backbuffer with the selected color */ | |
866 glClearColor(r, g, b, a); | |
867 glClear(GL_COLOR_BUFFER_BIT); | |
868 return 0; | |
869 } | |
870 | |
871 static void | |
872 GLES2_SetBlendMode(int blendMode) | |
873 { | |
874 switch (blendMode) | |
875 { | |
876 case SDL_BLENDMODE_NONE: | |
877 default: | |
878 glDisable(GL_BLEND); | |
879 break; | |
880 case SDL_BLENDMODE_BLEND: | |
881 glEnable(GL_BLEND); | |
882 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
883 break; | |
884 case SDL_BLENDMODE_ADD: | |
885 glEnable(GL_BLEND); | |
886 glBlendFunc(GL_SRC_ALPHA, GL_ONE); | |
887 break; | |
888 case SDL_BLENDMODE_MOD: | |
889 glEnable(GL_BLEND); | |
890 glBlendFunc(GL_ZERO, GL_SRC_COLOR); | |
891 break; | |
892 } | |
893 } | |
894 | |
895 static int | |
896 GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count) | |
897 { | |
898 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
899 GLfloat *vertices; | |
900 SDL_BlendMode blendMode; | |
901 int alpha; | |
902 GLuint locColor; | |
903 int idx; | |
904 | |
905 GLES2_ActivateRenderer(renderer); | |
906 | |
907 blendMode = renderer->blendMode; | |
908 alpha = renderer->a; | |
909 | |
910 /* Activate an appropriate shader and set the projection matrix */ | |
911 if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) | |
912 return -1; | |
913 | |
914 /* Select the color to draw with */ | |
915 locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR]; | |
916 glGetError(); | |
917 glUniform4f(locColor, | |
918 renderer->r / 255.0f, | |
919 renderer->g / 255.0f, | |
920 renderer->b / 255.0f, | |
921 alpha / 255.0f); | |
922 | |
923 /* Configure the correct blend mode */ | |
924 GLES2_SetBlendMode(blendMode); | |
925 | |
926 /* Emit the specified vertices as points */ | |
927 vertices = SDL_stack_alloc(GLfloat, count * 2); | |
928 for (idx = 0; idx < count; ++idx) | |
929 { | |
930 GLfloat x = (GLfloat)points[idx].x + 0.5f; | |
931 GLfloat y = (GLfloat)points[idx].y + 0.5f; | |
932 | |
933 vertices[idx * 2] = x; | |
934 vertices[(idx * 2) + 1] = y; | |
935 } | |
936 glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
937 glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); | |
938 glDrawArrays(GL_POINTS, 0, count); | |
939 glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
940 SDL_stack_free(vertices); | |
941 if (glGetError() != GL_NO_ERROR) | |
942 { | |
943 SDL_SetError("Failed to render lines"); | |
944 return -1; | |
945 } | |
946 return 0; | |
947 } | |
948 | |
949 static int | |
950 GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count) | |
951 { | |
952 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
953 GLfloat *vertices; | |
954 SDL_BlendMode blendMode; | |
955 int alpha; | |
956 GLuint locColor; | |
957 int idx; | |
958 | |
959 GLES2_ActivateRenderer(renderer); | |
960 | |
961 blendMode = renderer->blendMode; | |
962 alpha = renderer->a; | |
963 | |
964 /* Activate an appropriate shader and set the projection matrix */ | |
965 if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) | |
966 return -1; | |
967 | |
968 /* Select the color to draw with */ | |
969 locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR]; | |
970 glGetError(); | |
971 glUniform4f(locColor, | |
972 renderer->r / 255.0f, | |
973 renderer->g / 255.0f, | |
974 renderer->b / 255.0f, | |
975 alpha / 255.0f); | |
976 | |
977 /* Configure the correct blend mode */ | |
978 GLES2_SetBlendMode(blendMode); | |
979 | |
980 /* Emit a line strip including the specified vertices */ | |
981 vertices = SDL_stack_alloc(GLfloat, count * 2); | |
982 for (idx = 0; idx < count; ++idx) | |
983 { | |
984 GLfloat x = (GLfloat)points[idx].x + 0.5f; | |
985 GLfloat y = (GLfloat)points[idx].y + 0.5f; | |
986 | |
987 vertices[idx * 2] = x; | |
988 vertices[(idx * 2) + 1] = y; | |
989 } | |
990 glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
991 glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); | |
992 glDrawArrays(GL_LINE_STRIP, 0, count); | |
993 glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
994 SDL_stack_free(vertices); | |
995 if (glGetError() != GL_NO_ERROR) | |
996 { | |
997 SDL_SetError("Failed to render lines"); | |
998 return -1; | |
999 } | |
1000 return 0; | |
1001 } | |
1002 | |
1003 static int | |
1004 GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect **rects, int count) | |
1005 { | |
1006 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
1007 GLfloat vertices[8]; | |
1008 SDL_BlendMode blendMode; | |
1009 int alpha; | |
1010 GLuint locColor; | |
1011 int idx; | |
1012 | |
1013 GLES2_ActivateRenderer(renderer); | |
1014 | |
1015 blendMode = renderer->blendMode; | |
1016 alpha = renderer->a; | |
1017 | |
1018 /* Activate an appropriate shader and set the projection matrix */ | |
1019 if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) | |
1020 return -1; | |
1021 | |
1022 /* Select the color to draw with */ | |
1023 locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR]; | |
1024 glGetError(); | |
1025 glUniform4f(locColor, | |
1026 renderer->r / 255.0f, | |
1027 renderer->g / 255.0f, | |
1028 renderer->b / 255.0f, | |
1029 alpha / 255.0f); | |
1030 | |
1031 /* Configure the correct blend mode */ | |
1032 GLES2_SetBlendMode(blendMode); | |
1033 | |
1034 /* Emit a line loop for each rectangle */ | |
1035 glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
1036 for (idx = 0; idx < count; ++idx) | |
1037 { | |
1038 GLfloat xMin = (GLfloat)rects[idx]->x; | |
1039 GLfloat xMax = (GLfloat)(rects[idx]->x + rects[idx]->w); | |
1040 GLfloat yMin = (GLfloat)rects[idx]->y; | |
1041 GLfloat yMax = (GLfloat)(rects[idx]->y + rects[idx]->h); | |
1042 | |
1043 vertices[0] = xMin; | |
1044 vertices[1] = yMin; | |
1045 vertices[2] = xMax; | |
1046 vertices[3] = yMin; | |
1047 vertices[4] = xMin; | |
1048 vertices[5] = yMax; | |
1049 vertices[6] = xMax; | |
1050 vertices[7] = yMax; | |
1051 glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); | |
1052 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
1053 } | |
1054 glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
1055 if (glGetError() != GL_NO_ERROR) | |
1056 { | |
1057 SDL_SetError("Failed to render lines"); | |
1058 return -1; | |
1059 } | |
1060 return 0; | |
1061 } | |
1062 | |
1063 static int | |
1064 GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, | |
1065 const SDL_Rect *dstrect) | |
1066 { | |
1067 GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata; | |
1068 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; | |
1069 GLES2_ImageSource sourceType; | |
1070 SDL_BlendMode blendMode; | |
1071 int alpha; | |
1072 GLfloat vertices[8]; | |
1073 GLfloat texCoords[8]; | |
1074 GLuint locTexture; | |
1075 GLuint locModulation; | |
1076 GLuint locColorTable; | |
1077 | |
1078 GLES2_ActivateRenderer(renderer); | |
1079 | |
1080 /* Activate an appropriate shader and set the projection matrix */ | |
1081 blendMode = texture->blendMode; | |
1082 alpha = texture->a; | |
1083 sourceType = GLES2_IMAGESOURCE_TEXTURE; | |
1084 if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) | |
1085 return -1; | |
1086 | |
1087 /* Select the target texture */ | |
1088 locTexture = rdata->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE]; | |
1089 glGetError(); | |
1090 glActiveTexture(GL_TEXTURE0); | |
1091 glBindTexture(tdata->texture_type, tdata->texture); | |
1092 glUniform1i(locTexture, 0); | |
1093 | |
1094 /* Configure texture blending */ | |
1095 GLES2_SetBlendMode(blendMode); | |
1096 | |
1097 /* Configure color modulation */ | |
1098 locModulation = rdata->current_program->uniform_locations[GLES2_UNIFORM_MODULATION]; | |
1099 glUniform4f(locModulation, | |
1100 texture->r / 255.0f, | |
1101 texture->g / 255.0f, | |
1102 texture->b / 255.0f, | |
1103 alpha / 255.0f); | |
1104 | |
1105 /* Emit the textured quad */ | |
1106 glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); | |
1107 glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
1108 vertices[0] = (GLfloat)dstrect->x; | |
1109 vertices[1] = (GLfloat)dstrect->y; | |
1110 vertices[2] = (GLfloat)(dstrect->x + dstrect->w); | |
1111 vertices[3] = (GLfloat)dstrect->y; | |
1112 vertices[4] = (GLfloat)dstrect->x; | |
1113 vertices[5] = (GLfloat)(dstrect->y + dstrect->h); | |
1114 vertices[6] = (GLfloat)(dstrect->x + dstrect->w); | |
1115 vertices[7] = (GLfloat)(dstrect->y + dstrect->h); | |
1116 glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); | |
1117 texCoords[0] = srcrect->x / (GLfloat)texture->w; | |
1118 texCoords[1] = srcrect->y / (GLfloat)texture->h; | |
1119 texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; | |
1120 texCoords[3] = srcrect->y / (GLfloat)texture->h; | |
1121 texCoords[4] = srcrect->x / (GLfloat)texture->w; | |
1122 texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; | |
1123 texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; | |
1124 texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; | |
1125 glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords); | |
1126 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
1127 glDisableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); | |
1128 glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); | |
1129 if (glGetError() != GL_NO_ERROR) | |
1130 { | |
1131 SDL_SetError("Failed to render texture"); | |
1132 return -1; | |
1133 } | |
1134 return 0; | |
1135 } | |
1136 | |
1137 static void | |
1138 GLES2_RenderPresent(SDL_Renderer *renderer) | |
1139 { | |
1140 GLES2_ActivateRenderer(renderer); | |
1141 | |
1142 /* Tell the video driver to swap buffers */ | |
1143 SDL_GL_SwapWindow(renderer->window); | |
1144 } | |
1145 | |
1146 /************************************************************************************************* | |
1147 * Renderer instantiation * | |
1148 *************************************************************************************************/ | |
1149 | |
1150 #define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B | |
1151 | |
1152 static SDL_Renderer * | |
1153 GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) | |
1154 { | |
1155 SDL_Renderer *renderer; | |
1156 GLES2_DriverContext *rdata; | |
1157 GLint nFormats; | |
1158 #ifndef ZUNE_HD | |
1159 GLboolean hasCompiler; | |
1160 #endif | |
1161 | |
1162 /* Create the renderer struct */ | |
1163 renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer)); | |
1164 rdata = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext)); | |
1165 if (!renderer) | |
1166 { | |
1167 SDL_OutOfMemory(); | |
1168 SDL_free(renderer); | |
1169 SDL_free(rdata); | |
1170 return NULL; | |
1171 } | |
1172 renderer->info = GLES2_RenderDriver.info; | |
1173 renderer->window = window; | |
1174 renderer->driverdata = rdata; | |
1175 | |
1176 /* Create the GL context */ | |
1177 rdata->context = SDL_GL_CreateContext(window); | |
1178 if (!rdata->context) | |
1179 { | |
1180 SDL_free(renderer); | |
1181 SDL_free(rdata); | |
1182 return NULL; | |
1183 } | |
1184 | |
1185 /* Determine supported shader formats */ | |
1186 /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */ | |
1187 glGetError(); | |
1188 #ifdef ZUNE_HD | |
1189 nFormats = 1; | |
1190 #else /* !ZUNE_HD */ | |
1191 glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats); | |
1192 glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler); | |
1193 if (hasCompiler) | |
1194 ++nFormats; | |
1195 #endif /* ZUNE_HD */ | |
1196 rdata->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum)); | |
1197 if (!rdata->shader_formats) | |
1198 { | |
1199 SDL_OutOfMemory(); | |
1200 SDL_free(renderer); | |
1201 SDL_free(rdata); | |
1202 return NULL; | |
1203 } | |
1204 rdata->shader_format_count = nFormats; | |
1205 #ifdef ZUNE_HD | |
1206 rdata->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV; | |
1207 #else /* !ZUNE_HD */ | |
1208 glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)rdata->shader_formats); | |
1209 if (glGetError() != GL_NO_ERROR) | |
1210 { | |
1211 SDL_SetError("Failed to query supported shader formats"); | |
1212 SDL_free(renderer); | |
1213 SDL_free(rdata->shader_formats); | |
1214 SDL_free(rdata); | |
1215 return NULL; | |
1216 } | |
1217 if (hasCompiler) | |
1218 rdata->shader_formats[nFormats - 1] = (GLenum)-1; | |
1219 #endif /* ZUNE_HD */ | |
1220 | |
1221 /* Populate the function pointers for the module */ | |
1222 renderer->WindowEvent = &GLES2_WindowEvent; | |
1223 renderer->CreateTexture = &GLES2_CreateTexture; | |
1224 renderer->UpdateTexture = &GLES2_UpdateTexture; | |
1225 renderer->LockTexture = &GLES2_LockTexture; | |
1226 renderer->UnlockTexture = &GLES2_UnlockTexture; | |
1227 renderer->RenderClear = &GLES2_RenderClear; | |
1228 renderer->RenderDrawPoints = &GLES2_RenderDrawPoints; | |
1229 renderer->RenderDrawLines = &GLES2_RenderDrawLines; | |
1230 renderer->RenderFillRects = &GLES2_RenderFillRects; | |
1231 renderer->RenderCopy = &GLES2_RenderCopy; | |
1232 renderer->RenderPresent = &GLES2_RenderPresent; | |
1233 renderer->DestroyTexture = &GLES2_DestroyTexture; | |
1234 renderer->DestroyRenderer = &GLES2_DestroyRenderer; | |
1235 return renderer; | |
1236 } | |
1237 | |
1238 #endif /* SDL_VIDEO_RENDER_OGL_ES2 */ | |
1239 | |
1240 /* vi: set ts=4 sw=4 expandtab: */ |