comparison src/render/software/SDL_renderer_sw.c @ 5169:4d39eeaad00b

Added a way to get a framebuffer interface for a window, and also a way to create a software renderer for an arbitrary surface. The software renderer has been re-routed to use the framebuffer interface, which makes it possible to have software rendering available even on simple ports.
author Sam Lantinga <slouken@libsdl.org>
date Thu, 03 Feb 2011 15:49:37 -0800
parents d72793305335
children
comparison
equal deleted inserted replaced
5168:2b1989f59674 5169:4d39eeaad00b
67 67
68 SDL_RenderDriver SW_RenderDriver = { 68 SDL_RenderDriver SW_RenderDriver = {
69 SW_CreateRenderer, 69 SW_CreateRenderer,
70 { 70 {
71 "software", 71 "software",
72 (SDL_RENDERER_PRESENTVSYNC), 72 0,
73 8, 73 8,
74 { 74 {
75 SDL_PIXELFORMAT_RGB555, 75 SDL_PIXELFORMAT_RGB555,
76 SDL_PIXELFORMAT_RGB565, 76 SDL_PIXELFORMAT_RGB565,
77 SDL_PIXELFORMAT_RGB888, 77 SDL_PIXELFORMAT_RGB888,
85 0} 85 0}
86 }; 86 };
87 87
88 typedef struct 88 typedef struct
89 { 89 {
90 Uint32 format;
91 SDL_bool updateSize; 90 SDL_bool updateSize;
92 SDL_Texture *texture; 91 SDL_Surface *surface;
93 SDL_Surface surface;
94 SDL_Renderer *renderer;
95 } SW_RenderData; 92 } SW_RenderData;
96 93
97 static SDL_Texture *
98 CreateTexture(SDL_Renderer * renderer, Uint32 format, int w, int h)
99 {
100 SDL_Texture *texture;
101
102 texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
103 if (!texture) {
104 SDL_OutOfMemory();
105 return NULL;
106 }
107
108 texture->format = format;
109 texture->access = SDL_TEXTUREACCESS_STREAMING;
110 texture->w = w;
111 texture->h = h;
112 texture->renderer = renderer;
113
114 if (renderer->CreateTexture(renderer, texture) < 0) {
115 SDL_free(texture);
116 return NULL;
117 }
118 return texture;
119 }
120
121 static void
122 DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
123 {
124 renderer->DestroyTexture(renderer, texture);
125 SDL_free(texture);
126 }
127 94
128 SDL_Renderer * 95 SDL_Renderer *
129 SW_CreateRenderer(SDL_Window * window, Uint32 flags) 96 SW_CreateRendererForSurface(SDL_Surface * surface)
130 { 97 {
131 SDL_Renderer *renderer; 98 SDL_Renderer *renderer;
132 SW_RenderData *data; 99 SW_RenderData *data;
133 int i; 100
134 int w, h; 101 if (!surface) {
135 Uint32 format; 102 SDL_SetError("Can't create renderer for NULL surface");
136 int bpp;
137 Uint32 Rmask, Gmask, Bmask, Amask;
138 Uint32 renderer_flags;
139 const char *desired_driver;
140
141 format = SDL_GetWindowPixelFormat(window);
142 if (!SDL_PixelFormatEnumToMasks
143 (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
144 SDL_SetError("Unknown display format");
145 return NULL; 103 return NULL;
146 } 104 }
147 105
148 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); 106 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
149 if (!renderer) { 107 if (!renderer) {
155 if (!data) { 113 if (!data) {
156 SW_DestroyRenderer(renderer); 114 SW_DestroyRenderer(renderer);
157 SDL_OutOfMemory(); 115 SDL_OutOfMemory();
158 return NULL; 116 return NULL;
159 } 117 }
118 data->surface = surface;
119
160 renderer->WindowEvent = SW_WindowEvent; 120 renderer->WindowEvent = SW_WindowEvent;
161 renderer->CreateTexture = SW_CreateTexture; 121 renderer->CreateTexture = SW_CreateTexture;
162 renderer->SetTextureColorMod = SW_SetTextureColorMod; 122 renderer->SetTextureColorMod = SW_SetTextureColorMod;
163 renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod; 123 renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
164 renderer->SetTextureBlendMode = SW_SetTextureBlendMode; 124 renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
172 renderer->RenderCopy = SW_RenderCopy; 132 renderer->RenderCopy = SW_RenderCopy;
173 renderer->RenderReadPixels = SW_RenderReadPixels; 133 renderer->RenderReadPixels = SW_RenderReadPixels;
174 renderer->RenderPresent = SW_RenderPresent; 134 renderer->RenderPresent = SW_RenderPresent;
175 renderer->DestroyRenderer = SW_DestroyRenderer; 135 renderer->DestroyRenderer = SW_DestroyRenderer;
176 renderer->info = SW_RenderDriver.info; 136 renderer->info = SW_RenderDriver.info;
177 renderer->info.flags = 0;
178 renderer->window = window;
179 renderer->driverdata = data; 137 renderer->driverdata = data;
180 138
181 data->format = format; 139 return renderer;
182 140 }
183 /* Find a render driver that we can use to display data */ 141
184 renderer_flags = 0; 142 SDL_Renderer *
185 if (flags & SDL_RENDERER_PRESENTVSYNC) { 143 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
186 renderer_flags |= SDL_RENDERER_PRESENTVSYNC; 144 {
187 } 145 SDL_Surface *surface;
188 desired_driver = SDL_getenv("SDL_VIDEO_RENDERER_SWDRIVER"); 146
189 for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { 147 surface = SDL_GetWindowSurface(window);
190 SDL_RendererInfo info; 148 if (!surface) {
191 SDL_GetRenderDriverInfo(i, &info);
192 if (SDL_strcmp(info.name, SW_RenderDriver.info.name) == 0) {
193 continue;
194 }
195 if (desired_driver
196 && SDL_strcasecmp(desired_driver, info.name) != 0) {
197 continue;
198 }
199 data->renderer = SDL_CreateRenderer(window, i, renderer_flags);
200 if (data->renderer) {
201 break;
202 }
203 }
204 if (i == SDL_GetNumRenderDrivers()) {
205 SW_DestroyRenderer(renderer);
206 SDL_SetError("Couldn't find display render driver");
207 return NULL; 149 return NULL;
208 } 150 }
209 if (data->renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { 151 return SW_CreateRendererForSurface(surface);
210 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; 152 }
211 } 153
212 154 static SDL_Surface *
213 /* Create the textures we'll use for display */
214 SDL_GetWindowSize(window, &w, &h);
215 data->texture = CreateTexture(data->renderer, data->format, w, h);
216 if (!data->texture) {
217 SW_DestroyRenderer(renderer);
218 return NULL;
219 }
220
221 /* Create a surface we'll use for rendering */
222 data->surface.flags = SDL_PREALLOC;
223 data->surface.format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
224 if (!data->surface.format) {
225 SW_DestroyRenderer(renderer);
226 return NULL;
227 }
228
229 return renderer;
230 }
231
232 static SDL_Texture *
233 SW_ActivateRenderer(SDL_Renderer * renderer) 155 SW_ActivateRenderer(SDL_Renderer * renderer)
234 { 156 {
235 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 157 SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
236 SDL_Window *window = renderer->window; 158 SDL_Window *window = renderer->window;
237 159
238 if (data->updateSize) { 160 if (data->updateSize) {
239 /* Recreate the textures for the new window size */ 161 data->surface = SDL_GetWindowSurface(window);
240 int w, h; 162 data->updateSize = SDL_FALSE;
241 if (data->texture) { 163 }
242 DestroyTexture(data->renderer, data->texture); 164 return data->surface;
243 }
244 SDL_GetWindowSize(window, &w, &h);
245 data->texture = CreateTexture(data->renderer, data->format, w, h);
246 if (data->texture) {
247 data->updateSize = SDL_FALSE;
248 }
249 }
250 return data->texture;
251 } 165 }
252 166
253 static void 167 static void
254 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 168 SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
255 { 169 {
354 268
355 static int 269 static int
356 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, 270 SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
357 int count) 271 int count)
358 { 272 {
359 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 273 SDL_Surface *surface = SW_ActivateRenderer(renderer);
360 SDL_Texture *texture = SW_ActivateRenderer(renderer); 274
361 SDL_Rect rect; 275 if (!surface) {
362 int i; 276 return -1;
363 int x, y; 277 }
364 int status = 0;
365
366 if (!texture) {
367 return -1;
368 }
369
370 /* Get the smallest rectangle that contains everything */
371 rect.x = 0;
372 rect.y = 0;
373 rect.w = texture->w;
374 rect.h = texture->h;
375 if (!SDL_EnclosePoints(points, count, &rect, &rect)) {
376 /* Nothing to draw */
377 return 0;
378 }
379
380 if (data->renderer->LockTexture(data->renderer, texture, &rect,
381 &data->surface.pixels,
382 &data->surface.pitch) < 0) {
383 return -1;
384 }
385
386 data->surface.clip_rect.w = data->surface.w = rect.w;
387 data->surface.clip_rect.h = data->surface.h = rect.h;
388 278
389 /* Draw the points! */ 279 /* Draw the points! */
390 if (renderer->blendMode == SDL_BLENDMODE_NONE) { 280 if (renderer->blendMode == SDL_BLENDMODE_NONE) {
391 Uint32 color = SDL_MapRGBA(data->surface.format, 281 Uint32 color = SDL_MapRGBA(surface->format,
392 renderer->r, renderer->g, renderer->b, 282 renderer->r, renderer->g, renderer->b,
393 renderer->a); 283 renderer->a);
394 284
395 for (i = 0; i < count; ++i) { 285 return SDL_DrawPoints(surface, points, count, color);
396 x = points[i].x - rect.x;
397 y = points[i].y - rect.y;
398
399 status = SDL_DrawPoint(&data->surface, x, y, color);
400 }
401 } else { 286 } else {
402 for (i = 0; i < count; ++i) { 287 return SDL_BlendPoints(surface, points, count,
403 x = points[i].x - rect.x; 288 renderer->blendMode,
404 y = points[i].y - rect.y; 289 renderer->r, renderer->g, renderer->b,
405 290 renderer->a);
406 status = SDL_BlendPoint(&data->surface, x, y, 291 }
407 renderer->blendMode,
408 renderer->r, renderer->g, renderer->b,
409 renderer->a);
410 }
411 }
412
413 data->renderer->UnlockTexture(data->renderer, texture);
414
415 return status;
416 } 292 }
417 293
418 static int 294 static int
419 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, 295 SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
420 int count) 296 int count)
421 { 297 {
422 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 298 SDL_Surface *surface = SW_ActivateRenderer(renderer);
423 SDL_Texture *texture = SW_ActivateRenderer(renderer); 299
424 SDL_Rect clip, rect; 300 if (!surface) {
425 int i; 301 return -1;
426 int x1, y1, x2, y2; 302 }
427 int status = 0; 303
428 304 /* Draw the lines! */
429 if (!texture) {
430 return -1;
431 }
432
433 /* Get the smallest rectangle that contains everything */
434 clip.x = 0;
435 clip.y = 0;
436 clip.w = texture->w;
437 clip.h = texture->h;
438 SDL_EnclosePoints(points, count, NULL, &rect);
439 if (!SDL_IntersectRect(&rect, &clip, &rect)) {
440 /* Nothing to draw */
441 return 0;
442 }
443
444 if (data->renderer->LockTexture(data->renderer, texture, &rect,
445 &data->surface.pixels,
446 &data->surface.pitch) < 0) {
447 return -1;
448 }
449
450 data->surface.clip_rect.w = data->surface.w = rect.w;
451 data->surface.clip_rect.h = data->surface.h = rect.h;
452
453 /* Draw the points! */
454 if (renderer->blendMode == SDL_BLENDMODE_NONE) { 305 if (renderer->blendMode == SDL_BLENDMODE_NONE) {
455 Uint32 color = SDL_MapRGBA(data->surface.format, 306 Uint32 color = SDL_MapRGBA(surface->format,
456 renderer->r, renderer->g, renderer->b, 307 renderer->r, renderer->g, renderer->b,
457 renderer->a); 308 renderer->a);
458 309
459 for (i = 1; i < count; ++i) { 310 return SDL_DrawLines(surface, points, count, color);
460 x1 = points[i-1].x - rect.x;
461 y1 = points[i-1].y - rect.y;
462 x2 = points[i].x - rect.x;
463 y2 = points[i].y - rect.y;
464
465 status = SDL_DrawLine(&data->surface, x1, y1, x2, y2, color);
466 }
467 } else { 311 } else {
468 for (i = 1; i < count; ++i) { 312 return SDL_BlendLines(surface, points, count,
469 x1 = points[i-1].x - rect.x; 313 renderer->blendMode,
470 y1 = points[i-1].y - rect.y; 314 renderer->r, renderer->g, renderer->b,
471 x2 = points[i].x - rect.x; 315 renderer->a);
472 y2 = points[i].y - rect.y; 316 }
473 317 }
474 status = SDL_BlendLine(&data->surface, x1, y1, x2, y2, 318
475 renderer->blendMode, 319 static int
320 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
321 int count)
322 {
323 SDL_Surface *surface = SW_ActivateRenderer(renderer);
324
325 if (!surface) {
326 return -1;
327 }
328
329 if (renderer->blendMode == SDL_BLENDMODE_NONE) {
330 Uint32 color = SDL_MapRGBA(surface->format,
476 renderer->r, renderer->g, renderer->b, 331 renderer->r, renderer->g, renderer->b,
477 renderer->a); 332 renderer->a);
478 } 333 return SDL_FillRects(surface, rects, count, color);
479 } 334 } else {
480 335 return SDL_BlendFillRects(surface, rects, count,
481 data->renderer->UnlockTexture(data->renderer, texture); 336 renderer->blendMode,
482 337 renderer->r, renderer->g, renderer->b,
483 return status; 338 renderer->a);
484 } 339 }
485
486 static int
487 SW_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
488 int count)
489 {
490 SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
491 SDL_Texture *texture = SW_ActivateRenderer(renderer);
492 SDL_Rect clip, rect;
493 Uint32 color = 0;
494 int i;
495 int status = 0;
496
497 if (!texture) {
498 return -1;
499 }
500
501 clip.x = 0;
502 clip.y = 0;
503 clip.w = texture->w;
504 clip.h = texture->h;
505
506 if (renderer->blendMode == SDL_BLENDMODE_NONE) {
507 color = SDL_MapRGBA(data->surface.format,
508 renderer->r, renderer->g, renderer->b,
509 renderer->a);
510 }
511
512 for (i = 0; i < count; ++i) {
513 if (!SDL_IntersectRect(rects[i], &clip, &rect)) {
514 /* Nothing to draw */
515 continue;
516 }
517
518 if (data->renderer->LockTexture(data->renderer, texture, &rect,
519 &data->surface.pixels,
520 &data->surface.pitch) < 0) {
521 return -1;
522 }
523
524 data->surface.clip_rect.w = data->surface.w = rect.w;
525 data->surface.clip_rect.h = data->surface.h = rect.h;
526
527 if (renderer->blendMode == SDL_BLENDMODE_NONE) {
528 status = SDL_FillRect(&data->surface, NULL, color);
529 } else {
530 status = SDL_BlendFillRect(&data->surface, NULL,
531 renderer->blendMode,
532 renderer->r, renderer->g, renderer->b,
533 renderer->a);
534 }
535
536 data->renderer->UnlockTexture(data->renderer, texture);
537 }
538 return status;
539 } 340 }
540 341
541 static int 342 static int
542 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 343 SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
543 const SDL_Rect * srcrect, const SDL_Rect * dstrect) 344 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
544 { 345 {
545 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 346 SDL_Surface *surface = SW_ActivateRenderer(renderer);
546 SDL_Surface *surface; 347 SDL_Surface *src = (SDL_Surface *) texture->driverdata;
547 SDL_Rect real_srcrect; 348 SDL_Rect final_rect = *dstrect;
548 SDL_Rect real_dstrect; 349
549 int status; 350 if (!surface) {
550 351 return -1;
551 if (!SW_ActivateRenderer(renderer)) { 352 }
552 return -1; 353 return SDL_BlitSurface(src, srcrect, surface, &final_rect);
553 }
554
555 if (data->renderer->LockTexture(data->renderer, data->texture, dstrect,
556 &data->surface.pixels,
557 &data->surface.pitch) < 0) {
558 return -1;
559 }
560
561 surface = (SDL_Surface *) texture->driverdata;
562 real_srcrect = *srcrect;
563
564 data->surface.w = dstrect->w;
565 data->surface.h = dstrect->h;
566 data->surface.clip_rect.w = dstrect->w;
567 data->surface.clip_rect.h = dstrect->h;
568 real_dstrect = data->surface.clip_rect;
569
570 status = SDL_LowerBlit(surface, &real_srcrect, &data->surface, &real_dstrect);
571 data->renderer->UnlockTexture(data->renderer, data->texture);
572 return status;
573 } 354 }
574 355
575 static int 356 static int
576 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 357 SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
577 Uint32 format, void * pixels, int pitch) 358 Uint32 format, void * pixels, int pitch)
578 { 359 {
579 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 360 SDL_Surface *surface = SW_ActivateRenderer(renderer);
580 361 Uint32 src_format;
581 if (!SW_ActivateRenderer(renderer)) { 362 void *src_pixels;
582 return -1; 363
583 } 364 if (!surface) {
584 365 return -1;
585 if (data->renderer->LockTexture(data->renderer, data->texture, rect, 366 }
586 &data->surface.pixels, 367
587 &data->surface.pitch) < 0) { 368 if (rect->x < 0 || rect->x+rect->w > surface->w ||
588 return -1; 369 rect->y < 0 || rect->y+rect->h > surface->h) {
589 } 370 SDL_SetError("Tried to read outside of surface bounds");
590 371 return -1;
591 SDL_ConvertPixels(rect->w, rect->h, 372 }
592 data->format, data->surface.pixels, data->surface.pitch, 373
593 format, pixels, pitch); 374 src_format = SDL_MasksToPixelFormatEnum(
594 375 surface->format->BitsPerPixel,
595 data->renderer->UnlockTexture(data->renderer, data->texture); 376 surface->format->Rmask, surface->format->Gmask,
596 return 0; 377 surface->format->Bmask, surface->format->Amask);
378
379 src_pixels = (void*)((Uint8 *) surface->pixels +
380 rect->y * surface->pitch +
381 rect->x * surface->format->BytesPerPixel);
382
383 return SDL_ConvertPixels(rect->w, rect->h,
384 src_format, src_pixels, surface->pitch,
385 format, pixels, pitch);
597 } 386 }
598 387
599 static void 388 static void
600 SW_RenderPresent(SDL_Renderer * renderer) 389 SW_RenderPresent(SDL_Renderer * renderer)
601 { 390 {
602 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 391 SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
603 SDL_Texture *texture = SW_ActivateRenderer(renderer); 392 SDL_Window *window = renderer->window;
604 SDL_Rect rect; 393
605 394 if (window) {
606 if (!texture) { 395 SDL_UpdateWindowSurface(window);
607 return; 396 }
608 }
609
610 /* Send the data to the display */
611 rect.x = 0;
612 rect.y = 0;
613 rect.w = texture->w;
614 rect.h = texture->h;
615 data->renderer->RenderCopy(data->renderer, texture, &rect, &rect);
616 data->renderer->RenderPresent(data->renderer);
617 } 397 }
618 398
619 static void 399 static void
620 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) 400 SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
621 { 401 {
626 406
627 static void 407 static void
628 SW_DestroyRenderer(SDL_Renderer * renderer) 408 SW_DestroyRenderer(SDL_Renderer * renderer)
629 { 409 {
630 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 410 SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
631 SDL_Window *window = renderer->window;
632 411
633 if (data) { 412 if (data) {
634 if (data->texture) {
635 DestroyTexture(data->renderer, data->texture);
636 }
637 if (data->surface.format) {
638 SDL_FreeFormat(data->surface.format);
639 }
640 if (data->renderer) {
641 data->renderer->DestroyRenderer(data->renderer);
642 }
643 SDL_free(data); 413 SDL_free(data);
644 } 414 }
645 SDL_free(renderer); 415 SDL_free(renderer);
646 } 416 }
647 417