src/platform/sdl/sw-sdl.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "main.h"
7
8#include <mgba/core/core.h>
9#include <mgba/core/thread.h>
10#include <mgba/core/version.h>
11#include <mgba-util/arm-algo.h>
12
13static bool mSDLSWInit(struct mSDLRenderer* renderer);
14static void mSDLSWRunloop(struct mSDLRenderer* renderer, void* user);
15static void mSDLSWDeinit(struct mSDLRenderer* renderer);
16
17void mSDLSWCreate(struct mSDLRenderer* renderer) {
18 renderer->init = mSDLSWInit;
19 renderer->deinit = mSDLSWDeinit;
20 renderer->runloop = mSDLSWRunloop;
21}
22
23bool mSDLSWInit(struct mSDLRenderer* renderer) {
24#if !SDL_VERSION_ATLEAST(2, 0, 0)
25#ifdef COLOR_16_BIT
26 SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_DOUBLEBUF | SDL_HWSURFACE);
27#else
28 SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_DOUBLEBUF | SDL_HWSURFACE);
29#endif
30#endif
31
32 unsigned width, height;
33 renderer->core->desiredVideoDimensions(renderer->core, &width, &height);
34#if SDL_VERSION_ATLEAST(2, 0, 0)
35 renderer->window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen));
36 SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
37 renderer->player.window = renderer->window;
38 renderer->sdlRenderer = SDL_CreateRenderer(renderer->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
39#ifdef COLOR_16_BIT
40#ifdef COLOR_5_6_5
41 renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, width, height);
42#else
43 renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, width, height);
44#endif
45#else
46 renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height);
47#endif
48
49 int stride;
50 SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->outputBuffer, &stride);
51 renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, stride / BYTES_PER_PIXEL);
52#else
53 SDL_Surface* surface = SDL_GetVideoSurface();
54 SDL_LockSurface(surface);
55
56 if (renderer->ratio == 1) {
57 renderer->core->setVideoBuffer(renderer->core, surface->pixels, surface->pitch / BYTES_PER_PIXEL);
58 } else {
59#ifdef USE_PIXMAN
60 renderer->outputBuffer = malloc(width * height * BYTES_PER_PIXEL);
61 renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, width);
62#ifdef COLOR_16_BIT
63#ifdef COLOR_5_6_5
64 pixman_format_code_t format = PIXMAN_r5g6b5;
65#else
66 pixman_format_code_t format = PIXMAN_x1b5g5r5;
67#endif
68#else
69 pixman_format_code_t format = PIXMAN_x8b8g8r8;
70#endif
71 renderer->pix = pixman_image_create_bits(format, width, height,
72 renderer->outputBuffer, width * BYTES_PER_PIXEL);
73 renderer->screenpix = pixman_image_create_bits(format, renderer->viewportWidth, renderer->viewportHeight, surface->pixels, surface->pitch);
74
75 pixman_transform_t transform;
76 pixman_transform_init_identity(&transform);
77 pixman_transform_scale(0, &transform, pixman_int_to_fixed(renderer->ratio), pixman_int_to_fixed(renderer->ratio));
78 pixman_image_set_transform(renderer->pix, &transform);
79 pixman_image_set_filter(renderer->pix, PIXMAN_FILTER_NEAREST, 0, 0);
80#else
81 return false;
82#endif
83 }
84#endif
85
86 return true;
87}
88
89void mSDLSWRunloop(struct mSDLRenderer* renderer, void* user) {
90 struct mCoreThread* context = user;
91 SDL_Event event;
92#if !SDL_VERSION_ATLEAST(2, 0, 0)
93 SDL_Surface* surface = SDL_GetVideoSurface();
94#endif
95
96 while (mCoreThreadIsActive(context)) {
97 while (SDL_PollEvent(&event)) {
98 mSDLHandleEvent(context, &renderer->player, &event);
99 }
100
101 if (mCoreSyncWaitFrameStart(&context->impl->sync)) {
102#if SDL_VERSION_ATLEAST(2, 0, 0)
103 SDL_UnlockTexture(renderer->sdlTex);
104 SDL_RenderCopy(renderer->sdlRenderer, renderer->sdlTex, 0, 0);
105 SDL_RenderPresent(renderer->sdlRenderer);
106 int stride;
107 SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->outputBuffer, &stride);
108 renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, stride / BYTES_PER_PIXEL);
109#else
110#ifdef USE_PIXMAN
111 if (renderer->ratio > 1) {
112 pixman_image_composite32(PIXMAN_OP_SRC, renderer->pix, 0, renderer->screenpix,
113 0, 0, 0, 0, 0, 0,
114 renderer->viewportWidth, renderer->viewportHeight);
115 }
116#else
117 switch (renderer->ratio) {
118#if defined(__ARM_NEON) && COLOR_16_BIT
119 case 2:
120 _neon2x(surface->pixels, renderer->outputBuffer, width, height);
121 break;
122 case 4:
123 _neon4x(surface->pixels, renderer->outputBuffer, width, height);
124 break;
125#endif
126 case 1:
127 break;
128 default:
129 abort();
130 }
131#endif
132 SDL_UnlockSurface(surface);
133 SDL_Flip(surface);
134 SDL_LockSurface(surface);
135#endif
136 }
137 mCoreSyncWaitFrameEnd(&context->impl->sync);
138 }
139}
140
141void mSDLSWDeinit(struct mSDLRenderer* renderer) {
142 if (renderer->ratio > 1) {
143 free(renderer->outputBuffer);
144 }
145#if !SDL_VERSION_ATLEAST(2, 0, 0)
146 SDL_Surface* surface = SDL_GetVideoSurface();
147 SDL_UnlockSurface(surface);
148#ifdef USE_PIXMAN
149 pixman_image_unref(renderer->pix);
150 pixman_image_unref(renderer->screenpix);
151#endif
152#endif
153}