comparison src/video/SDL_renderer_sw.c @ 1895:c121d94672cb

SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 10 Jul 2006 21:04:37 +0000
parents
children c2a27da60b18
comparison
equal deleted inserted replaced
1894:c69cee13dd76 1895:c121d94672cb
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #include "SDL_video.h"
25 #include "SDL_sysvideo.h"
26 #include "SDL_rect_c.h"
27 #include "SDL_yuv_sw_c.h"
28
29
30 /* SDL surface based renderer implementation */
31
32 static SDL_Renderer *SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags);
33 static int SDL_SW_CreateTexture(SDL_Renderer * renderer,
34 SDL_Texture * texture);
35 static int SDL_SW_QueryTexturePixels(SDL_Renderer * renderer,
36 SDL_Texture * texture, void **pixels,
37 int *pitch);
38 static int SDL_SW_SetTexturePalette(SDL_Renderer * renderer,
39 SDL_Texture * texture,
40 const SDL_Color * colors, int firstcolor,
41 int ncolors);
42 static int SDL_SW_GetTexturePalette(SDL_Renderer * renderer,
43 SDL_Texture * texture, SDL_Color * colors,
44 int firstcolor, int ncolors);
45 static int SDL_SW_UpdateTexture(SDL_Renderer * renderer,
46 SDL_Texture * texture, const SDL_Rect * rect,
47 const void *pixels, int pitch);
48 static int SDL_SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
49 const SDL_Rect * rect, int markDirty,
50 void **pixels, int *pitch);
51 static void SDL_SW_UnlockTexture(SDL_Renderer * renderer,
52 SDL_Texture * texture);
53 static void SDL_SW_DirtyTexture(SDL_Renderer * renderer,
54 SDL_Texture * texture, int numrects,
55 const SDL_Rect * rects);
56 static void SDL_SW_SelectRenderTexture(SDL_Renderer * renderer,
57 SDL_Texture * texture);
58 static int SDL_SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
59 Uint32 color);
60 static int SDL_SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
61 const SDL_Rect * srcrect,
62 const SDL_Rect * dstrect, int blendMode,
63 int scaleMode);
64 static int SDL_SW_RenderReadPixels(SDL_Renderer * renderer,
65 const SDL_Rect * rect, void *pixels,
66 int pitch);
67 static int SDL_SW_RenderWritePixels(SDL_Renderer * renderer,
68 const SDL_Rect * rect, const void *pixels,
69 int pitch);
70 static void SDL_SW_RenderPresent(SDL_Renderer * renderer);
71 static void SDL_SW_DestroyTexture(SDL_Renderer * renderer,
72 SDL_Texture * texture);
73 static void SDL_SW_DestroyRenderer(SDL_Renderer * renderer);
74
75
76 SDL_RenderDriver SDL_SW_RenderDriver = {
77 SDL_SW_CreateRenderer,
78 {
79 "software",
80 (SDL_Renderer_PresentDiscard |
81 SDL_Renderer_PresentCopy |
82 SDL_Renderer_PresentFlip2 |
83 SDL_Renderer_PresentFlip3 | SDL_Renderer_RenderTarget),
84 (SDL_TextureBlendMode_None |
85 SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),
86 (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),
87 11,
88 {
89 SDL_PixelFormat_Index8,
90 SDL_PixelFormat_RGB555,
91 SDL_PixelFormat_RGB565,
92 SDL_PixelFormat_RGB888,
93 SDL_PixelFormat_BGR888,
94 SDL_PixelFormat_ARGB8888,
95 SDL_PixelFormat_RGBA8888,
96 SDL_PixelFormat_ABGR8888,
97 SDL_PixelFormat_BGRA8888,
98 SDL_PixelFormat_YUY2,
99 SDL_PixelFormat_UYVY},
100 0,
101 0}
102 };
103
104 typedef struct
105 {
106 int current_screen;
107 SDL_Surface *screens[3];
108 SDL_Surface *target;
109 SDL_Renderer *renderer;
110 SDL_DirtyRectList dirty;
111 } SDL_SW_RenderData;
112
113 SDL_Renderer *
114 SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags)
115 {
116 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
117 SDL_DisplayMode *displayMode = &display->current_mode;
118 SDL_Renderer *renderer;
119 SDL_SW_RenderData *data;
120 int i, n;
121 int bpp;
122 Uint32 Rmask, Gmask, Bmask, Amask;
123
124 if (!SDL_PixelFormatEnumToMasks
125 (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
126 SDL_SetError("Unknown display format");
127 return NULL;
128 }
129
130 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
131 if (!renderer) {
132 SDL_OutOfMemory();
133 return NULL;
134 }
135
136 data = (SDL_SW_RenderData *) SDL_malloc(sizeof(*data));
137 if (!data) {
138 SDL_SW_DestroyRenderer(renderer);
139 SDL_OutOfMemory();
140 return NULL;
141 }
142 SDL_zerop(data);
143
144 renderer->CreateTexture = SDL_SW_CreateTexture;
145 renderer->QueryTexturePixels = SDL_SW_QueryTexturePixels;
146 renderer->SetTexturePalette = SDL_SW_SetTexturePalette;
147 renderer->GetTexturePalette = SDL_SW_GetTexturePalette;
148 renderer->UpdateTexture = SDL_SW_UpdateTexture;
149 renderer->LockTexture = SDL_SW_LockTexture;
150 renderer->UnlockTexture = SDL_SW_UnlockTexture;
151 renderer->DirtyTexture = SDL_SW_DirtyTexture;
152 renderer->SelectRenderTexture = SDL_SW_SelectRenderTexture;
153 renderer->RenderFill = SDL_SW_RenderFill;
154 renderer->RenderCopy = SDL_SW_RenderCopy;
155 renderer->RenderReadPixels = SDL_SW_RenderReadPixels;
156 renderer->RenderWritePixels = SDL_SW_RenderWritePixels;
157 renderer->RenderPresent = SDL_SW_RenderPresent;
158 renderer->DestroyTexture = SDL_SW_DestroyTexture;
159 renderer->DestroyRenderer = SDL_SW_DestroyRenderer;
160 renderer->info = SDL_SW_RenderDriver.info;
161 renderer->window = window->id;
162 renderer->driverdata = data;
163
164 renderer->info.flags = SDL_Renderer_RenderTarget;
165
166 if (flags & SDL_Renderer_PresentFlip2) {
167 renderer->info.flags |= SDL_Renderer_PresentFlip2;
168 n = 2;
169 } else if (flags & SDL_Renderer_PresentFlip3) {
170 renderer->info.flags |= SDL_Renderer_PresentFlip3;
171 n = 3;
172 } else {
173 renderer->info.flags |= SDL_Renderer_PresentCopy;
174 n = 1;
175 }
176 for (i = 0; i < n; ++i) {
177 data->screens[i] =
178 SDL_CreateRGBSurface(0, window->w, window->h, bpp, Rmask, Gmask,
179 Bmask, Amask);
180 if (!data->screens[i]) {
181 SDL_SW_DestroyRenderer(renderer);
182 return NULL;
183 }
184 SDL_SetSurfacePalette(data->screens[i], display->palette);
185 }
186 data->current_screen = 0;
187 data->target = data->screens[0];
188
189 /* Find a render driver that we can use to display data */
190 for (i = 0; i < display->num_render_drivers; ++i) {
191 SDL_RenderDriver *driver = &display->render_drivers[i];
192 if (driver->info.name != SDL_SW_RenderDriver.info.name) {
193 data->renderer =
194 driver->CreateRenderer(window, SDL_Renderer_PresentDiscard);
195 if (data->renderer) {
196 break;
197 }
198 }
199 }
200 if (i == display->num_render_drivers) {
201 SDL_SW_DestroyRenderer(renderer);
202 SDL_SetError("Couldn't find display render driver");
203 return NULL;
204 }
205 return renderer;
206 }
207
208 static int
209 SDL_SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
210 {
211 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
212 if (texture->access == SDL_TextureAccess_Render) {
213 SDL_SetError("Rendering to YUV format textures is not supported");
214 return -1;
215 }
216 texture->driverdata = SDL_SW_CreateYUVTexture(texture);
217 } else {
218 int bpp;
219 Uint32 Rmask, Gmask, Bmask, Amask;
220
221 if (!SDL_PixelFormatEnumToMasks
222 (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
223 SDL_SetError("Unknown texture format");
224 return -1;
225 }
226
227 texture->driverdata =
228 SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
229 Bmask, Amask);
230 }
231
232 if (!texture->driverdata) {
233 return -1;
234 }
235 return 0;
236 }
237
238 static int
239 SDL_SW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
240 void **pixels, int *pitch)
241 {
242 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
243 return SDL_SW_QueryYUVTexturePixels((SDL_SW_YUVTexture *) texture->
244 driverdata, pixels, pitch);
245 } else {
246 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
247
248 *pixels = surface->pixels;
249 *pitch = surface->pitch;
250 return 0;
251 }
252 }
253
254 static int
255 SDL_SW_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
256 const SDL_Color * colors, int firstcolor,
257 int ncolors)
258 {
259 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
260 SDL_SetError("YUV textures don't have a palette");
261 return -1;
262 } else {
263 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
264
265 return SDL_SetPaletteColors(surface->format->palette, colors,
266 firstcolor, ncolors);
267 }
268 }
269
270 static int
271 SDL_SW_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
272 SDL_Color * colors, int firstcolor, int ncolors)
273 {
274 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
275 SDL_SetError("YUV textures don't have a palette");
276 return -1;
277 } else {
278 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
279
280 SDL_memcpy(colors, &surface->format->palette->colors[firstcolor],
281 ncolors * sizeof(*colors));
282 return 0;
283 }
284 }
285
286 static int
287 SDL_SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
288 const SDL_Rect * rect, const void *pixels, int pitch)
289 {
290 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
291 return SDL_SW_UpdateYUVTexture((SDL_SW_YUVTexture *) texture->
292 driverdata, rect, pixels, pitch);
293 } else {
294 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
295 Uint8 *src, *dst;
296 int row;
297 size_t length;
298
299 src = (Uint8 *) pixels;
300 dst =
301 (Uint8 *) surface->pixels + rect->y * surface->pitch +
302 rect->x * surface->format->BytesPerPixel;
303 length = rect->w * surface->format->BytesPerPixel;
304 for (row = 0; row < rect->h; ++row) {
305 SDL_memcpy(dst, src, length);
306 src += pitch;
307 dst += surface->pitch;
308 }
309 return 0;
310 }
311 }
312
313 static int
314 SDL_SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
315 const SDL_Rect * rect, int markDirty, void **pixels,
316 int *pitch)
317 {
318 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
319 return SDL_SW_LockYUVTexture((SDL_SW_YUVTexture *) texture->
320 driverdata, rect, markDirty, pixels,
321 pitch);
322 } else {
323 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
324
325 *pixels =
326 (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
327 rect->x * surface->format->BytesPerPixel);
328 *pitch = surface->pitch;
329 return 0;
330 }
331 }
332
333 static void
334 SDL_SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
335 {
336 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
337 SDL_SW_UnlockYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
338 }
339 }
340
341 static void
342 SDL_SW_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
343 int numrects, const SDL_Rect * rects)
344 {
345 }
346
347 static void
348 SDL_SW_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture)
349 {
350 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
351
352 if (texture) {
353 data->target = (SDL_Surface *) texture->driverdata;
354 } else {
355 data->target = data->screens[data->current_screen];
356 }
357 }
358
359 static int
360 SDL_SW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
361 Uint32 color)
362 {
363 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
364 SDL_Rect real_rect = *rect;
365 Uint8 r, g, b, a;
366
367 SDL_AddDirtyRect(&data->dirty, rect);
368
369 a = (Uint8) ((color >> 24) & 0xFF);
370 r = (Uint8) ((color >> 16) & 0xFF);
371 g = (Uint8) ((color >> 8) & 0xFF);
372 b = (Uint8) (color & 0xFF);
373 color = SDL_MapRGBA(data->target->format, r, g, b, a);
374
375 return SDL_FillRect(data->target, &real_rect, color);
376 }
377
378 static int
379 SDL_SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
380 const SDL_Rect * srcrect, const SDL_Rect * dstrect,
381 int blendMode, int scaleMode)
382 {
383 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
384 SDL_Window *window = SDL_GetWindowFromID(renderer->window);
385 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
386
387 SDL_AddDirtyRect(&data->dirty, dstrect);
388
389 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
390 SDL_Surface *target = data->target;
391 void *pixels =
392 (Uint8 *) target->pixels + dstrect->y * target->pitch +
393 dstrect->x * target->format->BytesPerPixel;
394 return SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata,
395 srcrect, display->current_mode.format,
396 dstrect->w, dstrect->h, pixels,
397 target->pitch);
398 } else {
399 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
400 SDL_Rect real_srcrect = *srcrect;
401 SDL_Rect real_dstrect = *dstrect;
402
403 if (blendMode &
404 (SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend)) {
405 SDL_SetAlpha(surface, SDL_SRCALPHA, 0);
406 } else {
407 SDL_SetAlpha(surface, 0, 0);
408 }
409 if (scaleMode != SDL_TextureScaleMode_None &&
410 (srcrect->w != dstrect->w || srcrect->h != dstrect->h)) {
411 return SDL_SoftStretch(surface, &real_srcrect, data->target,
412 &real_dstrect);
413 } else {
414 return SDL_LowerBlit(surface, &real_srcrect, data->target,
415 &real_dstrect);
416 }
417 }
418 }
419
420 static int
421 SDL_SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
422 void *pixels, int pitch)
423 {
424 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
425 SDL_Surface *surface = data->target;
426 Uint8 *src, *dst;
427 int row;
428 size_t length;
429
430 src =
431 (Uint8 *) surface->pixels + rect->y * surface->pitch +
432 rect->x * surface->format->BytesPerPixel;
433 dst = (Uint8 *) pixels;
434 length = rect->w * surface->format->BytesPerPixel;
435 for (row = 0; row < rect->h; ++row) {
436 SDL_memcpy(dst, src, length);
437 src += surface->pitch;
438 dst += pitch;
439 }
440 return 0;
441 }
442
443 static int
444 SDL_SW_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
445 const void *pixels, int pitch)
446 {
447 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
448 SDL_Surface *surface = data->target;
449 Uint8 *src, *dst;
450 int row;
451 size_t length;
452
453 SDL_AddDirtyRect(&data->dirty, rect);
454
455 src = (Uint8 *) pixels;
456 dst =
457 (Uint8 *) surface->pixels + rect->y * surface->pitch +
458 rect->x * surface->format->BytesPerPixel;
459 length = rect->w * surface->format->BytesPerPixel;
460 for (row = 0; row < rect->h; ++row) {
461 SDL_memcpy(dst, src, length);
462 src += pitch;
463 dst += surface->pitch;
464 }
465 return 0;
466 }
467
468 static void
469 SDL_SW_RenderPresent(SDL_Renderer * renderer)
470 {
471 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
472 SDL_Surface *surface = data->screens[data->current_screen];
473 SDL_DirtyRect *dirty;
474 int new_screen;
475
476 /* Send the data to the display */
477 for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
478 void *pixels =
479 (void *) ((Uint8 *) surface->pixels +
480 dirty->rect.y * surface->pitch +
481 dirty->rect.x * surface->format->BytesPerPixel);
482 data->renderer->RenderWritePixels(data->renderer, &dirty->rect,
483 pixels, surface->pitch);
484 }
485 SDL_ClearDirtyRects(&data->dirty);
486 data->renderer->RenderPresent(data->renderer);
487
488
489 /* Update the flipping chain, if any */
490 if (renderer->info.flags & SDL_Renderer_PresentFlip2) {
491 new_screen = (data->current_screen + 1) % 2;
492 } else if (renderer->info.flags & SDL_Renderer_PresentFlip3) {
493 new_screen = (data->current_screen + 1) % 3;
494 } else {
495 new_screen = 0;
496 }
497 if (data->target == data->screens[data->current_screen]) {
498 data->target = data->screens[new_screen];
499 }
500 data->current_screen = new_screen;
501 }
502
503 static void
504 SDL_SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
505 {
506 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
507 SDL_SW_DestroyYUVTexture((SDL_SW_YUVTexture *) texture->driverdata);
508 } else {
509 SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
510
511 SDL_FreeSurface(surface);
512 }
513 }
514
515 static void
516 SDL_SW_DestroyRenderer(SDL_Renderer * renderer)
517 {
518 SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata;
519 int i;
520
521 if (data) {
522 for (i = 0; i < SDL_arraysize(data->screens); ++i) {
523 if (data->screens[i]) {
524 SDL_FreeSurface(data->screens[i]);
525 }
526 }
527 SDL_FreeDirtyRects(&data->dirty);
528 SDL_free(data);
529 }
530 SDL_free(renderer);
531 }
532
533 /* vi: set ts=4 sw=4 expandtab: */