all repos — mgba @ d68a4f97c51a6277ea7ba95245679f0cc62cd973

mGBA Game Boy Advance Emulator

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 (context->state < THREAD_EXITING) {
 97		while (SDL_PollEvent(&event)) {
 98			mSDLHandleEvent(context, &renderer->player, &event);
 99		}
100
101		if (mCoreSyncWaitFrameStart(&context->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->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}