mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
f83733518e
2
CHANGES
2
CHANGES
|
@ -49,6 +49,7 @@ Features:
|
|||
- Discord Rich Presence now supports time elapsed
|
||||
- Additional scaling shaders
|
||||
Emulation fixes:
|
||||
- GB I/O: Fix incrementing SGB controller when P14 is low (fixes mgba.io/i/2202)
|
||||
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
|
||||
- GB Video: Render SGB border when unmasking with ATTR/PAL_SET (fixes mgba.io/i/2261)
|
||||
- GBA: Improve timing when not booting from BIOS
|
||||
|
@ -56,6 +57,7 @@ Emulation fixes:
|
|||
- GBA Video: Fix backdrop color if DISPCNT is first set to 0 (fixes mgba.io/i/2260)
|
||||
Other fixes:
|
||||
- Core: Don't attempt to restore rewind diffs past start of rewind
|
||||
- FFmpeg: Don't attempt to use YUV 4:2:0 for lossless videos (fixes mgba.io/i/2084)
|
||||
- GB Video: Fix memory leak when reseting SGB games
|
||||
- GBA: Fix out of bounds ROM accesses on patched ROMs smaller than 32 MiB
|
||||
- Libretro: Fix crash when using Game Boy codes (fixes mgba.io/i/2281)
|
||||
|
|
|
@ -79,7 +79,7 @@ if(NOT LIBMGBA_ONLY)
|
|||
set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)")
|
||||
set(BUILD_GL ON CACHE BOOL "Build with OpenGL")
|
||||
set(BUILD_GLES2 ON CACHE BOOL "Build with OpenGL|ES 2")
|
||||
set(BUILD_GLES3 OFF CACHE BOOL "Build with OpenGL|ES 3")
|
||||
set(BUILD_GLES3 ON CACHE BOOL "Build with OpenGL|ES 3")
|
||||
set(USE_EPOXY ON CACHE STRING "Build with libepoxy")
|
||||
set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies")
|
||||
set(DISTBUILD OFF CACHE BOOL "Build distribution packages")
|
||||
|
@ -123,6 +123,10 @@ else()
|
|||
set(CMAKE_INSTALL_INCLUDEDIR "include")
|
||||
endif()
|
||||
|
||||
if(APPLE AND DISTBUILD)
|
||||
set(CMAKE_INSTALL_DOCDIR ".")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED LIBDIR)
|
||||
set(LIBDIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
@ -212,8 +216,7 @@ if(WIN32)
|
|||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_UNICODE -DUNICODE)
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -municode")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
endif()
|
||||
list(APPEND OS_LIB ws2_32 shlwapi)
|
||||
list(APPEND CORE_VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/vfs-w32.c)
|
||||
|
@ -331,7 +334,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|||
find_function(localtime_r)
|
||||
# The strtof_l on Linux not actually exposed nor actually strtof_l
|
||||
set(HAVE_STRTOF_L OFF)
|
||||
elseif(NOT DEFINED PSP2)
|
||||
else()
|
||||
find_function(localtime_r)
|
||||
find_function(strtof_l)
|
||||
endif()
|
||||
|
@ -398,6 +401,7 @@ if(CMAKE_SYSTEM_NAME MATCHES ".*BSD|DragonFly")
|
|||
else()
|
||||
find_feature(USE_EDITLINE "libedit")
|
||||
endif()
|
||||
|
||||
if(BUILD_GL)
|
||||
find_package(OpenGL QUIET)
|
||||
if(NOT OPENGL_FOUND)
|
||||
|
@ -406,39 +410,49 @@ if(BUILD_GL)
|
|||
set(OPENGL_LIBRARY OpenGL::GL)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT BUILD_GL AND NOT LIBMGBA_ONLY)
|
||||
set(OPENGL_LIBRARY "" CACHE PATH "" FORCE)
|
||||
endif()
|
||||
if(BUILD_GLES2 AND NOT BUILD_RASPI AND NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin|Linux|.*BSD|DragonFly|Haiku)$")
|
||||
find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h)
|
||||
find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)
|
||||
if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
|
||||
set(BUILD_GLES2 OFF CACHE BOOL "OpenGL|ES 2 not found" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT BUILD_GLES2 AND NOT LIBMGBA_ONLY)
|
||||
set(OPENGLES2_LIBRARY "" CACHE PATH "" FORCE)
|
||||
endif()
|
||||
if(BUILD_GL)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||
list(APPEND FEATURE_DEFINES BUILD_GL)
|
||||
list(APPEND DEPENDENCY_LIB ${OPENGL_LIBRARY})
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT BUILD_GL AND NOT LIBMGBA_ONLY)
|
||||
set(OPENGL_LIBRARY "" CACHE PATH "" FORCE)
|
||||
endif()
|
||||
|
||||
if(BUILD_GLES2 AND NOT BUILD_GL)
|
||||
find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h)
|
||||
find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)
|
||||
if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
|
||||
set(BUILD_GLES2 OFF CACHE BOOL "OpenGL|ES 2 not found" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if(BUILD_GLES2)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
list(APPEND FEATURE_DEFINES BUILD_GLES2)
|
||||
list(APPEND DEPENDENCY_LIB ${OPENGLES2_LIBRARY})
|
||||
include_directories(${OPENGLES2_INCLUDE_DIR})
|
||||
endif()
|
||||
if(BUILD_GLES3)
|
||||
|
||||
if(BUILD_GLES3 AND NOT BUILD_GL)
|
||||
find_path(OPENGLES3_INCLUDE_DIR NAMES GLES3/gl3.h)
|
||||
find_library(OPENGLES3_LIBRARY NAMES GLESv3 GLESv2)
|
||||
list(APPEND FEATURE_DEFINES BUILD_GLES3)
|
||||
if(NOT OPENGLES3_INCLUDE_DIR OR NOT OPENGLES3_LIBRARY)
|
||||
set(BUILD_GLES3 OFF CACHE BOOL "OpenGL|ES 3 not found" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if(BUILD_GLES3)
|
||||
list(APPEND FEATURE_DEFINES BUILD_GLES3)
|
||||
list(APPEND DEPENDENCY_LIB ${OPENGLES3_LIBRARY})
|
||||
include_directories(${OPENGLES3_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
if(BUILD_GLES2 OR BUILD_GLES3)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_GLES2 AND NOT BUILD_GLES3 AND NOT LIBMGBA_ONLY)
|
||||
set(OPENGLES2_LIBRARY "" CACHE PATH "" FORCE)
|
||||
endif()
|
||||
|
||||
if(DISABLE_DEPS)
|
||||
set(USE_GDB_STUB OFF)
|
||||
|
@ -692,7 +706,7 @@ endif()
|
|||
|
||||
if(USE_EPOXY)
|
||||
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
list(APPEND FEATURE_DEFINES BUILD_GL BUILD_GLES2)
|
||||
list(APPEND FEATURE_DEFINES BUILD_GL BUILD_GLES2 BUILD_GLES3)
|
||||
list(APPEND FEATURES EPOXY)
|
||||
include_directories(AFTER ${EPOXY_INCLUDE_DIRS})
|
||||
link_directories(${EPOXY_LIBRARY_DIRS})
|
||||
|
@ -937,14 +951,16 @@ if(BUILD_OPENEMU)
|
|||
install(TARGETS ${BINARY_NAME}-openemu LIBRARY DESTINATION ${OE_LIBDIR} COMPONENT ${BINARY_NAME}.oecoreplugin NAMELINK_SKIP)
|
||||
endif()
|
||||
|
||||
if(BUILD_QT AND WIN32)
|
||||
if(BUILD_QT AND (WIN32 OR APPLE))
|
||||
set(BUILD_UPDATER ON)
|
||||
endif()
|
||||
|
||||
if(BUILD_UPDATER)
|
||||
add_executable(updater-stub WIN32 ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/updater-main.c)
|
||||
target_link_libraries(updater-stub ${OS_LIB} ${PLATFORM_LIBRARY} ${BINARY_NAME})
|
||||
if(NOT MSVC)
|
||||
if(MSVC)
|
||||
set_target_properties(updater-stub PROPERTIES LINK_FLAGS /ENTRY:mainCRTStartup)
|
||||
else()
|
||||
set_target_properties(updater-stub PROPERTIES LINK_FLAGS_RELEASE -s)
|
||||
set_target_properties(updater-stub PROPERTIES LINK_FLAGS_RELWITHDEBINFO -s)
|
||||
endif()
|
||||
|
@ -1091,6 +1107,9 @@ endif()
|
|||
|
||||
if(DISTBUILD)
|
||||
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
|
||||
set(CPACK_DMG_FILESYSTEM "HFS+")
|
||||
set(CPACK_DMG_FORMAT "UDBZ")
|
||||
set(CPACK_DMG_VOLUME_NAME "${PROJECT_NAME} ${VERSION_STRING}")
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND BUILD_SHARED)
|
||||
if(NOT APPLE)
|
||||
add_custom_command(TARGET ${BINARY_NAME} POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$<TARGET_FILE:${BINARY_NAME}>" "$<TARGET_FILE:${BINARY_NAME}>.debug")
|
||||
|
@ -1101,7 +1120,8 @@ if(DISTBUILD)
|
|||
endif()
|
||||
if(APPLE)
|
||||
set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-qt ${BINARY_NAME}-sdl ${BINARY_NAME}-qt-dbg ${BINARY_NAME}-sdl-dbg ${BINARY_NAME}-perf)
|
||||
set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/cmake/DMGOverrides.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/DMGOverrides.cmake @ONLY)
|
||||
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/DMGOverrides.cmake)
|
||||
elseif(WIN32)
|
||||
set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-qt ${BINARY_NAME}-sdl ${BINARY_NAME}-qt-dbg ${BINARY_NAME}-sdl-dbg ${BINARY_NAME}-perf installer)
|
||||
elseif(3DS)
|
||||
|
|
|
@ -253,9 +253,9 @@ typedef intptr_t ssize_t;
|
|||
#define ATTRIBUTE_NOINLINE
|
||||
// Adapted from https://stackoverflow.com/a/2390626
|
||||
#define _CONSTRUCTOR(FN, PRE) \
|
||||
static void FN(void); \
|
||||
__declspec(allocate(".CRT$XCU")) void (*_CONSTRUCTOR_ ## FN)(void) = FN; \
|
||||
static void FN(void)
|
||||
static void FN(void); \
|
||||
__declspec(allocate(".CRT$XCU")) void (*_CONSTRUCTOR_ ## FN)(void) = FN; \
|
||||
static void FN(void)
|
||||
#ifdef _WIN64
|
||||
#define CONSTRUCTOR(FN) _CONSTRUCTOR(FN, "")
|
||||
#else
|
||||
|
|
|
@ -59,6 +59,31 @@ enum GUIIcon {
|
|||
GUI_ICON_UP,
|
||||
GUI_ICON_RIGHT,
|
||||
GUI_ICON_DOWN,
|
||||
GUI_ICON_9SLICE_EMPTY_NW,
|
||||
GUI_ICON_9SLICE_EMPTY_N,
|
||||
GUI_ICON_9SLICE_EMPTY_NE,
|
||||
GUI_ICON_9SLICE_EMPTY_W,
|
||||
GUI_ICON_9SLICE_EMPTY_E,
|
||||
GUI_ICON_9SLICE_EMPTY_SW,
|
||||
GUI_ICON_9SLICE_EMPTY_S,
|
||||
GUI_ICON_9SLICE_EMPTY_SE,
|
||||
GUI_ICON_9SLICE_FILLED_NW,
|
||||
GUI_ICON_9SLICE_FILLED_N,
|
||||
GUI_ICON_9SLICE_FILLED_NE,
|
||||
GUI_ICON_9SLICE_FILLED_W,
|
||||
GUI_ICON_9SLICE_FILLED_C,
|
||||
GUI_ICON_9SLICE_FILLED_E,
|
||||
GUI_ICON_9SLICE_FILLED_SW,
|
||||
GUI_ICON_9SLICE_FILLED_S,
|
||||
GUI_ICON_9SLICE_FILLED_SE,
|
||||
GUI_ICON_9SLICE_CAP_NNW,
|
||||
GUI_ICON_9SLICE_CAP_NWW,
|
||||
GUI_ICON_9SLICE_CAP_NNE,
|
||||
GUI_ICON_9SLICE_CAP_NEE,
|
||||
GUI_ICON_9SLICE_CAP_SSW,
|
||||
GUI_ICON_9SLICE_CAP_SWW,
|
||||
GUI_ICON_9SLICE_CAP_SSE,
|
||||
GUI_ICON_9SLICE_CAP_SEE,
|
||||
GUI_ICON_MAX,
|
||||
};
|
||||
|
||||
|
@ -80,6 +105,12 @@ struct GUIIconMetric {
|
|||
int height;
|
||||
};
|
||||
|
||||
enum GUI9SliceStyle {
|
||||
GUI_9SLICE_FILLED,
|
||||
GUI_9SLICE_EMPTY,
|
||||
GUI_9SLICE_EMPTY_CAPPED,
|
||||
};
|
||||
|
||||
unsigned GUIFontHeight(const struct GUIFont*);
|
||||
unsigned GUIFontGlyphWidth(const struct GUIFont*, uint32_t glyph);
|
||||
unsigned GUIFontSpanWidth(const struct GUIFont*, const char* text);
|
||||
|
@ -96,6 +127,8 @@ void GUIFontDrawIconSize(struct GUIFont* font, int x, int y, int w, int h, uint3
|
|||
void GUIFontDrawSubmit(struct GUIFont* font);
|
||||
#endif
|
||||
|
||||
void GUIFontDraw9Slice(struct GUIFont*, int x, int y, int width, int height, uint32_t color, enum GUI9SliceStyle style);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,16 +17,16 @@ struct StringList;
|
|||
struct Table;
|
||||
|
||||
struct mUpdaterContext {
|
||||
struct Configuration manifest;
|
||||
struct Configuration manifest;
|
||||
};
|
||||
|
||||
struct mUpdate {
|
||||
const char* path;
|
||||
size_t size;
|
||||
int rev;
|
||||
const char* version;
|
||||
const char* commit;
|
||||
const char* sha256;
|
||||
const char* path;
|
||||
size_t size;
|
||||
int rev;
|
||||
const char* version;
|
||||
const char* commit;
|
||||
const char* sha256;
|
||||
};
|
||||
|
||||
bool mUpdaterInit(struct mUpdaterContext*, const char* manifest);
|
||||
|
|
|
@ -16,7 +16,7 @@ CXX_GUARD_START
|
|||
#include <mgba/internal/gba/renderers/common.h>
|
||||
#include <mgba/internal/gba/video.h>
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
|
||||
#ifdef USE_EPOXY
|
||||
#include <epoxy/gl.h>
|
||||
|
|
BIN
res/icons.png
BIN
res/icons.png
Binary file not shown.
Before Width: | Height: | Size: 619 B After Width: | Height: | Size: 663 B |
BIN
res/icons2x.png
BIN
res/icons2x.png
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -662,7 +662,7 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
break;
|
||||
case 'X':
|
||||
_writeMemoryBinary(stub, message);
|
||||
break;
|
||||
break;
|
||||
case 'Z':
|
||||
_setBreakpoint(stub, message);
|
||||
break;
|
||||
|
|
|
@ -81,20 +81,12 @@ bool FFmpegDecoderOpen(struct FFmpegDecoder* decoder, const char* infile) {
|
|||
decoder->videoStream = i;
|
||||
decoder->width = -1;
|
||||
decoder->height = -1;
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
decoder->videoFrame = av_frame_alloc();
|
||||
#else
|
||||
decoder->videoFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (type == AVMEDIA_TYPE_AUDIO) {
|
||||
decoder->audioStream = i;
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
decoder->audioFrame = av_frame_alloc();
|
||||
#else
|
||||
decoder->audioFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -102,11 +94,7 @@ bool FFmpegDecoderOpen(struct FFmpegDecoder* decoder, const char* infile) {
|
|||
|
||||
void FFmpegDecoderClose(struct FFmpegDecoder* decoder) {
|
||||
if (decoder->audioFrame) {
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&decoder->audioFrame);
|
||||
#else
|
||||
avcodec_free_frame(&decoder->audioFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (decoder->audio) {
|
||||
|
@ -124,11 +112,7 @@ void FFmpegDecoderClose(struct FFmpegDecoder* decoder) {
|
|||
}
|
||||
|
||||
if (decoder->videoFrame) {
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&decoder->videoFrame);
|
||||
#else
|
||||
avcodec_free_frame(&decoder->videoFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (decoder->pixels) {
|
||||
|
@ -216,4 +200,4 @@ bool FFmpegDecoderRead(struct FFmpegDecoder* decoder) {
|
|||
#endif
|
||||
}
|
||||
return readPacket;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,6 @@ void FFmpegEncoderInit(struct FFmpegEncoder* encoder) {
|
|||
encoder->audioStream = NULL;
|
||||
encoder->audioFrame = NULL;
|
||||
encoder->audioBuffer = NULL;
|
||||
encoder->postaudioBuffer = NULL;
|
||||
encoder->video = NULL;
|
||||
encoder->videoStream = NULL;
|
||||
encoder->videoFrame = NULL;
|
||||
|
@ -315,17 +314,14 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
FFmpegEncoderClose(encoder);
|
||||
return false;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
encoder->audioFrame = av_frame_alloc();
|
||||
#else
|
||||
encoder->audioFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
if (!encoder->audio->frame_size) {
|
||||
encoder->audio->frame_size = 1;
|
||||
}
|
||||
encoder->audioFrame->nb_samples = encoder->audio->frame_size;
|
||||
encoder->audioFrame->format = encoder->audio->sample_fmt;
|
||||
encoder->audioFrame->pts = 0;
|
||||
encoder->audioFrame->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
#ifdef USE_LIBAVRESAMPLE
|
||||
encoder->resampleContext = avresample_alloc_context();
|
||||
av_opt_set_int(encoder->resampleContext, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
|
||||
|
@ -342,14 +338,12 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
#endif
|
||||
encoder->audioBufferSize = (encoder->audioFrame->nb_samples * PREFERRED_SAMPLE_RATE / encoder->sampleRate) * 4;
|
||||
encoder->audioBuffer = av_malloc(encoder->audioBufferSize);
|
||||
encoder->postaudioBufferSize = av_samples_get_buffer_size(0, encoder->audio->channels, encoder->audio->frame_size, encoder->audio->sample_fmt, 0);
|
||||
encoder->postaudioBuffer = av_malloc(encoder->postaudioBufferSize);
|
||||
avcodec_fill_audio_frame(encoder->audioFrame, encoder->audio->channels, encoder->audio->sample_fmt, (const uint8_t*) encoder->postaudioBuffer, encoder->postaudioBufferSize, 0);
|
||||
av_frame_get_buffer(encoder->audioFrame, 0);
|
||||
|
||||
if (encoder->audio->codec->id == AV_CODEC_ID_AAC &&
|
||||
(strcasecmp(encoder->containerFormat, "mp4") ||
|
||||
strcasecmp(encoder->containerFormat, "m4v") ||
|
||||
strcasecmp(encoder->containerFormat, "mov"))) {
|
||||
(strcasecmp(encoder->containerFormat, "mp4") == 0||
|
||||
strcasecmp(encoder->containerFormat, "m4v") == 0 ||
|
||||
strcasecmp(encoder->containerFormat, "mov") == 0)) {
|
||||
// MP4 container doesn't support the raw ADTS AAC format that the encoder spits out
|
||||
#ifdef FFMPEG_USE_NEW_BSF
|
||||
av_bsf_alloc(av_bsf_get_by_name("aac_adtstoasc"), &encoder->absf);
|
||||
|
@ -391,9 +385,9 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
}
|
||||
|
||||
if (encoder->video->codec->id == AV_CODEC_ID_H264 &&
|
||||
(strcasecmp(encoder->containerFormat, "mp4") ||
|
||||
strcasecmp(encoder->containerFormat, "m4v") ||
|
||||
strcasecmp(encoder->containerFormat, "mov"))) {
|
||||
(strcasecmp(encoder->containerFormat, "mp4") == 0 ||
|
||||
strcasecmp(encoder->containerFormat, "m4v") == 0 ||
|
||||
strcasecmp(encoder->containerFormat, "mov") == 0)) {
|
||||
// QuickTime and a few other things require YUV420
|
||||
encoder->video->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||
}
|
||||
|
@ -497,11 +491,7 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
encoder->sinkFrame = av_frame_alloc();
|
||||
#else
|
||||
encoder->sinkFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
AVDictionary* opts = 0;
|
||||
av_dict_set(&opts, "strict", "-2", 0);
|
||||
|
@ -511,17 +501,13 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
FFmpegEncoderClose(encoder);
|
||||
return false;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
encoder->videoFrame = av_frame_alloc();
|
||||
#else
|
||||
encoder->videoFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
encoder->videoFrame->format = encoder->video->pix_fmt != AV_PIX_FMT_PAL8 ? encoder->video->pix_fmt : encoder->ipixFormat;
|
||||
encoder->videoFrame->width = encoder->video->width;
|
||||
encoder->videoFrame->height = encoder->video->height;
|
||||
encoder->videoFrame->pts = 0;
|
||||
_ffmpegSetVideoDimensions(&encoder->d, encoder->iwidth, encoder->iheight);
|
||||
av_image_alloc(encoder->videoFrame->data, encoder->videoFrame->linesize, encoder->videoFrame->width, encoder->videoFrame->height, encoder->videoFrame->format, 32);
|
||||
av_frame_get_buffer(encoder->videoFrame, 32);
|
||||
#ifdef FFMPEG_USE_CODECPAR
|
||||
avcodec_parameters_from_context(encoder->videoStream->codecpar, encoder->video);
|
||||
#endif
|
||||
|
@ -579,21 +565,13 @@ void FFmpegEncoderClose(struct FFmpegEncoder* encoder) {
|
|||
avio_close(encoder->context->pb);
|
||||
}
|
||||
|
||||
if (encoder->postaudioBuffer) {
|
||||
av_free(encoder->postaudioBuffer);
|
||||
encoder->postaudioBuffer = NULL;
|
||||
}
|
||||
if (encoder->audioBuffer) {
|
||||
av_free(encoder->audioBuffer);
|
||||
encoder->audioBuffer = NULL;
|
||||
}
|
||||
|
||||
if (encoder->audioFrame) {
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&encoder->audioFrame);
|
||||
#else
|
||||
avcodec_free_frame(&encoder->audioFrame);
|
||||
#endif
|
||||
}
|
||||
if (encoder->audio) {
|
||||
#ifdef FFMPEG_USE_CODECPAR
|
||||
|
@ -623,20 +601,11 @@ void FFmpegEncoderClose(struct FFmpegEncoder* encoder) {
|
|||
}
|
||||
|
||||
if (encoder->videoFrame) {
|
||||
av_freep(encoder->videoFrame->data);
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&encoder->videoFrame);
|
||||
#else
|
||||
avcodec_free_frame(&encoder->videoFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (encoder->sinkFrame) {
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&encoder->sinkFrame);
|
||||
#else
|
||||
avcodec_free_frame(&encoder->sinkFrame);
|
||||
#endif
|
||||
encoder->sinkFrame = NULL;
|
||||
}
|
||||
|
||||
|
@ -696,7 +665,6 @@ void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right
|
|||
return;
|
||||
}
|
||||
|
||||
int channelSize = 2 * av_get_bytes_per_sample(encoder->audio->sample_fmt);
|
||||
encoder->currentAudioSample = 0;
|
||||
#ifdef USE_LIBAVRESAMPLE
|
||||
avresample_convert(encoder->resampleContext, 0, 0, 0,
|
||||
|
@ -705,19 +673,15 @@ void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right
|
|||
if (avresample_available(encoder->resampleContext) < encoder->audioFrame->nb_samples) {
|
||||
return;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_make_writable(encoder->audioFrame);
|
||||
#endif
|
||||
int samples = avresample_read(encoder->resampleContext, encoder->audioFrame->data, encoder->postaudioBufferSize / channelSize);
|
||||
int samples = avresample_read(encoder->resampleContext, encoder->audioFrame->data, encoder->audioFrame->nb_samples);
|
||||
#else
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_make_writable(encoder->audioFrame);
|
||||
#endif
|
||||
if (swr_get_out_samples(encoder->resampleContext, 1) < encoder->audioFrame->nb_samples) {
|
||||
swr_convert(encoder->resampleContext, NULL, 0, (const uint8_t**) &encoder->audioBuffer, encoder->audioBufferSize / 4);
|
||||
return;
|
||||
}
|
||||
int samples = swr_convert(encoder->resampleContext, encoder->audioFrame->data, encoder->postaudioBufferSize / channelSize,
|
||||
int samples = swr_convert(encoder->resampleContext, encoder->audioFrame->data, encoder->audioFrame->nb_samples,
|
||||
(const uint8_t**) &encoder->audioBuffer, encoder->audioBufferSize / 4);
|
||||
#endif
|
||||
|
||||
|
@ -728,61 +692,76 @@ void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right
|
|||
}
|
||||
|
||||
bool _ffmpegWriteAudioFrame(struct FFmpegEncoder* encoder, struct AVFrame* audioFrame) {
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
packet.data = 0;
|
||||
packet.size = 0;
|
||||
AVPacket* packet;
|
||||
#ifdef FFMPEG_USE_PACKET_UNREF
|
||||
packet = av_packet_alloc();
|
||||
#else
|
||||
packet = av_malloc(sizeof(*packet));
|
||||
av_init_packet(packet);
|
||||
#endif
|
||||
packet->data = 0;
|
||||
packet->size = 0;
|
||||
|
||||
int gotData;
|
||||
#ifdef FFMPEG_USE_PACKETS
|
||||
avcodec_send_frame(encoder->audio, audioFrame);
|
||||
gotData = avcodec_receive_packet(encoder->audio, &packet);
|
||||
gotData = (gotData == 0) && packet.size;
|
||||
gotData = avcodec_receive_packet(encoder->audio, packet);
|
||||
gotData = (gotData == 0) && packet->size;
|
||||
#else
|
||||
avcodec_encode_audio2(encoder->audio, &packet, audioFrame, &gotData);
|
||||
avcodec_encode_audio2(encoder->audio, packet, audioFrame, &gotData);
|
||||
#endif
|
||||
packet.pts = av_rescale_q(packet.pts, encoder->audio->time_base, encoder->audioStream->time_base);
|
||||
packet.dts = packet.pts;
|
||||
packet->pts = av_rescale_q(packet->pts, encoder->audio->time_base, encoder->audioStream->time_base);
|
||||
packet->dts = packet->pts;
|
||||
|
||||
if (gotData) {
|
||||
if (encoder->absf) {
|
||||
AVPacket tempPacket;
|
||||
AVPacket* tempPacket;
|
||||
#ifdef FFMPEG_USE_PACKETS
|
||||
tempPacket = av_packet_alloc();
|
||||
#else
|
||||
tempPacket = av_malloc(sizeof(*tempPacket));
|
||||
av_init_packet(tempPacket);
|
||||
#endif
|
||||
|
||||
#ifdef FFMPEG_USE_NEW_BSF
|
||||
int success = av_bsf_send_packet(encoder->absf, &packet);
|
||||
int success = av_bsf_send_packet(encoder->absf, packet);
|
||||
if (success >= 0) {
|
||||
success = av_bsf_receive_packet(encoder->absf, &tempPacket);
|
||||
success = av_bsf_receive_packet(encoder->absf, tempPacket);
|
||||
}
|
||||
#else
|
||||
int success = av_bitstream_filter_filter(encoder->absf, encoder->audio, 0,
|
||||
&tempPacket.data, &tempPacket.size,
|
||||
packet.data, packet.size, 0);
|
||||
&tempPacket->data, &tempPacket->size,
|
||||
packet->data, packet->size, 0);
|
||||
#endif
|
||||
|
||||
if (success >= 0) {
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 53
|
||||
tempPacket.buf = av_buffer_create(tempPacket.data, tempPacket.size, av_buffer_default_free, 0, 0);
|
||||
tempPacket->buf = av_buffer_create(tempPacket->data, tempPacket->size, av_buffer_default_free, 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef FFMPEG_USE_PACKET_UNREF
|
||||
av_packet_move_ref(&packet, &tempPacket);
|
||||
av_packet_move_ref(packet, tempPacket);
|
||||
av_packet_free(&packet);
|
||||
#else
|
||||
av_free_packet(&packet);
|
||||
av_free_packet(packet);
|
||||
av_freep(&packet);
|
||||
packet = tempPacket;
|
||||
#endif
|
||||
|
||||
packet.stream_index = encoder->audioStream->index;
|
||||
av_interleaved_write_frame(encoder->context, &packet);
|
||||
packet->stream_index = encoder->audioStream->index;
|
||||
av_interleaved_write_frame(encoder->context, packet);
|
||||
}
|
||||
} else {
|
||||
packet.stream_index = encoder->audioStream->index;
|
||||
av_interleaved_write_frame(encoder->context, &packet);
|
||||
packet->stream_index = encoder->audioStream->index;
|
||||
av_interleaved_write_frame(encoder->context, packet);
|
||||
}
|
||||
}
|
||||
#ifdef FFMPEG_USE_PACKET_UNREF
|
||||
av_packet_unref(&packet);
|
||||
av_packet_unref(packet);
|
||||
av_packet_free(&packet);
|
||||
#else
|
||||
av_free_packet(&packet);
|
||||
av_free_packet(packet);
|
||||
av_freep(&packet);
|
||||
#endif
|
||||
return gotData;
|
||||
}
|
||||
|
@ -798,9 +777,7 @@ void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size
|
|||
}
|
||||
stride *= BYTES_PER_PIXEL;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_make_writable(encoder->videoFrame);
|
||||
#endif
|
||||
if (encoder->video->codec->id == AV_CODEC_ID_WEBP) {
|
||||
// TODO: Figure out why WebP is rescaling internally (should video frames not be rescaled externally?)
|
||||
encoder->videoFrame->pts = encoder->currentVideoFrame;
|
||||
|
@ -829,32 +806,39 @@ void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size
|
|||
}
|
||||
|
||||
bool _ffmpegWriteVideoFrame(struct FFmpegEncoder* encoder, struct AVFrame* videoFrame) {
|
||||
AVPacket packet;
|
||||
AVPacket* packet;
|
||||
|
||||
av_init_packet(&packet);
|
||||
packet.data = 0;
|
||||
packet.size = 0;
|
||||
#ifdef FFMPEG_USE_PACKET_UNREF
|
||||
packet = av_packet_alloc();
|
||||
#else
|
||||
packet = av_malloc(sizeof(*packet));
|
||||
av_init_packet(packet);
|
||||
#endif
|
||||
packet->data = 0;
|
||||
packet->size = 0;
|
||||
|
||||
int gotData;
|
||||
#ifdef FFMPEG_USE_PACKETS
|
||||
avcodec_send_frame(encoder->video, videoFrame);
|
||||
gotData = avcodec_receive_packet(encoder->video, &packet) == 0;
|
||||
gotData = avcodec_receive_packet(encoder->video, packet) == 0;
|
||||
#else
|
||||
avcodec_encode_video2(encoder->video, &packet, videoFrame, &gotData);
|
||||
avcodec_encode_video2(encoder->video, packet, videoFrame, &gotData);
|
||||
#endif
|
||||
if (gotData) {
|
||||
#ifndef FFMPEG_USE_PACKET_UNREF
|
||||
if (encoder->video->coded_frame->key_frame) {
|
||||
packet.flags |= AV_PKT_FLAG_KEY;
|
||||
packet->flags |= AV_PKT_FLAG_KEY;
|
||||
}
|
||||
#endif
|
||||
packet.stream_index = encoder->videoStream->index;
|
||||
av_interleaved_write_frame(encoder->context, &packet);
|
||||
packet->stream_index = encoder->videoStream->index;
|
||||
av_interleaved_write_frame(encoder->context, packet);
|
||||
}
|
||||
#ifdef FFMPEG_USE_PACKET_UNREF
|
||||
av_packet_unref(&packet);
|
||||
av_packet_unref(packet);
|
||||
av_packet_free(&packet);
|
||||
#else
|
||||
av_free_packet(&packet);
|
||||
av_free_packet(packet);
|
||||
av_freep(&packet);
|
||||
#endif
|
||||
|
||||
return gotData;
|
||||
|
|
|
@ -33,8 +33,6 @@ struct FFmpegEncoder {
|
|||
int sampleRate;
|
||||
uint16_t* audioBuffer;
|
||||
size_t audioBufferSize;
|
||||
uint16_t* postaudioBuffer;
|
||||
size_t postaudioBufferSize;
|
||||
AVFrame* audioFrame;
|
||||
size_t currentAudioSample;
|
||||
int64_t currentAudioFrame;
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/core/config.h>
|
||||
#include <mgba/core/version.h>
|
||||
#include <mgba/feature/updater.h>
|
||||
#include <mgba-util/string.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -16,13 +18,18 @@
|
|||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <process.h>
|
||||
#include <synchapi.h>
|
||||
|
||||
#define mkdir(X, Y) _mkdir(X)
|
||||
#elif defined(_POSIX_C_SOURCE)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
bool extractArchive(struct VDir* archive, const char* root) {
|
||||
#ifndef W_OK
|
||||
#define W_OK 02
|
||||
#endif
|
||||
|
||||
bool extractArchive(struct VDir* archive, const char* root, bool prefix) {
|
||||
char path[PATH_MAX] = {0};
|
||||
struct VDirEntry* vde;
|
||||
uint8_t block[8192];
|
||||
|
@ -30,17 +37,37 @@ bool extractArchive(struct VDir* archive, const char* root) {
|
|||
while ((vde = archive->listNext(archive))) {
|
||||
struct VFile* vfIn;
|
||||
struct VFile* vfOut;
|
||||
const char* fname = strchr(vde->name(vde), '/');
|
||||
if (!fname) {
|
||||
const char* fname;
|
||||
if (prefix) {
|
||||
fname = strchr(vde->name(vde), '/');
|
||||
if (!fname) {
|
||||
continue;
|
||||
}
|
||||
snprintf(path, sizeof(path), "%s/%s", root, &fname[1]);
|
||||
} else {
|
||||
fname = vde->name(vde);
|
||||
snprintf(path, sizeof(path), "%s/%s", root, fname);
|
||||
}
|
||||
if (fname[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
snprintf(path, sizeof(path), "%s/%s", root, &fname[1]);
|
||||
switch (vde->type(vde)) {
|
||||
case VFS_DIRECTORY:
|
||||
printf("mkdir %s\n", fname);
|
||||
if (mkdir(path, 0755) < 0 && errno != EEXIST) {
|
||||
return false;
|
||||
}
|
||||
if (!prefix) {
|
||||
struct VDir* subdir = archive->openDir(archive, fname);
|
||||
if (!subdir) {
|
||||
return false;
|
||||
}
|
||||
if (!extractArchive(subdir, path, false)) {
|
||||
subdir->close(subdir);
|
||||
return false;
|
||||
}
|
||||
subdir->close(subdir);
|
||||
}
|
||||
break;
|
||||
case VFS_FILE:
|
||||
printf("extract %s\n", fname);
|
||||
|
@ -48,7 +75,11 @@ bool extractArchive(struct VDir* archive, const char* root) {
|
|||
errno = 0;
|
||||
vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (!vfOut && errno == EACCES) {
|
||||
#ifdef _WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
}
|
||||
if (!vfOut) {
|
||||
|
@ -76,6 +107,7 @@ int main(int argc, char* argv[]) {
|
|||
UNUSED(argv);
|
||||
struct mCoreConfig config;
|
||||
char updateArchive[PATH_MAX] = {0};
|
||||
char bin[PATH_MAX] = {0};
|
||||
const char* root;
|
||||
int ok = 1;
|
||||
|
||||
|
@ -87,14 +119,71 @@ int main(int argc, char* argv[]) {
|
|||
} else if (access(root, W_OK)) {
|
||||
puts("Cannot write to update path");
|
||||
} else {
|
||||
#ifdef __APPLE__
|
||||
char subdir[PATH_MAX];
|
||||
char devpath[PATH_MAX] = {0};
|
||||
bool needsUnmount = false;
|
||||
#endif
|
||||
bool isPortable = mCoreConfigIsPortable();
|
||||
struct VDir* archive = VDirOpenArchive(updateArchive);
|
||||
const char* extension = mUpdateGetArchiveExtension(&config);
|
||||
struct VDir* archive = NULL;
|
||||
bool prefix = true;
|
||||
if (strcmp(extension, "dmg") == 0) {
|
||||
#ifdef __APPLE__
|
||||
char mountpoint[PATH_MAX];
|
||||
// Make a slightly random directory name for the updater mountpoint
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
int printed = snprintf(mountpoint, sizeof(mountpoint), "/Volumes/%s Updater %04X", projectName, (t.tv_usec >> 2) & 0xFFFF);
|
||||
|
||||
// Fork hdiutil to mount it
|
||||
char* args[] = {"hdiutil", "attach", "-nobrowse", "-mountpoint", mountpoint, updateArchive, NULL};
|
||||
int fds[2];
|
||||
pipe(fds);
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
dup2(fds[1], STDOUT_FILENO);
|
||||
execvp("hdiutil", args);
|
||||
_exit(1);
|
||||
} else {
|
||||
// Parse out the disk ID so we can detach it when we're done
|
||||
char buffer[1024] = {0};
|
||||
ssize_t size;
|
||||
while ((size = read(fds[0], buffer, sizeof(buffer) - 1)) > 0) { // Leave the last byte null
|
||||
char* devinfo = strnstr(buffer, "\n/dev/disk", size);
|
||||
if (!devinfo) {
|
||||
continue;
|
||||
}
|
||||
char* devend = strpbrk(&devinfo[9], "s \t");
|
||||
if (!devend) {
|
||||
continue;
|
||||
}
|
||||
off_t diff = devend - devinfo - 1;
|
||||
memcpy(devpath, &devinfo[1], diff);
|
||||
puts(devpath);
|
||||
break;
|
||||
}
|
||||
int retstat;
|
||||
wait4(pid, &retstat, 0, NULL);
|
||||
}
|
||||
snprintf(&mountpoint[printed], sizeof(mountpoint) - printed, "/%s.app", projectName);
|
||||
snprintf(subdir, sizeof(subdir), "%s/%s.app", root, projectName);
|
||||
root = subdir;
|
||||
archive = VDirOpen(mountpoint);
|
||||
prefix = false;
|
||||
needsUnmount = true;
|
||||
#endif
|
||||
} else {
|
||||
archive = VDirOpenArchive(updateArchive);
|
||||
}
|
||||
if (!archive) {
|
||||
puts("Cannot open update archive");
|
||||
} else {
|
||||
puts("Extracting update");
|
||||
if (extractArchive(archive, root)) {
|
||||
if (extractArchive(archive, root, prefix)) {
|
||||
puts("Complete");
|
||||
const char* command = mUpdateGetCommand(&config);
|
||||
strlcpy(bin, command, sizeof(bin));
|
||||
ok = 0;
|
||||
mUpdateDeregister(&config);
|
||||
} else {
|
||||
|
@ -103,19 +192,31 @@ int main(int argc, char* argv[]) {
|
|||
archive->close(archive);
|
||||
unlink(updateArchive);
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
if (needsUnmount) {
|
||||
char* args[] = {"hdiutil", "detach", devpath, NULL};
|
||||
pid_t pid = vfork();
|
||||
if (pid == 0) {
|
||||
execvp("hdiutil", args);
|
||||
_exit(0);
|
||||
} else {
|
||||
int retstat;
|
||||
wait4(pid, &retstat, 0, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!isPortable) {
|
||||
char portableIni[PATH_MAX] = {0};
|
||||
snprintf(portableIni, sizeof(portableIni), "%s/portable.ini", root);
|
||||
unlink(portableIni);
|
||||
}
|
||||
}
|
||||
const char* bin = mUpdateGetCommand(&config);
|
||||
mCoreConfigDeinit(&config);
|
||||
if (ok == 0) {
|
||||
const char* argv[] = { bin, NULL };
|
||||
#ifdef _WIN32
|
||||
_execv(bin, argv);
|
||||
#elif defined(_POSIX_C_SOURCE)
|
||||
#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
|
||||
execv(bin, argv);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -185,6 +185,16 @@ void mUpdateRegister(struct mCoreConfig* config, const char* arg0, const char* u
|
|||
#endif
|
||||
if (last) {
|
||||
last[0] = '\0';
|
||||
#ifdef __APPLE__
|
||||
ssize_t len = strlen(filename);
|
||||
if (len > 19 && strcmp(&filename[len - 19], ".app/Contents/MacOS") == 0) {
|
||||
filename[len - 19] = '\0';
|
||||
last = strrchr(filename, '/');
|
||||
if (last) {
|
||||
last[0] = '\0';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ConfigurationSetValue(cfg, UPDATE_SECTION, "bin", arg0);
|
||||
ConfigurationSetValue(cfg, UPDATE_SECTION, "root", filename);
|
||||
|
|
14
src/gb/io.c
14
src/gb/io.c
|
@ -119,19 +119,15 @@ static void _writeSGBBits(struct GB* gb, int bits) {
|
|||
if (bits == gb->currentSgbBits) {
|
||||
return;
|
||||
}
|
||||
switch (bits) {
|
||||
case 0:
|
||||
case 1:
|
||||
if (gb->currentSgbBits & 2) {
|
||||
gb->sgbIncrement = !gb->sgbIncrement;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (bits & 2) {
|
||||
if (gb->sgbIncrement) {
|
||||
gb->sgbIncrement = false;
|
||||
gb->sgbCurrentController = (gb->sgbCurrentController + 1) & gb->sgbControllers;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (gb->currentSgbBits & 2) {
|
||||
gb->sgbIncrement = !gb->sgbIncrement;
|
||||
}
|
||||
}
|
||||
gb->currentSgbBits = bits;
|
||||
if (gb->sgbBit == 128 && bits == 2) {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef DISABLE_THREADING
|
||||
#include <mgba/feature/thread-proxy.h>
|
||||
#endif
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
#include <mgba/internal/gba/renderers/gl.h>
|
||||
#endif
|
||||
#include <mgba/internal/gba/renderers/proxy.h>
|
||||
|
@ -138,7 +138,7 @@ struct GBACore {
|
|||
struct mCore d;
|
||||
struct GBAVideoRenderer dummyRenderer;
|
||||
struct GBAVideoSoftwareRenderer renderer;
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
struct GBAVideoGLRenderer glRenderer;
|
||||
#endif
|
||||
#ifndef MINIMAL_CORE
|
||||
|
@ -196,7 +196,7 @@ static bool _GBACoreInit(struct mCore* core) {
|
|||
GBAVideoSoftwareRendererCreate(&gbacore->renderer);
|
||||
gbacore->renderer.outputBuffer = NULL;
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
GBAVideoGLRendererCreate(&gbacore->glRenderer);
|
||||
gbacore->glRenderer.outputTex = -1;
|
||||
#endif
|
||||
|
@ -256,7 +256,7 @@ static bool _GBACoreSupportsFeature(const struct mCore* core, enum mCoreFeature
|
|||
UNUSED(core);
|
||||
switch (feature) {
|
||||
case mCORE_FEATURE_OPENGL:
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
@ -370,7 +370,7 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c
|
|||
}
|
||||
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
if (strcmp("videoScale", option) == 0) {
|
||||
if (config != &core->config) {
|
||||
mCoreConfigCopyValue(&core->config, config, "videoScale");
|
||||
|
@ -388,7 +388,7 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c
|
|||
if (gbacore->renderer.outputBuffer) {
|
||||
renderer = &gbacore->renderer.d;
|
||||
}
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
|
||||
mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale);
|
||||
renderer = &gbacore->glRenderer.d;
|
||||
|
@ -410,7 +410,7 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c
|
|||
}
|
||||
|
||||
static void _GBACoreDesiredVideoDimensions(const struct mCore* core, unsigned* width, unsigned* height) {
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
const struct GBACore* gbacore = (const struct GBACore*) core;
|
||||
int scale = gbacore->glRenderer.scale;
|
||||
#else
|
||||
|
@ -430,7 +430,7 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s
|
|||
}
|
||||
|
||||
static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) {
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
gbacore->glRenderer.outputTex = texid;
|
||||
#else
|
||||
|
@ -573,7 +573,7 @@ static void _GBACoreReset(struct mCore* core) {
|
|||
struct GBA* gba = (struct GBA*) core->board;
|
||||
int fakeBool;
|
||||
if (gbacore->renderer.outputBuffer
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
|| gbacore->glRenderer.outputTex != (unsigned) -1
|
||||
#endif
|
||||
) {
|
||||
|
@ -581,7 +581,7 @@ static void _GBACoreReset(struct mCore* core) {
|
|||
if (gbacore->renderer.outputBuffer) {
|
||||
renderer = &gbacore->renderer.d;
|
||||
}
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
|
||||
mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale);
|
||||
renderer = &gbacore->glRenderer.d;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/renderers/gl.h>
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#ifdef BUILD_GLES3
|
||||
|
||||
#include <mgba/core/cache-set.h>
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
message(FATAL ${CPACK_GENERATOR})
|
||||
if(CPACK_GENERATOR STREQUAL "DragNDrop")
|
||||
set(CPACK_COMPONENTS_ALL @BINARY_NAME@ @BINARY_NAME@-qt @BINARY_NAME@-qt-dbg)
|
||||
set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE)
|
||||
unset(CPACK_RESOURCE_FILE_LICENSE)
|
||||
endif()
|
|
@ -159,6 +159,7 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
|
|||
mGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, false, 0, 0);
|
||||
mGLES2ShaderInit(&context->interframeShader, 0, _interframeFragmentShader, -1, -1, false, 0, 0);
|
||||
|
||||
#ifdef BUILD_GLES3
|
||||
if (context->initialShader.vao != (GLuint) -1) {
|
||||
glBindVertexArray(context->initialShader.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, context->vbo);
|
||||
|
@ -168,6 +169,7 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
|
|||
glBindBuffer(GL_ARRAY_BUFFER, context->vbo);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
glDeleteFramebuffers(1, &context->finalShader.fbo);
|
||||
glDeleteTextures(1, &context->finalShader.tex);
|
||||
|
@ -297,9 +299,12 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
|
|||
glUseProgram(shader->program);
|
||||
glUniform1i(shader->texLocation, 0);
|
||||
glUniform2f(shader->texSizeLocation, context->d.width - padW, context->d.height - padH);
|
||||
#ifdef BUILD_GLES3
|
||||
if (shader->vao != (GLuint) -1) {
|
||||
glBindVertexArray(shader->vao);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, context->vbo);
|
||||
glEnableVertexAttribArray(shader->positionLocation);
|
||||
glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
|
@ -391,9 +396,11 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) {
|
|||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glUseProgram(0);
|
||||
#ifdef BUILD_GLES3
|
||||
if (context->finalShader.vao != (GLuint) -1) {
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
|
||||
|
@ -508,6 +515,7 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f
|
|||
shader->uniforms[i].location = glGetUniformLocation(shader->program, shader->uniforms[i].name);
|
||||
}
|
||||
|
||||
#ifdef BUILD_GLES3
|
||||
const GLubyte* extensions = glGetString(GL_EXTENSIONS);
|
||||
if (shaderBuffer[0] == _gles2Header || version[0] >= '3' || (extensions && strstr((const char*) extensions, "_vertex_array_object") != NULL)) {
|
||||
glGenVertexArrays(1, &shader->vao);
|
||||
|
@ -515,7 +523,9 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f
|
|||
glEnableVertexAttribArray(shader->positionLocation);
|
||||
glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glBindVertexArray(0);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
shader->vao = -1;
|
||||
}
|
||||
|
||||
|
@ -527,9 +537,11 @@ void mGLES2ShaderDeinit(struct mGLES2Shader* shader) {
|
|||
glDeleteShader(shader->fragmentShader);
|
||||
glDeleteProgram(shader->program);
|
||||
glDeleteFramebuffers(1, &shader->fbo);
|
||||
#ifdef BUILD_GLES3
|
||||
if (shader->vao != (GLuint) -1) {
|
||||
glDeleteVertexArrays(1, &shader->vao);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shaders, size_t nShaders) {
|
||||
|
@ -547,16 +559,20 @@ void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shad
|
|||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
#ifdef BUILD_GLES3
|
||||
if (context->shaders[i].vao != (GLuint) -1) {
|
||||
glBindVertexArray(context->shaders[i].vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, context->vbo);
|
||||
glEnableVertexAttribArray(context->shaders[i].positionLocation);
|
||||
glVertexAttribPointer(context->shaders[i].positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef BUILD_GLES3
|
||||
if (context->initialShader.vao != (GLuint) -1) {
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
#endif
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ CXX_GUARD_START
|
|||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
#endif
|
||||
#elif defined(BUILD_GLES3)
|
||||
#include <GLES3/gl3.h>
|
||||
#else
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,7 @@ include("${VITASDK}/share/vita.cmake" REQUIRED)
|
|||
find_program(OBJCOPY ${cross_prefix}objcopy)
|
||||
find_file(NIDDB db.json PATHS ${VITASDK} ${VITASDK}/bin ${VITASDK}/share)
|
||||
|
||||
set(OS_DEFINES IOAPI_NO_64)
|
||||
set(OS_DEFINES IOAPI_NO_64 _GNU_SOURCE)
|
||||
set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE)
|
||||
|
||||
file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/psp2-*.c)
|
||||
|
|
|
@ -90,7 +90,7 @@ struct VFile* VFileOpenSce(const char* path, int flags, SceMode mode) {
|
|||
|
||||
bool _vfsceClose(struct VFile* vf) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
sceIoSyncByFd(vfsce->fd);
|
||||
sceIoSyncByFd(vfsce->fd, 0);
|
||||
return sceIoClose(vfsce->fd) >= 0;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ static void _vfsceUnmap(struct VFile* vf, void* memory, size_t size) {
|
|||
sceIoLseek(vfsce->fd, 0, SEEK_SET);
|
||||
sceIoWrite(vfsce->fd, memory, size);
|
||||
sceIoLseek(vfsce->fd, cur, SEEK_SET);
|
||||
sceIoSyncByFd(vfsce->fd);
|
||||
sceIoSyncByFd(vfsce->fd, 0);
|
||||
mappedMemoryFree(memory, size);
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ bool _vfsceSync(struct VFile* vf, void* buffer, size_t size) {
|
|||
sceIoLseek(vfsce->fd, cur, SEEK_SET);
|
||||
return res == size;
|
||||
}
|
||||
return sceIoSyncByFd(vfsce->fd) >= 0;
|
||||
return sceIoSyncByFd(vfsce->fd, 0) >= 0;
|
||||
}
|
||||
|
||||
struct VDir* VDirOpen(const char* path) {
|
||||
|
|
|
@ -44,8 +44,7 @@ ApplicationUpdater::ApplicationUpdater(ConfigController* config, QObject* parent
|
|||
config->setQtOption("lastUpdateCheck", m_lastCheck);
|
||||
|
||||
if (available && currentVersion() < updateInfo()) {
|
||||
#ifdef Q_OS_WIN
|
||||
// Only works on Windows at the moment
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
ApplicationUpdatePrompt* prompt = new ApplicationUpdatePrompt;
|
||||
connect(prompt, &QDialog::accepted, GBAApp::app(), &GBAApp::restartForUpdate);
|
||||
prompt->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
|
|
@ -25,7 +25,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/input)
|
|||
|
||||
find_package(Qt5 COMPONENTS Core Widgets Network Multimedia)
|
||||
|
||||
if(NOT BUILD_GL AND NOT BUILD_GLES2)
|
||||
if(NOT BUILD_GL AND NOT BUILD_GLES2 AND NOT BUILD_GLES3)
|
||||
message(WARNING "OpenGL is recommended to build the Qt port")
|
||||
endif()
|
||||
|
||||
|
@ -244,6 +244,11 @@ if(APPLE)
|
|||
set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.endrift.${BINARY_NAME}-qt)
|
||||
set_source_files_properties(${CMAKE_SOURCE_DIR}/res/icon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
if(DISTBUILD)
|
||||
set(APPDIR ".")
|
||||
else()
|
||||
set(APPDIR "Applications")
|
||||
endif()
|
||||
endif()
|
||||
if(WIN32)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/res/win.rc.in ${CMAKE_BINARY_DIR}/res/${BINARY_NAME}.rc)
|
||||
|
@ -252,7 +257,7 @@ if(WIN32)
|
|||
endif()
|
||||
if(NOT DEFINED DATADIR)
|
||||
if(APPLE)
|
||||
set(DATADIR Applications/${PROJECT_NAME}.app/Contents/Resources)
|
||||
set(DATADIR ${APPDIR}/${PROJECT_NAME}.app/Contents/Resources)
|
||||
elseif(WIN32 AND NOT WIN32_UNIX_PATHS)
|
||||
set(DATADIR ".")
|
||||
else()
|
||||
|
@ -308,6 +313,9 @@ set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CM
|
|||
|
||||
if(WIN32)
|
||||
set_target_properties(${BINARY_NAME}-qt PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
if(NOT MSVC)
|
||||
target_link_libraries(${BINARY_NAME}-qt -municode)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::Network)
|
||||
|
@ -339,11 +347,11 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
|
|||
|
||||
install(TARGETS ${BINARY_NAME}-qt
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt
|
||||
BUNDLE DESTINATION Applications COMPONENT ${BINARY_NAME}-qt)
|
||||
BUNDLE DESTINATION ${APPDIR} COMPONENT ${BINARY_NAME}-qt)
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/res/qt.desktop DESTINATION share/applications RENAME ${BINARY_NAME}-qt.desktop COMPONENT ${BINARY_NAME}-qt)
|
||||
endif()
|
||||
if(UNIX)
|
||||
if(UNIX AND NOT (APPLE AND DISTBUILD))
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/doc/${BINARY_NAME}-qt.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-qt)
|
||||
endif()
|
||||
if(APPLE OR WIN32)
|
||||
|
@ -376,7 +384,7 @@ if(APPLE)
|
|||
if(DEFINED CROSS_ROOT)
|
||||
set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -R "${CROSS_ROOT}")
|
||||
endif()
|
||||
install(CODE "execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/tools/deploy-mac.py\" -v ${DEPLOY_OPTIONS} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/Applications/${PROJECT_NAME}.app\")")
|
||||
install(CODE "execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/tools/deploy-mac.py\" -v ${DEPLOY_OPTIONS} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${APPDIR}/${PROJECT_NAME}.app\")")
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
if(CMAKE_MAJOR_VERSION EQUAL 3 AND CMAKE_MINOR_VERSION EQUAL 8)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "Display.h"
|
||||
|
||||
#include "CoreController.h"
|
||||
#include "ConfigController.h"
|
||||
#include "DisplayGL.h"
|
||||
#include "DisplayQt.h"
|
||||
|
@ -14,23 +15,23 @@
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
Display::Driver Display::s_driver = Display::Driver::OPENGL;
|
||||
#else
|
||||
Display::Driver Display::s_driver = Display::Driver::QT;
|
||||
#endif
|
||||
|
||||
Display* Display::create(QWidget* parent) {
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
QSurfaceFormat format;
|
||||
format.setSwapInterval(1);
|
||||
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
|
||||
#endif
|
||||
|
||||
switch (s_driver) {
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
case Driver::OPENGL:
|
||||
#if defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
|
||||
format.setVersion(2, 0);
|
||||
} else {
|
||||
|
@ -65,7 +66,7 @@ Display* Display::create(QWidget* parent) {
|
|||
return new DisplayQt(parent);
|
||||
|
||||
default:
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
return new DisplayGL(format, parent);
|
||||
#else
|
||||
return new DisplayQt(parent);
|
||||
|
@ -118,7 +119,7 @@ void Display::configure(ConfigController* config) {
|
|||
interframeBlending(opts->interframeBlending);
|
||||
filter(opts->resampleVideo);
|
||||
config->updateOption("showOSD");
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (opts->shader) {
|
||||
struct VDir* shader = VDirOpen(opts->shader);
|
||||
if (shader && supportsShaders()) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "DisplayGL.h"
|
||||
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMutexLocker>
|
||||
|
@ -24,7 +24,7 @@
|
|||
#ifdef BUILD_GL
|
||||
#include "platform/opengl/gl.h"
|
||||
#endif
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
#include "platform/opengl/gles2.h"
|
||||
#ifdef _WIN32
|
||||
#include <epoxy/wgl.h>
|
||||
|
@ -297,13 +297,13 @@ void PainterGL::create() {
|
|||
#ifdef BUILD_GL
|
||||
mGLContext* glBackend;
|
||||
#endif
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
mGLES2Context* gl2Backend;
|
||||
#endif
|
||||
|
||||
m_window = std::make_unique<QOpenGLPaintDevice>();
|
||||
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
auto version = m_format.version();
|
||||
if (version >= qMakePair(2, 0)) {
|
||||
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
||||
|
@ -329,7 +329,7 @@ void PainterGL::create() {
|
|||
};
|
||||
|
||||
m_backend->init(m_backend, 0);
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (m_supportsShaders) {
|
||||
m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<mGLES2Context*>(m_backend)->initialShader);
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ void PainterGL::destroy() {
|
|||
return;
|
||||
}
|
||||
makeCurrent();
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (m_shader.passes) {
|
||||
mGLES2ShaderFree(&m_shader);
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ void PainterGL::filter(bool filter) {
|
|||
void PainterGL::start() {
|
||||
makeCurrent();
|
||||
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (m_supportsShaders && m_shader.passes) {
|
||||
mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses);
|
||||
}
|
||||
|
@ -524,19 +524,17 @@ void PainterGL::unpause() {
|
|||
}
|
||||
|
||||
void PainterGL::performDraw() {
|
||||
m_painter.begin(m_window.get());
|
||||
m_painter.beginNativePainting();
|
||||
float r = m_surface->devicePixelRatio();
|
||||
m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r);
|
||||
if (m_buffer) {
|
||||
m_backend->postFrame(m_backend, m_buffer);
|
||||
}
|
||||
m_backend->drawFrame(m_backend);
|
||||
m_painter.endNativePainting();
|
||||
if (m_showOSD && m_messagePainter) {
|
||||
m_painter.begin(m_window.get());
|
||||
m_messagePainter->paint(&m_painter);
|
||||
m_painter.end();
|
||||
}
|
||||
m_painter.end();
|
||||
}
|
||||
|
||||
void PainterGL::enqueue(const uint32_t* backing) {
|
||||
|
@ -601,7 +599,7 @@ void PainterGL::setShaders(struct VDir* dir) {
|
|||
if (!supportsShaders()) {
|
||||
return;
|
||||
}
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (m_shader.passes) {
|
||||
mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend));
|
||||
mGLES2ShaderFree(&m_shader);
|
||||
|
@ -615,7 +613,7 @@ void PainterGL::clearShaders() {
|
|||
if (!supportsShaders()) {
|
||||
return;
|
||||
}
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (m_shader.passes) {
|
||||
mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend));
|
||||
mGLES2ShaderFree(&m_shader);
|
||||
|
@ -628,7 +626,7 @@ VideoShader* PainterGL::shaders() {
|
|||
}
|
||||
|
||||
int PainterGL::glTex() {
|
||||
#ifdef BUILD_GLES2
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (supportsShaders()) {
|
||||
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(m_backend);
|
||||
return gl2Backend->tex;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2)
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ CXX_GUARD_START
|
|||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
#include "gl-common.h"
|
||||
#include "platform/opengl/gles2.h"
|
||||
#endif
|
||||
|
@ -72,7 +72,7 @@ struct mSDLRenderer {
|
|||
#ifdef BUILD_GL
|
||||
struct mGLContext gl;
|
||||
#endif
|
||||
#if defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY)
|
||||
struct mGLES2Context gl2;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -716,7 +716,11 @@ static struct VDir* _makeOutDir(const char* testName) {
|
|||
strncpy(pathEnd, testName, len);
|
||||
pathEnd += len;
|
||||
|
||||
#ifndef _WIN32
|
||||
mkdir(path, 0777);
|
||||
#else
|
||||
mkdir(path);
|
||||
#endif
|
||||
|
||||
if (!pos) {
|
||||
break;
|
||||
|
|
|
@ -83,8 +83,8 @@ static Socket _server = INVALID_SOCKET;
|
|||
int main(int argc, char** argv) {
|
||||
#ifdef _3DS
|
||||
UNUSED(_mPerfShutdown);
|
||||
gfxInitDefault();
|
||||
osSetSpeedupEnable(true);
|
||||
gfxInitDefault();
|
||||
osSetSpeedupEnable(true);
|
||||
consoleInit(GFX_BOTTOM, NULL);
|
||||
#elif defined(__SWITCH__)
|
||||
UNUSED(_mPerfShutdown);
|
||||
|
|
|
@ -102,7 +102,7 @@ const struct GUIFontGlyphMetric defaultFontMetrics[128] = {
|
|||
{ 6, 11, { 2, 5, 3, 5 }}, // 0x5D "]"
|
||||
{ 8, 7, { 2, 4, 7, 4 }}, // 0x5E "^"
|
||||
{ 10, 3, { 10, 3, 3, 3 }}, // 0x5F "_"
|
||||
{ 6, 5, { 8, 6, 3, 4 }}, // 0x60 "`"
|
||||
{ 6, 5, { 3, 4, 8, 6 }}, // 0x60 "`"
|
||||
{ 8, 7, { 6, 4, 3, 4 }}, // 0x61 "a"
|
||||
{ 8, 11, { 2, 4, 3, 4 }}, // 0x62 "b"
|
||||
{ 8, 7, { 6, 4, 3, 4 }}, // 0x63 "c"
|
||||
|
@ -158,4 +158,29 @@ const struct GUIIconMetric defaultIconMetrics[] = {
|
|||
[GUI_ICON_DOWN] = { 130, 34, 12, 12 },
|
||||
[GUI_ICON_STATUS_FAST_FORWARD] = { 2, 50, 12, 12 },
|
||||
[GUI_ICON_STATUS_MUTE] = { 17, 50, 14, 12 },
|
||||
[GUI_ICON_9SLICE_EMPTY_NW] = { 162, 1, 8, 8 },
|
||||
[GUI_ICON_9SLICE_EMPTY_N] = { 170, 1, 12, 8 },
|
||||
[GUI_ICON_9SLICE_EMPTY_NE] = { 182, 1, 8, 8 },
|
||||
[GUI_ICON_9SLICE_EMPTY_W] = { 162, 9, 8, 12 },
|
||||
[GUI_ICON_9SLICE_EMPTY_E] = { 182, 9, 8, 12 },
|
||||
[GUI_ICON_9SLICE_EMPTY_SW] = { 162, 23, 8, 8 },
|
||||
[GUI_ICON_9SLICE_EMPTY_S] = { 170, 23, 12, 8 },
|
||||
[GUI_ICON_9SLICE_EMPTY_SE] = { 182, 23, 8, 8 },
|
||||
[GUI_ICON_9SLICE_FILLED_NW] = { 194, 1, 8, 8 },
|
||||
[GUI_ICON_9SLICE_FILLED_N] = { 202, 1, 12, 8 },
|
||||
[GUI_ICON_9SLICE_FILLED_NE] = { 214, 1, 8, 8 },
|
||||
[GUI_ICON_9SLICE_FILLED_W] = { 194, 9, 8, 12 },
|
||||
[GUI_ICON_9SLICE_FILLED_C] = { 202, 9, 12, 12 },
|
||||
[GUI_ICON_9SLICE_FILLED_E] = { 214, 9, 8, 12 },
|
||||
[GUI_ICON_9SLICE_FILLED_SW] = { 194, 23, 8, 8 },
|
||||
[GUI_ICON_9SLICE_FILLED_S] = { 202, 23, 12, 8 },
|
||||
[GUI_ICON_9SLICE_FILLED_SE] = { 214, 23, 8, 8 },
|
||||
[GUI_ICON_9SLICE_CAP_NNW] = { 240, 1, 8, 7 },
|
||||
[GUI_ICON_9SLICE_CAP_NWW] = { 226, 16, 6, 8 },
|
||||
[GUI_ICON_9SLICE_CAP_NNE] = { 232, 1, 8, 7 },
|
||||
[GUI_ICON_9SLICE_CAP_NEE] = { 248, 16, 6, 8 },
|
||||
[GUI_ICON_9SLICE_CAP_SSW] = { 240, 24, 8, 7 },
|
||||
[GUI_ICON_9SLICE_CAP_SWW] = { 226, 8, 6, 8 },
|
||||
[GUI_ICON_9SLICE_CAP_SSE] = { 232, 24, 8, 7 },
|
||||
[GUI_ICON_9SLICE_CAP_SEE] = { 248, 8, 6, 8 },
|
||||
};
|
||||
|
|
|
@ -86,3 +86,55 @@ void GUIFontPrintf(struct GUIFont* font, int x, int y, enum GUIAlignment align,
|
|||
va_end(args);
|
||||
GUIFontPrint(font, x, y, align, color, buffer);
|
||||
}
|
||||
|
||||
void GUIFontDraw9Slice(struct GUIFont* font, int x, int y, int width, int height, uint32_t color, enum GUI9SliceStyle style) {
|
||||
switch (style) {
|
||||
case GUI_9SLICE_EMPTY:
|
||||
case GUI_9SLICE_EMPTY_CAPPED:
|
||||
GUIFontDrawIcon(font, x , y , GUI_ALIGN_LEFT | GUI_ALIGN_TOP , GUI_ORIENT_0, color, GUI_ICON_9SLICE_EMPTY_NW);
|
||||
GUIFontDrawIcon(font, x + width, y , GUI_ALIGN_RIGHT | GUI_ALIGN_TOP , GUI_ORIENT_0, color, GUI_ICON_9SLICE_EMPTY_NE);
|
||||
GUIFontDrawIcon(font, x , y + height, GUI_ALIGN_LEFT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_EMPTY_SW);
|
||||
GUIFontDrawIcon(font, x + width, y + height, GUI_ALIGN_RIGHT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_EMPTY_SE);
|
||||
break;
|
||||
case GUI_9SLICE_FILLED:
|
||||
GUIFontDrawIcon(font, x , y , GUI_ALIGN_LEFT | GUI_ALIGN_TOP , GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILLED_NW);
|
||||
GUIFontDrawIcon(font, x + width, y , GUI_ALIGN_RIGHT | GUI_ALIGN_TOP , GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILLED_NE);
|
||||
GUIFontDrawIcon(font, x , y + height, GUI_ALIGN_LEFT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILLED_SW);
|
||||
GUIFontDrawIcon(font, x + width, y + height, GUI_ALIGN_RIGHT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_FILLED_SE);
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned offX, offY;
|
||||
unsigned endX, endY;
|
||||
GUIFontIconMetrics(font, GUI_ICON_9SLICE_EMPTY_NW, &offX, &offY);
|
||||
GUIFontIconMetrics(font, GUI_ICON_9SLICE_EMPTY_SE, &endX, &endY);
|
||||
|
||||
switch (style) {
|
||||
case GUI_9SLICE_EMPTY:
|
||||
GUIFontDrawIconSize(font, x + offX, y, width - offX - endX, offY, color, GUI_ICON_9SLICE_EMPTY_N);
|
||||
GUIFontDrawIconSize(font, x, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_EMPTY_W);
|
||||
GUIFontDrawIconSize(font, x + offX, y + height - endY, width - offX - endX, offY, color, GUI_ICON_9SLICE_EMPTY_S);
|
||||
GUIFontDrawIconSize(font, x + width - endX, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_EMPTY_E);
|
||||
break;
|
||||
case GUI_9SLICE_FILLED:
|
||||
GUIFontDrawIconSize(font, x + offX, y, width - offX - endX, offY, color, GUI_ICON_9SLICE_FILLED_N);
|
||||
GUIFontDrawIconSize(font, x, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_FILLED_W);
|
||||
GUIFontDrawIconSize(font, x + offX, y + height - endY, width - offX - endX, offY, color, GUI_ICON_9SLICE_FILLED_S);
|
||||
GUIFontDrawIconSize(font, x + width - endX, y + offY, offX, height - offY - endY, color, GUI_ICON_9SLICE_FILLED_E);
|
||||
GUIFontDrawIconSize(font, x + offX, y + offY, width - offX - endX, height - offY - endY, color, GUI_ICON_9SLICE_FILLED_C);
|
||||
break;
|
||||
case GUI_9SLICE_EMPTY_CAPPED:
|
||||
GUIFontDrawIcon(font, x + offX, y, GUI_ALIGN_LEFT | GUI_ALIGN_TOP, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_NNW);
|
||||
GUIFontDrawIcon(font, x, y + offY, GUI_ALIGN_LEFT | GUI_ALIGN_TOP, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_NWW);
|
||||
|
||||
GUIFontDrawIcon(font, x + width - endX, y, GUI_ALIGN_RIGHT | GUI_ALIGN_TOP, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_NNE);
|
||||
GUIFontDrawIcon(font, x + width, y + offY, GUI_ALIGN_RIGHT | GUI_ALIGN_TOP, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_NEE);
|
||||
|
||||
GUIFontDrawIcon(font, x + offX, y + height, GUI_ALIGN_LEFT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_SSW);
|
||||
GUIFontDrawIcon(font, x, y + height - endY, GUI_ALIGN_LEFT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_SWW);
|
||||
|
||||
GUIFontDrawIcon(font, x + width - endX, y + height, GUI_ALIGN_RIGHT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_SSE);
|
||||
GUIFontDrawIcon(font, x + width, y + height - endY, GUI_ALIGN_RIGHT | GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, GUI_ICON_9SLICE_CAP_SEE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue