diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index bb8f7892cf..519da4faa9 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -2,34 +2,34 @@ - Only RetroArch bugs should be filed here. Not core bugs or game bugs - This is not a forum or a help section, this is strictly developer oriented -## Description - -[Description of the bug] - -### Expected behavior - -[What you expected to happen] - -### Actual behavior - -[What is actually happening] - -### Steps to reproduce the bug - -1. [First step] -2. [Second step] -3. [and so on...] - -### Bisect Results +## Description + +[Description of the bug] + +### Expected behavior + +[What you expected to happen] + +### Actual behavior + +[What is actually happening] + +### Steps to reproduce the bug + +1. [First step] +2. [Second step] +3. [and so on...] + +### Bisect Results + +[Try to bisect and tell us when this started happening] + +### Version/Commit +You can find this information under Information/System Information + +- RetroArch: [version/commit] + +### Environment information -[Try to bisect and tell us when this started happening] - -### Version/Commit -You can find this information under Information/System Information - -- RetroArch: [version/commit] - -### Environment information - - OS: [The operating system you're running] -- Compiler: [In case you are running local builds] +- Compiler: [In case you are running local builds] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6ed2410576..faeca1adf3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,58 +1,58 @@ -# Contributing to RetroArch - -If you are a developer and want to contribute to the development of RetroArch, please read this. -If you have found a bug and want to submit a minor patch or a bug report, please read this as well. - -# Submitting a bug report -When submitting a bug report, make sure that the bug is local to RetroArch. -A bug in a libretro core or something deemed to be external is likely to be closed very fast. -If you still suspect a bug in RetroArch, make sure to test with several cores to make sure. - -If you have troubles building RetroArch on Linux/BSD/OSX, make sure to paste shell output of ./configure, -as well as config.log and shell output of make. If building on Windows, just paste shell output of make. - -If the issue occurs during runtime, make sure to paste RetroArch's verbose log. -If using Phoenix frontend, you can find log in (File -> Show Log) after running. -In console, make sure to run with verbose (-v) flag. - -# Pull Requests -Outside contributions are generally only accepted in the form of a pull request. The process is very simple. -Fork RetroArch, make your changes, and issue a pull request on GitHub. This can all be done within the browser. -The changes are reviewed, and might be merged in. If the pull request isn't acceptable at the time, -note that it's possible to continue pushing up commits to your branch. - -If you want to develop a larger feature, -we'd like to discuss this first (ideally on IRC) so that you don't risk developing something -that won't be merged. A pull request with a proof-of-concept is fine, but please indicate so. - -## libretro API -If you wish to add functionality to libretro's API, it can take some time to merge in, because changes -to libretro API will affect other projects as well, and we highly value API/ABI stability. -Features will only be added when deemed *necessary* for a concrete libretro core to function properly. -Features will not be added on basis of hypothetical libretro implementations. - -# Coding style -Having a consistent code style throughout the code base is highly valued. -Please look through the code to get a feel for the coding style. -A pull request may be asked to fix the coding style before submission. -In other cases, a pull request may be followed up with a "style nit commit". - -## Non-obvious things: - - Code should be both ISO C99 and ISO C++ compatible. This dual requirement is for XBox360 and MSVC in general. Think of it as a C++ compatible subset of C99. - - Warnings are not allowed (-Wall). Make sure your code is warning-free. Note that warning sensitivity differs a bit across compiler versions. - - Using deprecated APIs is discouraged. - -# Copyright Headers and AUTHORS -If you have contributed to a part of a source file (a chunk of code that's written by you), -you should add yourself to the copyright header in that file. -If you have contributed significantly -(a feature, a contribution you can "name", e.g. "Added audio driver foo"), you should add yourself to AUTHORS file. -We'd like your full name and email, and which features you have been part of. - -# IRC -Active development happens on IRC. (#retroarch @ irc.freenode.org) -We value discussing things in "real-time". - -# Commit Access -Contributors who show a track record of making good pull requests over time will eventually get commit access to the repo. +# Contributing to RetroArch + +If you are a developer and want to contribute to the development of RetroArch, please read this. +If you have found a bug and want to submit a minor patch or a bug report, please read this as well. + +# Submitting a bug report +When submitting a bug report, make sure that the bug is local to RetroArch. +A bug in a libretro core or something deemed to be external is likely to be closed very fast. +If you still suspect a bug in RetroArch, make sure to test with several cores to make sure. + +If you have troubles building RetroArch on Linux/BSD/OSX, make sure to paste shell output of ./configure, +as well as config.log and shell output of make. If building on Windows, just paste shell output of make. + +If the issue occurs during runtime, make sure to paste RetroArch's verbose log. +If using Phoenix frontend, you can find log in (File -> Show Log) after running. +In console, make sure to run with verbose (-v) flag. + +# Pull Requests +Outside contributions are generally only accepted in the form of a pull request. The process is very simple. +Fork RetroArch, make your changes, and issue a pull request on GitHub. This can all be done within the browser. +The changes are reviewed, and might be merged in. If the pull request isn't acceptable at the time, +note that it's possible to continue pushing up commits to your branch. + +If you want to develop a larger feature, +we'd like to discuss this first (ideally on IRC) so that you don't risk developing something +that won't be merged. A pull request with a proof-of-concept is fine, but please indicate so. + +## libretro API +If you wish to add functionality to libretro's API, it can take some time to merge in, because changes +to libretro API will affect other projects as well, and we highly value API/ABI stability. +Features will only be added when deemed *necessary* for a concrete libretro core to function properly. +Features will not be added on basis of hypothetical libretro implementations. + +# Coding style +Having a consistent code style throughout the code base is highly valued. +Please look through the code to get a feel for the coding style. +A pull request may be asked to fix the coding style before submission. +In other cases, a pull request may be followed up with a "style nit commit". + +## Non-obvious things: + - Code should be both ISO C99 and ISO C++ compatible. This dual requirement is for XBox360 and MSVC in general. Think of it as a C++ compatible subset of C99. + - Warnings are not allowed (-Wall). Make sure your code is warning-free. Note that warning sensitivity differs a bit across compiler versions. + - Using deprecated APIs is discouraged. + +# Copyright Headers and AUTHORS +If you have contributed to a part of a source file (a chunk of code that's written by you), +you should add yourself to the copyright header in that file. +If you have contributed significantly +(a feature, a contribution you can "name", e.g. "Added audio driver foo"), you should add yourself to AUTHORS file. +We'd like your full name and email, and which features you have been part of. + +# IRC +Active development happens on IRC. (#retroarch @ irc.freenode.org) +We value discussing things in "real-time". + +# Commit Access +Contributors who show a track record of making good pull requests over time will eventually get commit access to the repo. This typically happens when the "overhead" of looking through pull requests over time becomes a burden. \ No newline at end of file diff --git a/Makefile.ps3.salamander b/Makefile.ps3.salamander index 37778bf6f4..114ffded25 100644 --- a/Makefile.ps3.salamander +++ b/Makefile.ps3.salamander @@ -1,91 +1,91 @@ -CELL_BUILD_TOOLS = GCC -CELL_SDK ?= /usr/local/cell -HAVE_LOGGER = 0 -CELL_MK_DIR ?= $(CELL_SDK)/samples/mk - -include $(CELL_MK_DIR)/sdk.makedef.mk - -# system platform -system_platform = unix -ifeq ($(shell uname -a),) -EXE_EXT = .exe - system_platform = win -else ifneq ($(findstring Darwin,$(shell uname -a)),) - system_platform = osx -else ifneq ($(findstring MINGW,$(shell uname -a)),) - system_platform = win -endif - -ifeq ($(DEBUG), 1) - PPU_OPTIMIZE_LV := -O0 -g -else - PPU_OPTIMIZE_LV := -O2 -DNDEBUG -endif - -STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe - -INCFLAGS = -I. -Idefines -Ilibretro-common/include -Ideps/libz -DEFINES = -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC - -ifeq ($(DEX_BUILD), 1) -DEFINES += -DDEX_BUILD -endif - -ifeq ($(CEX_BUILD), 1) -DEFINES += -DCEX_BUILD -endif - -ifeq ($(ODE_BUILD), 1) -DEFINES += -DODE_BUILD -endif - -PPU_CFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES) -PPU_CXXFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES) - -PPU_SRCS = frontend/frontend_salamander.c \ - frontend/frontend_driver.c \ - frontend/drivers/platform_ps3.c \ - frontend/drivers/platform_null.c \ - libretro-common/file/file_path.c \ - libretro-common/lists/dir_list.c \ - libretro-common/lists/string_list.c \ - libretro-common/file/retro_dirent.c \ - libretro-common/hash/rhash.c \ - libretro-common/string/stdstring.c \ - libretro-common/encodings/encoding_utf.c \ - libretro-common/compat/compat_strl.c \ - libretro-common/compat/compat_strcasestr.c \ - libretro-common/compat/fopen_utf8.c \ - libretro-common/streams/file_stream.c \ - libretro-common/vfs/vfs_implementation.c \ - libretro-common/file/config_file.c \ - file_path_str.c \ - verbosity.c - -ifeq ($(HAVE_LOGGER), 1) -PPU_CFLAGS += -DHAVE_LOGGER -PPU_SRCS += network/net_logger.c \ - libretro-common/net/net_compat.c \ - libretro-common/net/net_socket.c -endif - -PPU_TARGET = retroarch-salamander_ps3.elf - -ifeq ($(CELL_BUILD_TOOLS),SNC) - PPU_CFLAGS += -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 -Xunroll=1 -Xautovecreg=1 - PPU_CXXFLAGS += -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 -Xunroll=1 -Xautovecreg=1 - PPU_CXXLD = $(CELL_SDK)/host-win32/sn/bin/ps3ppuld.exe - PPU_CLD = $(CELL_SDK)/host-win32/sn/bin/ps3ppuld.exe - PPU_CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe -else - PPU_CFLAGS += -std=gnu99 - PPU_CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe - PPU_CLD = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ld.exe - PPU_CXXLD = $(CELL_SDK)/host-win32/sn/bin/ps3ppuld.exe -endif - -PPU_LDLIBS += -lm -lnet_stub -lnetctl_stub -lio_stub -lsysmodule_stub -lsysutil_stub -lsysutil_game_stub -lfs_stub -lsysutil_np_stub - -MAKE_FSELF = $(CELL_SDK)/host-win32/bin/make_fself.exe - -include $(CELL_MK_DIR)/sdk.target.mk +CELL_BUILD_TOOLS = GCC +CELL_SDK ?= /usr/local/cell +HAVE_LOGGER = 0 +CELL_MK_DIR ?= $(CELL_SDK)/samples/mk + +include $(CELL_MK_DIR)/sdk.makedef.mk + +# system platform +system_platform = unix +ifeq ($(shell uname -a),) +EXE_EXT = .exe + system_platform = win +else ifneq ($(findstring Darwin,$(shell uname -a)),) + system_platform = osx +else ifneq ($(findstring MINGW,$(shell uname -a)),) + system_platform = win +endif + +ifeq ($(DEBUG), 1) + PPU_OPTIMIZE_LV := -O0 -g +else + PPU_OPTIMIZE_LV := -O2 -DNDEBUG +endif + +STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe + +INCFLAGS = -I. -Idefines -Ilibretro-common/include -Ideps/libz +DEFINES = -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC + +ifeq ($(DEX_BUILD), 1) +DEFINES += -DDEX_BUILD +endif + +ifeq ($(CEX_BUILD), 1) +DEFINES += -DCEX_BUILD +endif + +ifeq ($(ODE_BUILD), 1) +DEFINES += -DODE_BUILD +endif + +PPU_CFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES) +PPU_CXXFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES) + +PPU_SRCS = frontend/frontend_salamander.c \ + frontend/frontend_driver.c \ + frontend/drivers/platform_ps3.c \ + frontend/drivers/platform_null.c \ + libretro-common/file/file_path.c \ + libretro-common/lists/dir_list.c \ + libretro-common/lists/string_list.c \ + libretro-common/file/retro_dirent.c \ + libretro-common/hash/rhash.c \ + libretro-common/string/stdstring.c \ + libretro-common/encodings/encoding_utf.c \ + libretro-common/compat/compat_strl.c \ + libretro-common/compat/compat_strcasestr.c \ + libretro-common/compat/fopen_utf8.c \ + libretro-common/streams/file_stream.c \ + libretro-common/vfs/vfs_implementation.c \ + libretro-common/file/config_file.c \ + file_path_str.c \ + verbosity.c + +ifeq ($(HAVE_LOGGER), 1) +PPU_CFLAGS += -DHAVE_LOGGER +PPU_SRCS += network/net_logger.c \ + libretro-common/net/net_compat.c \ + libretro-common/net/net_socket.c +endif + +PPU_TARGET = retroarch-salamander_ps3.elf + +ifeq ($(CELL_BUILD_TOOLS),SNC) + PPU_CFLAGS += -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 -Xunroll=1 -Xautovecreg=1 + PPU_CXXFLAGS += -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 -Xunroll=1 -Xautovecreg=1 + PPU_CXXLD = $(CELL_SDK)/host-win32/sn/bin/ps3ppuld.exe + PPU_CLD = $(CELL_SDK)/host-win32/sn/bin/ps3ppuld.exe + PPU_CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe +else + PPU_CFLAGS += -std=gnu99 + PPU_CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe + PPU_CLD = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ld.exe + PPU_CXXLD = $(CELL_SDK)/host-win32/sn/bin/ps3ppuld.exe +endif + +PPU_LDLIBS += -lm -lnet_stub -lnetctl_stub -lio_stub -lsysmodule_stub -lsysutil_stub -lsysutil_game_stub -lfs_stub -lsysutil_np_stub + +MAKE_FSELF = $(CELL_SDK)/host-win32/bin/make_fself.exe + +include $(CELL_MK_DIR)/sdk.target.mk diff --git a/audio/drivers/coreaudio3.m b/audio/drivers/coreaudio3.m index 279a4f2612..298dd3cb19 100644 --- a/audio/drivers/coreaudio3.m +++ b/audio/drivers/coreaudio3.m @@ -1,382 +1,382 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2019 - Stuart Carnie - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#import -#import -#import - -#include -#include -#include -#include - -#include "../audio_driver.h" - -#pragma mark - ringbuffer - -typedef struct ringbuffer -{ - float *buffer; - size_t cap; - atomic_int len; - size_t writePtr; - size_t readPtr; -} ringbuffer_t; - -typedef ringbuffer_t * ringbuffer_h; - -static inline size_t rb_len(ringbuffer_h r) -{ - return atomic_load_explicit(&r->len, memory_order_relaxed); -} - -static inline size_t rb_cap(ringbuffer_h r) -{ - return (r->readPtr + r->cap - r->writePtr) % r->cap; -} - -static inline size_t rb_avail(ringbuffer_h r) -{ - return r->cap - rb_len(r); -} - -static inline void rb_advance_write(ringbuffer_h r) -{ - r->writePtr = (r->writePtr + 1) % r->cap; -} - -static inline void rb_advance_write_n(ringbuffer_h r, size_t n) -{ - r->writePtr = (r->writePtr + n) % r->cap; -} - -static inline void rb_advance_read(ringbuffer_h r) -{ - r->readPtr = (r->readPtr + 1) % r->cap; -} - -static inline void rb_len_add(ringbuffer_h r, int n) -{ - atomic_fetch_add(&r->len, n); -} - -static inline void rb_len_sub(ringbuffer_h r, int n) -{ - atomic_fetch_sub(&r->len, n); -} - -static void rb_init(ringbuffer_h r, size_t cap) -{ - r->buffer = malloc(cap * sizeof(float)); - r->cap = cap; - atomic_init(&r->len, 0); - r->writePtr = 0; - r->readPtr = 0; -} - -static void rb_free(ringbuffer_h r) -{ - free(r->buffer); - bzero(r, sizeof(*r)); -} - -#define UNLIKELY(x) __builtin_expect((x), 0) -#define LIKELY(x) __builtin_expect((x), 1) - -static void rb_write_data(ringbuffer_h r, const float *data, size_t len) -{ - size_t avail = rb_avail(r); - size_t n = MIN(len, avail); - size_t first_write = n; - size_t rest_write = 0; - - if (r->writePtr + n > r->cap) - { - first_write = r->cap - r->writePtr; - rest_write = n - first_write; - } - - memcpy(r->buffer + r->writePtr, data, first_write*sizeof(float)); - memcpy(r->buffer, data + first_write, rest_write*sizeof(float)); - - rb_advance_write_n(r, n); - rb_len_add(r, (int)n); -} - -static void rb_read_data(ringbuffer_h r, float *d0, float *d1, size_t len) -{ - size_t need = len*2; - - do { - size_t have = rb_len(r); - size_t n = MIN(have, need); - int i = 0; - for (; i < n/2; i++) - { - d0[i] = r->buffer[r->readPtr]; - rb_advance_read(r); - d1[i] = r->buffer[r->readPtr]; - rb_advance_read(r); - } - - need -= n; - rb_len_sub(r, (int)n); - - if (UNLIKELY(need > 0)) - { - /* we got more data */ - if (rb_len(r) > 0) - continue; - - // underflow - const float quiet = 0.0f; - size_t fill = (need/2)*sizeof(float); - memset_pattern4(&d0[i], &quiet, fill); - memset_pattern4(&d1[i], &quiet, fill); - } - } while (0); -} - -#pragma mark - CoreAudio3 - -static bool g_interrupted; - -@interface CoreAudio3 : NSObject { - ringbuffer_t _rb; - dispatch_semaphore_t _sema; - AUAudioUnit *_au; - size_t _bufferSize; - BOOL _nonBlock; -} - -@property (nonatomic, readwrite) BOOL nonBlock; -@property (nonatomic, readonly) BOOL paused; -@property (nonatomic, readonly) size_t writeAvailableInBytes; -@property (nonatomic, readonly) size_t bufferSizeInBytes; - -- (instancetype)initWithRate:(NSUInteger)rate - latency:(NSUInteger)latency; -- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples; -- (void)start; -- (void)stop; - -@end - -@implementation CoreAudio3 - -- (instancetype)initWithRate:(NSUInteger)rate - latency:(NSUInteger)latency { - if (self = [super init]) - { - _sema = dispatch_semaphore_create(0); - - _bufferSize = (latency * rate) / 1000; - _bufferSize *= 2; // stereo - rb_init(&_rb, _bufferSize); - - AudioComponentDescription desc = { - .componentType = kAudioUnitType_Output, - .componentSubType = kAudioUnitSubType_DefaultOutput, - .componentManufacturer = kAudioUnitManufacturer_Apple, - }; - - NSError *err; - AUAudioUnit *au = [[AUAudioUnit alloc] initWithComponentDescription:desc error:&err]; - if (err != nil) - return nil; - - AVAudioFormat *format = au.outputBusses[0].format; - if (format.channelCount != 2) - return nil; - - AVAudioFormat *renderFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:rate channels:2]; - [au.inputBusses[0] setFormat:renderFormat error:&err]; - if (err != nil) - return nil; - - ringbuffer_h rb = &_rb; - __block dispatch_semaphore_t sema = _sema; - au.outputProvider = ^AUAudioUnitStatus(AudioUnitRenderActionFlags * actionFlags, const AudioTimeStamp * timestamp, AUAudioFrameCount frameCount, NSInteger inputBusNumber, AudioBufferList * inputData) { - rb_read_data(rb, inputData->mBuffers[0].mData, inputData->mBuffers[1].mData, frameCount); - dispatch_semaphore_signal(sema); - return 0; - }; - - [au allocateRenderResourcesAndReturnError:&err]; - if (err != nil) - return nil; - - _au = au; - - RARCH_LOG("[CoreAudio3]: Using buffer size of %u bytes: (latency = %u ms)\n", (unsigned)self.bufferSizeInBytes, latency); - - [self start]; - } - return self; -} - -- (void)dealloc { - rb_free(&_rb); -} - -- (BOOL)paused { - return !_au.running; -} - -- (size_t)bufferSizeInBytes { - return _bufferSize * sizeof(float); -} - -- (size_t)writeAvailableInBytes { - return rb_avail(&_rb) * sizeof(float); -} - -- (void)start { - NSError *err; - [_au startHardwareAndReturnError:&err]; -} - -- (void)stop { - [_au stopHardware]; -} - -- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples { - size_t written = 0; - while (!g_interrupted && samples > 0) - { - size_t write_avail = rb_avail(&_rb); - if (write_avail > samples) - write_avail = samples; - - rb_write_data(&_rb, data, write_avail); - data += write_avail; - written += write_avail; - samples -= write_avail; - - if (_nonBlock) - break; - - if (write_avail == 0) - dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER); - } - - return written; -} - -@end - -static void coreaudio3_free(void *data) -{ - CoreAudio3 *dev = (__bridge_transfer CoreAudio3 *)data; - if (dev == nil) - return; - - [dev stop]; - dev = nil; -} - -static void *coreaudio3_init(const char *device, - unsigned rate, unsigned latency, - unsigned block_frames, - unsigned *new_rate) -{ - CoreAudio3 *dev = [[CoreAudio3 alloc] initWithRate:rate - latency:latency]; - - *new_rate = rate; - - return (__bridge_retained void *)dev; -} - -static ssize_t coreaudio3_write(void *data, const void *buf_, size_t size) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - return [dev writeFloat:(const float *)buf_ samples:size/sizeof(float)] * sizeof(float); -} - -static void coreaudio3_set_nonblock_state(void *data, bool state) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - if (dev == nil) - return; - - dev.nonBlock = state; -} - -static bool coreaudio3_alive(void *data) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - if (dev == nil) - return NO; - - return !dev.paused; -} - -static bool coreaudio3_stop(void *data) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - if (dev == nil) - return NO; - - [dev stop]; - return dev.paused; -} - -static bool coreaudio3_start(void *data, bool is_shutdown) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - if (dev == nil) - return NO; - - [dev start]; - return !dev.paused; -} - -static bool coreaudio3_use_float(void *data) -{ - return YES; -} - -static size_t coreaudio3_write_avail(void *data) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - if (dev == nil) - return 0; - - return dev.writeAvailableInBytes; -} - -static size_t coreaudio3_buffer_size(void *data) -{ - CoreAudio3 *dev = (__bridge CoreAudio3 *)data; - if (dev == nil) - return 0; - - return dev.bufferSizeInBytes; -} - -audio_driver_t audio_coreaudio3 = { - coreaudio3_init, - coreaudio3_write, - coreaudio3_stop, - coreaudio3_start, - coreaudio3_alive, - coreaudio3_set_nonblock_state, - coreaudio3_free, - coreaudio3_use_float, - "coreaudio3", - coreaudio3_write_avail, - coreaudio3_buffer_size, -}; +/* RetroArch - A frontend for libretro. + * Copyright (C) 2019 - Stuart Carnie + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#import +#import +#import + +#include +#include +#include +#include + +#include "../audio_driver.h" + +#pragma mark - ringbuffer + +typedef struct ringbuffer +{ + float *buffer; + size_t cap; + atomic_int len; + size_t writePtr; + size_t readPtr; +} ringbuffer_t; + +typedef ringbuffer_t * ringbuffer_h; + +static inline size_t rb_len(ringbuffer_h r) +{ + return atomic_load_explicit(&r->len, memory_order_relaxed); +} + +static inline size_t rb_cap(ringbuffer_h r) +{ + return (r->readPtr + r->cap - r->writePtr) % r->cap; +} + +static inline size_t rb_avail(ringbuffer_h r) +{ + return r->cap - rb_len(r); +} + +static inline void rb_advance_write(ringbuffer_h r) +{ + r->writePtr = (r->writePtr + 1) % r->cap; +} + +static inline void rb_advance_write_n(ringbuffer_h r, size_t n) +{ + r->writePtr = (r->writePtr + n) % r->cap; +} + +static inline void rb_advance_read(ringbuffer_h r) +{ + r->readPtr = (r->readPtr + 1) % r->cap; +} + +static inline void rb_len_add(ringbuffer_h r, int n) +{ + atomic_fetch_add(&r->len, n); +} + +static inline void rb_len_sub(ringbuffer_h r, int n) +{ + atomic_fetch_sub(&r->len, n); +} + +static void rb_init(ringbuffer_h r, size_t cap) +{ + r->buffer = malloc(cap * sizeof(float)); + r->cap = cap; + atomic_init(&r->len, 0); + r->writePtr = 0; + r->readPtr = 0; +} + +static void rb_free(ringbuffer_h r) +{ + free(r->buffer); + bzero(r, sizeof(*r)); +} + +#define UNLIKELY(x) __builtin_expect((x), 0) +#define LIKELY(x) __builtin_expect((x), 1) + +static void rb_write_data(ringbuffer_h r, const float *data, size_t len) +{ + size_t avail = rb_avail(r); + size_t n = MIN(len, avail); + size_t first_write = n; + size_t rest_write = 0; + + if (r->writePtr + n > r->cap) + { + first_write = r->cap - r->writePtr; + rest_write = n - first_write; + } + + memcpy(r->buffer + r->writePtr, data, first_write*sizeof(float)); + memcpy(r->buffer, data + first_write, rest_write*sizeof(float)); + + rb_advance_write_n(r, n); + rb_len_add(r, (int)n); +} + +static void rb_read_data(ringbuffer_h r, float *d0, float *d1, size_t len) +{ + size_t need = len*2; + + do { + size_t have = rb_len(r); + size_t n = MIN(have, need); + int i = 0; + for (; i < n/2; i++) + { + d0[i] = r->buffer[r->readPtr]; + rb_advance_read(r); + d1[i] = r->buffer[r->readPtr]; + rb_advance_read(r); + } + + need -= n; + rb_len_sub(r, (int)n); + + if (UNLIKELY(need > 0)) + { + /* we got more data */ + if (rb_len(r) > 0) + continue; + + // underflow + const float quiet = 0.0f; + size_t fill = (need/2)*sizeof(float); + memset_pattern4(&d0[i], &quiet, fill); + memset_pattern4(&d1[i], &quiet, fill); + } + } while (0); +} + +#pragma mark - CoreAudio3 + +static bool g_interrupted; + +@interface CoreAudio3 : NSObject { + ringbuffer_t _rb; + dispatch_semaphore_t _sema; + AUAudioUnit *_au; + size_t _bufferSize; + BOOL _nonBlock; +} + +@property (nonatomic, readwrite) BOOL nonBlock; +@property (nonatomic, readonly) BOOL paused; +@property (nonatomic, readonly) size_t writeAvailableInBytes; +@property (nonatomic, readonly) size_t bufferSizeInBytes; + +- (instancetype)initWithRate:(NSUInteger)rate + latency:(NSUInteger)latency; +- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples; +- (void)start; +- (void)stop; + +@end + +@implementation CoreAudio3 + +- (instancetype)initWithRate:(NSUInteger)rate + latency:(NSUInteger)latency { + if (self = [super init]) + { + _sema = dispatch_semaphore_create(0); + + _bufferSize = (latency * rate) / 1000; + _bufferSize *= 2; // stereo + rb_init(&_rb, _bufferSize); + + AudioComponentDescription desc = { + .componentType = kAudioUnitType_Output, + .componentSubType = kAudioUnitSubType_DefaultOutput, + .componentManufacturer = kAudioUnitManufacturer_Apple, + }; + + NSError *err; + AUAudioUnit *au = [[AUAudioUnit alloc] initWithComponentDescription:desc error:&err]; + if (err != nil) + return nil; + + AVAudioFormat *format = au.outputBusses[0].format; + if (format.channelCount != 2) + return nil; + + AVAudioFormat *renderFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:rate channels:2]; + [au.inputBusses[0] setFormat:renderFormat error:&err]; + if (err != nil) + return nil; + + ringbuffer_h rb = &_rb; + __block dispatch_semaphore_t sema = _sema; + au.outputProvider = ^AUAudioUnitStatus(AudioUnitRenderActionFlags * actionFlags, const AudioTimeStamp * timestamp, AUAudioFrameCount frameCount, NSInteger inputBusNumber, AudioBufferList * inputData) { + rb_read_data(rb, inputData->mBuffers[0].mData, inputData->mBuffers[1].mData, frameCount); + dispatch_semaphore_signal(sema); + return 0; + }; + + [au allocateRenderResourcesAndReturnError:&err]; + if (err != nil) + return nil; + + _au = au; + + RARCH_LOG("[CoreAudio3]: Using buffer size of %u bytes: (latency = %u ms)\n", (unsigned)self.bufferSizeInBytes, latency); + + [self start]; + } + return self; +} + +- (void)dealloc { + rb_free(&_rb); +} + +- (BOOL)paused { + return !_au.running; +} + +- (size_t)bufferSizeInBytes { + return _bufferSize * sizeof(float); +} + +- (size_t)writeAvailableInBytes { + return rb_avail(&_rb) * sizeof(float); +} + +- (void)start { + NSError *err; + [_au startHardwareAndReturnError:&err]; +} + +- (void)stop { + [_au stopHardware]; +} + +- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples { + size_t written = 0; + while (!g_interrupted && samples > 0) + { + size_t write_avail = rb_avail(&_rb); + if (write_avail > samples) + write_avail = samples; + + rb_write_data(&_rb, data, write_avail); + data += write_avail; + written += write_avail; + samples -= write_avail; + + if (_nonBlock) + break; + + if (write_avail == 0) + dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER); + } + + return written; +} + +@end + +static void coreaudio3_free(void *data) +{ + CoreAudio3 *dev = (__bridge_transfer CoreAudio3 *)data; + if (dev == nil) + return; + + [dev stop]; + dev = nil; +} + +static void *coreaudio3_init(const char *device, + unsigned rate, unsigned latency, + unsigned block_frames, + unsigned *new_rate) +{ + CoreAudio3 *dev = [[CoreAudio3 alloc] initWithRate:rate + latency:latency]; + + *new_rate = rate; + + return (__bridge_retained void *)dev; +} + +static ssize_t coreaudio3_write(void *data, const void *buf_, size_t size) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + return [dev writeFloat:(const float *)buf_ samples:size/sizeof(float)] * sizeof(float); +} + +static void coreaudio3_set_nonblock_state(void *data, bool state) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + if (dev == nil) + return; + + dev.nonBlock = state; +} + +static bool coreaudio3_alive(void *data) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + if (dev == nil) + return NO; + + return !dev.paused; +} + +static bool coreaudio3_stop(void *data) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + if (dev == nil) + return NO; + + [dev stop]; + return dev.paused; +} + +static bool coreaudio3_start(void *data, bool is_shutdown) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + if (dev == nil) + return NO; + + [dev start]; + return !dev.paused; +} + +static bool coreaudio3_use_float(void *data) +{ + return YES; +} + +static size_t coreaudio3_write_avail(void *data) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + if (dev == nil) + return 0; + + return dev.writeAvailableInBytes; +} + +static size_t coreaudio3_buffer_size(void *data) +{ + CoreAudio3 *dev = (__bridge CoreAudio3 *)data; + if (dev == nil) + return 0; + + return dev.bufferSizeInBytes; +} + +audio_driver_t audio_coreaudio3 = { + coreaudio3_init, + coreaudio3_write, + coreaudio3_stop, + coreaudio3_start, + coreaudio3_alive, + coreaudio3_set_nonblock_state, + coreaudio3_free, + coreaudio3_use_float, + "coreaudio3", + coreaudio3_write_avail, + coreaudio3_buffer_size, +}; diff --git a/audio/drivers/xaudio29.h b/audio/drivers/xaudio29.h index 46f5d616ca..c0334a5cb4 100644 --- a/audio/drivers/xaudio29.h +++ b/audio/drivers/xaudio29.h @@ -1,1306 +1,1306 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2018 - Krzysztof HaƂadyn - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - - /************************************************************************** - * - * Copyright (c) Microsoft Corporation. All rights reserved. - * - * File: xaudio2.h - * Content: Declarations for the XAudio2 game audio API. - * - **************************************************************************/ - - /* Modified slightly to build without requiring the WinRT compiler since that is only available in C++ sources */ - -#ifdef _MSC_VER -#pragma once -#endif - -#ifndef __XAUDIO2_INCLUDED__ -#define __XAUDIO2_INCLUDED__ - -#include - -#include - -#if(_WIN32_WINNT < _WIN32_WINNT_WIN8) -#error "This version of XAudio2 is available only in Windows 8 or later. Use the XAudio2 headers and libraries from the DirectX SDK with applications that target Windows 7 and earlier versions." -#endif // (_WIN32_WINNT < _WIN32_WINNT_WIN8) - -#include - -#pragma region Application Family -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_TV_APP | WINAPI_PARTITION_TV_TITLE) - -// Current name of the DLL shipped in the same SDK as this header. -// The name reflects the current version -#if(_WIN32_WINNT >= _WIN32_WINNT_WIN10) -#define XAUDIO2_DLL_A "xaudio2_9.dll" -#define XAUDIO2_DLL_W L"xaudio2_9.dll" -#define XAUDIO2D_DLL_A "xaudio2_9d.dll" -#define XAUDIO2D_DLL_W L"xaudio2_9d.dll" -#else -#define XAUDIO2_DLL_A "xaudio2_8.dll" -#define XAUDIO2_DLL_W L"xaudio2_8.dll" -#define XAUDIO2D_DLL_A "xaudio2_8.dll" -#define XAUDIO2D_DLL_W L"xaudio2_8.dll" -#endif - -#ifdef UNICODE -#define XAUDIO2_DLL XAUDIO2_DLL_W -#define XAUDIO2D_DLL XAUDIO2D_DLL_W -#else -#define XAUDIO2_DLL XAUDIO2_DLL_A -#define XAUDIO2D_DLL XAUDIO2D_DLL_A -#endif - - -/************************************************************************** - * - * XAudio2 COM object class and interface IDs. - * - **************************************************************************/ - -#include - -#if defined(__cplusplus__) && defined(__WINRT__) - -#if(_WIN32_WINNT >= _WIN32_WINNT_WIN10) - // XAudio 2.9 -interface __declspec(uuid("2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D")) IXAudio2; -#else - // XAudio 2.8 -interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2; -#endif - -#else - - /* Modified for C support */ -#define DEFINE_GUID_X(n, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - static const GUID n = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -#define DEFINE_CLSID_X(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - DEFINE_GUID_X(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) -#define DEFINE_IID_X(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - DEFINE_GUID_X(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) - -#if(_WIN32_WINNT >= _WIN32_WINNT_WIN10) -DEFINE_IID_X(IXAudio2, 2B02E3CF, 2E0B, 4ec3, BE, 45, 1B, 2A, 3F, E7, 21, 0D); -#else -DEFINE_IID_X(IXAudio2, 60d8dac8, 5aa1, 4e8e, b5, 97, 2f, 5e, 28, 83, d4, 84); -#endif - -#endif - - -// Ignore the rest of this header if only the GUID definitions were requested -#ifndef GUID_DEFS_ONLY - -#include // Windows COM declarations -#include // Markers for documenting API semantics -#include // Basic data types and constants for audio work -#include // For AUDIO_STREAM_CATEGORY - -// All structures defined in this file use tight field packing -#pragma pack(push, 1) - - -/************************************************************************** - * - * XAudio2 constants, flags and error codes. - * - **************************************************************************/ - - // Numeric boundary values -#define XAUDIO2_MAX_BUFFER_BYTES 0x80000000 // Maximum bytes allowed in a source buffer -#define XAUDIO2_MAX_QUEUED_BUFFERS 64 // Maximum buffers allowed in a voice queue -#define XAUDIO2_MAX_BUFFERS_SYSTEM 2 // Maximum buffers allowed for system threads (Xbox 360 only) -#define XAUDIO2_MAX_AUDIO_CHANNELS 64 // Maximum channels in an audio stream -#define XAUDIO2_MIN_SAMPLE_RATE 1000 // Minimum audio sample rate supported -#define XAUDIO2_MAX_SAMPLE_RATE 200000 // Maximum audio sample rate supported -#define XAUDIO2_MAX_VOLUME_LEVEL 16777216.0f // Maximum acceptable volume level (2^24) -#define XAUDIO2_MIN_FREQ_RATIO (1/1024.0f) // Minimum SetFrequencyRatio argument -#define XAUDIO2_MAX_FREQ_RATIO 1024.0f // Maximum MaxFrequencyRatio argument -#define XAUDIO2_DEFAULT_FREQ_RATIO 2.0f // Default MaxFrequencyRatio argument -#define XAUDIO2_MAX_FILTER_ONEOVERQ 1.5f // Maximum XAUDIO2_FILTER_PARAMETERS.OneOverQ -#define XAUDIO2_MAX_FILTER_FREQUENCY 1.0f // Maximum XAUDIO2_FILTER_PARAMETERS.Frequency -#define XAUDIO2_MAX_LOOP_COUNT 254 // Maximum non-infinite XAUDIO2_BUFFER.LoopCount -#define XAUDIO2_MAX_INSTANCES 8 // Maximum simultaneous XAudio2 objects on Xbox 360 - -// For XMA voices on Xbox 360 there is an additional restriction on the MaxFrequencyRatio -// argument and the voice's sample rate: the product of these numbers cannot exceed 600000 -// for one-channel voices or 300000 for voices with more than one channel. -#define XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MONO 600000 -#define XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MULTICHANNEL 300000 - -// Numeric values with special meanings -#define XAUDIO2_COMMIT_NOW 0 // Used as an OperationSet argument -#define XAUDIO2_COMMIT_ALL 0 // Used in IXAudio2::CommitChanges -#define XAUDIO2_INVALID_OPSET (UINT32)(-1) // Not allowed for OperationSet arguments -#define XAUDIO2_NO_LOOP_REGION 0 // Used in XAUDIO2_BUFFER.LoopCount -#define XAUDIO2_LOOP_INFINITE 255 // Used in XAUDIO2_BUFFER.LoopCount -#define XAUDIO2_DEFAULT_CHANNELS 0 // Used in CreateMasteringVoice -#define XAUDIO2_DEFAULT_SAMPLERATE 0 // Used in CreateMasteringVoice - -// Flags -#define XAUDIO2_DEBUG_ENGINE 0x0001 // Used in XAudio2Create -#define XAUDIO2_VOICE_NOPITCH 0x0002 // Used in IXAudio2::CreateSourceVoice -#define XAUDIO2_VOICE_NOSRC 0x0004 // Used in IXAudio2::CreateSourceVoice -#define XAUDIO2_VOICE_USEFILTER 0x0008 // Used in IXAudio2::CreateSource/SubmixVoice -#define XAUDIO2_PLAY_TAILS 0x0020 // Used in IXAudio2SourceVoice::Stop -#define XAUDIO2_END_OF_STREAM 0x0040 // Used in XAUDIO2_BUFFER.Flags -#define XAUDIO2_SEND_USEFILTER 0x0080 // Used in XAUDIO2_SEND_DESCRIPTOR.Flags -#define XAUDIO2_VOICE_NOSAMPLESPLAYED 0x0100 // Used in IXAudio2SourceVoice::GetState -#define XAUDIO2_STOP_ENGINE_WHEN_IDLE 0x2000 // Used in XAudio2Create to force the engine to Stop when no source voices are Started, and Start when a voice is Started -#define XAUDIO2_1024_QUANTUM 0x8000 // Used in XAudio2Create to specify nondefault processing quantum of 21.33 ms (1024 samples at 48KHz) -#define XAUDIO2_NO_VIRTUAL_AUDIO_CLIENT 0x10000 // Used in CreateMasteringVoice to create a virtual audio client - -// Default parameters for the built-in filter -#define XAUDIO2_DEFAULT_FILTER_TYPE LowPassFilter -#define XAUDIO2_DEFAULT_FILTER_FREQUENCY XAUDIO2_MAX_FILTER_FREQUENCY -#define XAUDIO2_DEFAULT_FILTER_ONEOVERQ 1.0f - -// Internal XAudio2 constants -// The audio frame quantum can be calculated by reducing the fraction: -// SamplesPerAudioFrame / SamplesPerSecond -#define XAUDIO2_QUANTUM_NUMERATOR 1 // On Windows, XAudio2 processes audio -#define XAUDIO2_QUANTUM_DENOMINATOR 100 // in 10ms chunks (= 1/100 seconds) -#define XAUDIO2_QUANTUM_MS (1000.0f * XAUDIO2_QUANTUM_NUMERATOR / XAUDIO2_QUANTUM_DENOMINATOR) - -// XAudio2 error codes -#define FACILITY_XAUDIO2 0x896 -#define XAUDIO2_E_INVALID_CALL 0x88960001 // An API call or one of its arguments was illegal -#define XAUDIO2_E_XMA_DECODER_ERROR 0x88960002 // The XMA hardware suffered an unrecoverable error -#define XAUDIO2_E_XAPO_CREATION_FAILED 0x88960003 // XAudio2 failed to initialize an XAPO effect -#define XAUDIO2_E_DEVICE_INVALIDATED 0x88960004 // An audio device became unusable (unplugged, etc) - -/************************************************************************** - * - * Forward declarations for the XAudio2 interfaces. - * - **************************************************************************/ - -#ifdef __cplusplus -#define FWD_DECLARE(x) interface x -#else -#define FWD_DECLARE(x) typedef interface x x -#endif - -FWD_DECLARE(IXAudio2); -FWD_DECLARE(IXAudio2Voice); -FWD_DECLARE(IXAudio2SourceVoice); -FWD_DECLARE(IXAudio2SubmixVoice); -FWD_DECLARE(IXAudio2MasteringVoice); -FWD_DECLARE(IXAudio2EngineCallback); -FWD_DECLARE(IXAudio2VoiceCallback); - - -/************************************************************************** - * - * XAudio2 structures and enumerations. - * - **************************************************************************/ - - // Used in XAudio2Create, specifies which CPU(s) to use. -typedef UINT32 XAUDIO2_PROCESSOR; -#define Processor1 0x00000001 -#define Processor2 0x00000002 -#define Processor3 0x00000004 -#define Processor4 0x00000008 -#define Processor5 0x00000010 -#define Processor6 0x00000020 -#define Processor7 0x00000040 -#define Processor8 0x00000080 -#define Processor9 0x00000100 -#define Processor10 0x00000200 -#define Processor11 0x00000400 -#define Processor12 0x00000800 -#define Processor13 0x00001000 -#define Processor14 0x00002000 -#define Processor15 0x00004000 -#define Processor16 0x00008000 -#define Processor17 0x00010000 -#define Processor18 0x00020000 -#define Processor19 0x00040000 -#define Processor20 0x00080000 -#define Processor21 0x00100000 -#define Processor22 0x00200000 -#define Processor23 0x00400000 -#define Processor24 0x00800000 -#define Processor25 0x01000000 -#define Processor26 0x02000000 -#define Processor27 0x04000000 -#define Processor28 0x08000000 -#define Processor29 0x10000000 -#define Processor30 0x20000000 -#define Processor31 0x40000000 -#define Processor32 0x80000000 -#define XAUDIO2_ANY_PROCESSOR 0xffffffff -#define XAUDIO2_DEFAULT_PROCESSOR Processor1 - -// Returned by IXAudio2Voice::GetVoiceDetails -typedef struct XAUDIO2_VOICE_DETAILS -{ - UINT32 CreationFlags; // Flags the voice was created with. - UINT32 ActiveFlags; // Flags currently active. - UINT32 InputChannels; // Channels in the voice's input audio. - UINT32 InputSampleRate; // Sample rate of the voice's input audio. -} XAUDIO2_VOICE_DETAILS; - -// Used in XAUDIO2_VOICE_SENDS below -typedef struct XAUDIO2_SEND_DESCRIPTOR -{ - UINT32 Flags; // Either 0 or XAUDIO2_SEND_USEFILTER. - IXAudio2Voice* pOutputVoice; // This send's destination voice. -} XAUDIO2_SEND_DESCRIPTOR; - -// Used in the voice creation functions and in IXAudio2Voice::SetOutputVoices -typedef struct XAUDIO2_VOICE_SENDS -{ - UINT32 SendCount; // Number of sends from this voice. - XAUDIO2_SEND_DESCRIPTOR* pSends; // Array of SendCount send descriptors. -} XAUDIO2_VOICE_SENDS; - -// Used in XAUDIO2_EFFECT_CHAIN below -typedef struct XAUDIO2_EFFECT_DESCRIPTOR -{ - IUnknown* pEffect; // Pointer to the effect object's IUnknown interface. - BOOL InitialState; // TRUE if the effect should begin in the enabled state. - UINT32 OutputChannels; // How many output channels the effect should produce. -} XAUDIO2_EFFECT_DESCRIPTOR; - -// Used in the voice creation functions and in IXAudio2Voice::SetEffectChain -typedef struct XAUDIO2_EFFECT_CHAIN -{ - UINT32 EffectCount; // Number of effects in this voice's effect chain. - XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors; // Array of effect descriptors. -} XAUDIO2_EFFECT_CHAIN; - -// Used in XAUDIO2_FILTER_PARAMETERS below -typedef enum XAUDIO2_FILTER_TYPE -{ - LowPassFilter, // Attenuates frequencies above the cutoff frequency (state-variable filter). - BandPassFilter, // Attenuates frequencies outside a given range (state-variable filter). - HighPassFilter, // Attenuates frequencies below the cutoff frequency (state-variable filter). - NotchFilter, // Attenuates frequencies inside a given range (state-variable filter). - LowPassOnePoleFilter, // Attenuates frequencies above the cutoff frequency (one-pole filter, XAUDIO2_FILTER_PARAMETERS.OneOverQ has no effect) - HighPassOnePoleFilter // Attenuates frequencies below the cutoff frequency (one-pole filter, XAUDIO2_FILTER_PARAMETERS.OneOverQ has no effect) -} XAUDIO2_FILTER_TYPE; - -// Used in IXAudio2Voice::Set/GetFilterParameters and Set/GetOutputFilterParameters -typedef struct XAUDIO2_FILTER_PARAMETERS -{ - XAUDIO2_FILTER_TYPE Type; // Filter type. - float Frequency; // Filter coefficient. - // must be >= 0 and <= XAUDIO2_MAX_FILTER_FREQUENCY - // See XAudio2CutoffFrequencyToRadians() for state-variable filter types and - // XAudio2CutoffFrequencyToOnePoleCoefficient() for one-pole filter types. - float OneOverQ; // Reciprocal of the filter's quality factor Q; - // must be > 0 and <= XAUDIO2_MAX_FILTER_ONEOVERQ. - // Has no effect for one-pole filters. -} XAUDIO2_FILTER_PARAMETERS; - -// Used in IXAudio2SourceVoice::SubmitSourceBuffer -typedef struct XAUDIO2_BUFFER -{ - UINT32 Flags; // Either 0 or XAUDIO2_END_OF_STREAM. - UINT32 AudioBytes; // Size of the audio data buffer in bytes. - const BYTE* pAudioData; // Pointer to the audio data buffer. - UINT32 PlayBegin; // First sample in this buffer to be played. - UINT32 PlayLength; // Length of the region to be played in samples, - // or 0 to play the whole buffer. - UINT32 LoopBegin; // First sample of the region to be looped. - UINT32 LoopLength; // Length of the desired loop region in samples, - // or 0 to loop the entire buffer. - UINT32 LoopCount; // Number of times to repeat the loop region, - // or XAUDIO2_LOOP_INFINITE to loop forever. - void* pContext; // Context value to be passed back in callbacks. -} XAUDIO2_BUFFER; - -// Used in IXAudio2SourceVoice::SubmitSourceBuffer when submitting XWMA data. -// NOTE: If an XWMA sound is submitted in more than one buffer, each buffer's -// pDecodedPacketCumulativeBytes[PacketCount-1] value must be subtracted from -// all the entries in the next buffer's pDecodedPacketCumulativeBytes array. -// And whether a sound is submitted in more than one buffer or not, the final -// buffer of the sound should use the XAUDIO2_END_OF_STREAM flag, or else the -// client must call IXAudio2SourceVoice::Discontinuity after submitting it. -typedef struct XAUDIO2_BUFFER_WMA -{ - const UINT32* pDecodedPacketCumulativeBytes; // Decoded packet's cumulative size array. - // Each element is the number of bytes accumulated - // when the corresponding XWMA packet is decoded in - // order. The array must have PacketCount elements. - UINT32 PacketCount; // Number of XWMA packets submitted. Must be >= 1 and - // divide evenly into XAUDIO2_BUFFER.AudioBytes. -} XAUDIO2_BUFFER_WMA; - -// Returned by IXAudio2SourceVoice::GetState -typedef struct XAUDIO2_VOICE_STATE -{ - void* pCurrentBufferContext; // The pContext value provided in the XAUDIO2_BUFFER - // that is currently being processed, or NULL if - // there are no buffers in the queue. - UINT32 BuffersQueued; // Number of buffers currently queued on the voice - // (including the one that is being processed). - UINT64 SamplesPlayed; // Total number of samples produced by the voice since - // it began processing the current audio stream. - // If XAUDIO2_VOICE_NOSAMPLESPLAYED is specified - // in the call to IXAudio2SourceVoice::GetState, - // this member will not be calculated, saving CPU. -} XAUDIO2_VOICE_STATE; - -// Returned by IXAudio2::GetPerformanceData -typedef struct XAUDIO2_PERFORMANCE_DATA -{ - // CPU usage information - UINT64 AudioCyclesSinceLastQuery; // CPU cycles spent on audio processing since the - // last call to StartEngine or GetPerformanceData. - UINT64 TotalCyclesSinceLastQuery; // Total CPU cycles elapsed since the last call - // (only counts the CPU XAudio2 is running on). - UINT32 MinimumCyclesPerQuantum; // Fewest CPU cycles spent processing any one - // audio quantum since the last call. - UINT32 MaximumCyclesPerQuantum; // Most CPU cycles spent processing any one - // audio quantum since the last call. - - // Memory usage information - UINT32 MemoryUsageInBytes; // Total heap space currently in use. - - // Audio latency and glitching information - UINT32 CurrentLatencyInSamples; // Minimum delay from when a sample is read from a - // source buffer to when it reaches the speakers. - UINT32 GlitchesSinceEngineStarted; // Audio dropouts since the engine was started. - - // Data about XAudio2's current workload - UINT32 ActiveSourceVoiceCount; // Source voices currently playing. - UINT32 TotalSourceVoiceCount; // Source voices currently existing. - UINT32 ActiveSubmixVoiceCount; // Submix voices currently playing/existing. - - UINT32 ActiveResamplerCount; // Resample xAPOs currently active. - UINT32 ActiveMatrixMixCount; // MatrixMix xAPOs currently active. - - // Usage of the hardware XMA decoder (Xbox 360 only) - UINT32 ActiveXmaSourceVoices; // Number of source voices decoding XMA data. - UINT32 ActiveXmaStreams; // A voice can use more than one XMA stream. -} XAUDIO2_PERFORMANCE_DATA; - -// Used in IXAudio2::SetDebugConfiguration -typedef struct XAUDIO2_DEBUG_CONFIGURATION -{ - UINT32 TraceMask; // Bitmap of enabled debug message types. - UINT32 BreakMask; // Message types that will break into the debugger. - BOOL LogThreadID; // Whether to log the thread ID with each message. - BOOL LogFileline; // Whether to log the source file and line number. - BOOL LogFunctionName; // Whether to log the function name. - BOOL LogTiming; // Whether to log message timestamps. -} XAUDIO2_DEBUG_CONFIGURATION; - -// Values for the TraceMask and BreakMask bitmaps. Only ERRORS and WARNINGS -// are valid in BreakMask. WARNINGS implies ERRORS, DETAIL implies INFO, and -// FUNC_CALLS implies API_CALLS. By default, TraceMask is ERRORS and WARNINGS -// and all the other settings are zero. -#define XAUDIO2_LOG_ERRORS 0x0001 // For handled errors with serious effects. -#define XAUDIO2_LOG_WARNINGS 0x0002 // For handled errors that may be recoverable. -#define XAUDIO2_LOG_INFO 0x0004 // Informational chit-chat (e.g. state changes). -#define XAUDIO2_LOG_DETAIL 0x0008 // More detailed chit-chat. -#define XAUDIO2_LOG_API_CALLS 0x0010 // Public API function entries and exits. -#define XAUDIO2_LOG_FUNC_CALLS 0x0020 // Internal function entries and exits. -#define XAUDIO2_LOG_TIMING 0x0040 // Delays detected and other timing data. -#define XAUDIO2_LOG_LOCKS 0x0080 // Usage of critical sections and mutexes. -#define XAUDIO2_LOG_MEMORY 0x0100 // Memory heap usage information. -#define XAUDIO2_LOG_STREAMING 0x1000 // Audio streaming information. - - -/************************************************************************** - * - * IXAudio2: Top-level XAudio2 COM interface. - * - **************************************************************************/ - - // Use default arguments if compiling as C++ -#ifdef __cplusplus -#define X2DEFAULT(x) =x -#else -#define X2DEFAULT(x) -#endif - -#undef INTERFACE -#define INTERFACE IXAudio2 -DECLARE_INTERFACE_(IXAudio2, IUnknown) -{ - // NAME: IXAudio2::QueryInterface - // DESCRIPTION: Queries for a given COM interface on the XAudio2 object. - // Only IID_IUnknown and IID_IXAudio2 are supported. - // - // ARGUMENTS: - // riid - IID of the interface to be obtained. - // ppvInterface - Returns a pointer to the requested interface. - // - STDMETHOD(QueryInterface) (THIS_ REFIID riid, _Outptr_ void** ppvInterface) PURE; - - // NAME: IXAudio2::AddRef - // DESCRIPTION: Adds a reference to the XAudio2 object. - // - STDMETHOD_(ULONG, AddRef) (THIS) PURE; - - // NAME: IXAudio2::Release - // DESCRIPTION: Releases a reference to the XAudio2 object. - // - STDMETHOD_(ULONG, Release) (THIS) PURE; - - // NAME: IXAudio2::RegisterForCallbacks - // DESCRIPTION: Adds a new client to receive XAudio2's engine callbacks. - // - // ARGUMENTS: - // pCallback - Callback interface to be called during each processing pass. - // - STDMETHOD(RegisterForCallbacks) (_In_ IXAudio2EngineCallback* pCallback) PURE; - - // NAME: IXAudio2::UnregisterForCallbacks - // DESCRIPTION: Removes an existing receiver of XAudio2 engine callbacks. - // - // ARGUMENTS: - // pCallback - Previously registered callback interface to be removed. - // - STDMETHOD_(void, UnregisterForCallbacks) (_In_ IXAudio2EngineCallback* pCallback) PURE; - - // NAME: IXAudio2::CreateSourceVoice - // DESCRIPTION: Creates and configures a source voice. - // - // ARGUMENTS: - // ppSourceVoice - Returns the new object's IXAudio2SourceVoice interface. - // pSourceFormat - Format of the audio that will be fed to the voice. - // Flags - XAUDIO2_VOICE flags specifying the source voice's behavior. - // MaxFrequencyRatio - Maximum SetFrequencyRatio argument to be allowed. - // pCallback - Optional pointer to a client-provided callback interface. - // pSendList - Optional list of voices this voice should send audio to. - // pEffectChain - Optional list of effects to apply to the audio data. - // - STDMETHOD(CreateSourceVoice) (THIS_ _Outptr_ IXAudio2SourceVoice** ppSourceVoice, - _In_ const WAVEFORMATEX* pSourceFormat, - UINT32 Flags X2DEFAULT(0), - float MaxFrequencyRatio X2DEFAULT(XAUDIO2_DEFAULT_FREQ_RATIO), - _In_opt_ IXAudio2VoiceCallback* pCallback X2DEFAULT(NULL), - _In_opt_ const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL), - _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; - - // NAME: IXAudio2::CreateSubmixVoice - // DESCRIPTION: Creates and configures a submix voice. - // - // ARGUMENTS: - // ppSubmixVoice - Returns the new object's IXAudio2SubmixVoice interface. - // InputChannels - Number of channels in this voice's input audio data. - // InputSampleRate - Sample rate of this voice's input audio data. - // Flags - XAUDIO2_VOICE flags specifying the submix voice's behavior. - // ProcessingStage - Arbitrary number that determines the processing order. - // pSendList - Optional list of voices this voice should send audio to. - // pEffectChain - Optional list of effects to apply to the audio data. - // - STDMETHOD(CreateSubmixVoice) (THIS_ _Outptr_ IXAudio2SubmixVoice** ppSubmixVoice, - UINT32 InputChannels, UINT32 InputSampleRate, - UINT32 Flags X2DEFAULT(0), UINT32 ProcessingStage X2DEFAULT(0), - _In_opt_ const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL), - _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; - - - // NAME: IXAudio2::CreateMasteringVoice - // DESCRIPTION: Creates and configures a mastering voice. - // - // ARGUMENTS: - // ppMasteringVoice - Returns the new object's IXAudio2MasteringVoice interface. - // InputChannels - Number of channels in this voice's input audio data. - // InputSampleRate - Sample rate of this voice's input audio data. - // Flags - XAUDIO2_VOICE flags specifying the mastering voice's behavior. - // szDeviceId - Identifier of the device to receive the output audio. - // pEffectChain - Optional list of effects to apply to the audio data. - // StreamCategory - The audio stream category to use for this mastering voice - // - STDMETHOD(CreateMasteringVoice) (THIS_ _Outptr_ IXAudio2MasteringVoice** ppMasteringVoice, - UINT32 InputChannels X2DEFAULT(XAUDIO2_DEFAULT_CHANNELS), - UINT32 InputSampleRate X2DEFAULT(XAUDIO2_DEFAULT_SAMPLERATE), - UINT32 Flags X2DEFAULT(0), _In_opt_z_ LPCWSTR szDeviceId X2DEFAULT(NULL), - _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL), - _In_ AUDIO_STREAM_CATEGORY StreamCategory X2DEFAULT(AudioCategory_GameEffects)) PURE; - - // NAME: IXAudio2::StartEngine - // DESCRIPTION: Creates and starts the audio processing thread. - // - STDMETHOD(StartEngine) (THIS) PURE; - - // NAME: IXAudio2::StopEngine - // DESCRIPTION: Stops and destroys the audio processing thread. - // - STDMETHOD_(void, StopEngine) (THIS) PURE; - - // NAME: IXAudio2::CommitChanges - // DESCRIPTION: Atomically applies a set of operations previously tagged - // with a given identifier. - // - // ARGUMENTS: - // OperationSet - Identifier of the set of operations to be applied. - // - STDMETHOD(CommitChanges) (THIS_ UINT32 OperationSet) PURE; - - // NAME: IXAudio2::GetPerformanceData - // DESCRIPTION: Returns current resource usage details: memory, CPU, etc. - // - // ARGUMENTS: - // pPerfData - Returns the performance data structure. - // - STDMETHOD_(void, GetPerformanceData) (THIS_ _Out_ XAUDIO2_PERFORMANCE_DATA* pPerfData) PURE; - - // NAME: IXAudio2::SetDebugConfiguration - // DESCRIPTION: Configures XAudio2's debug output (in debug builds only). - // - // ARGUMENTS: - // pDebugConfiguration - Structure describing the debug output behavior. - // pReserved - Optional parameter; must be NULL. - // - STDMETHOD_(void, SetDebugConfiguration) (THIS_ _In_opt_ const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration, - _Reserved_ void* pReserved X2DEFAULT(NULL)) PURE; -}; - - -/************************************************************************** - * - * IXAudio2Voice: Base voice management interface. - * - **************************************************************************/ - -#undef INTERFACE -#define INTERFACE IXAudio2Voice -DECLARE_INTERFACE(IXAudio2Voice) -{ - // These methods are declared in a macro so that the same declarations - // can be used in the derived voice types (IXAudio2SourceVoice, etc). - -#define Declare_IXAudio2Voice_Methods() \ - \ - /* NAME: IXAudio2Voice::GetVoiceDetails - // DESCRIPTION: Returns the basic characteristics of this voice. - // - // ARGUMENTS: - // pVoiceDetails - Returns the voice's details. - */\ - STDMETHOD_(void, GetVoiceDetails) (THIS_ _Out_ XAUDIO2_VOICE_DETAILS* pVoiceDetails) PURE; \ - \ - /* NAME: IXAudio2Voice::SetOutputVoices - // DESCRIPTION: Replaces the set of submix/mastering voices that receive - // this voice's output. - // - // ARGUMENTS: - // pSendList - Optional list of voices this voice should send audio to. - */\ - STDMETHOD(SetOutputVoices) (THIS_ _In_opt_ const XAUDIO2_VOICE_SENDS* pSendList) PURE; \ - \ - /* NAME: IXAudio2Voice::SetEffectChain - // DESCRIPTION: Replaces this voice's current effect chain with a new one. - // - // ARGUMENTS: - // pEffectChain - Structure describing the new effect chain to be used. - */\ - STDMETHOD(SetEffectChain) (THIS_ _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain) PURE; \ - \ - /* NAME: IXAudio2Voice::EnableEffect - // DESCRIPTION: Enables an effect in this voice's effect chain. - // - // ARGUMENTS: - // EffectIndex - Index of an effect within this voice's effect chain. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(EnableEffect) (THIS_ UINT32 EffectIndex, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::DisableEffect - // DESCRIPTION: Disables an effect in this voice's effect chain. - // - // ARGUMENTS: - // EffectIndex - Index of an effect within this voice's effect chain. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(DisableEffect) (THIS_ UINT32 EffectIndex, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetEffectState - // DESCRIPTION: Returns the running state of an effect. - // - // ARGUMENTS: - // EffectIndex - Index of an effect within this voice's effect chain. - // pEnabled - Returns the enabled/disabled state of the given effect. - */\ - STDMETHOD_(void, GetEffectState) (THIS_ UINT32 EffectIndex, _Out_ BOOL* pEnabled) PURE; \ - \ - /* NAME: IXAudio2Voice::SetEffectParameters - // DESCRIPTION: Sets effect-specific parameters. - // - // REMARKS: Unlike IXAPOParameters::SetParameters, this method may - // be called from any thread. XAudio2 implements - // appropriate synchronization to copy the parameters to the - // realtime audio processing thread. - // - // ARGUMENTS: - // EffectIndex - Index of an effect within this voice's effect chain. - // pParameters - Pointer to an effect-specific parameters block. - // ParametersByteSize - Size of the pParameters array in bytes. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(SetEffectParameters) (THIS_ UINT32 EffectIndex, \ - _In_reads_bytes_(ParametersByteSize) const void* pParameters, \ - UINT32 ParametersByteSize, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetEffectParameters - // DESCRIPTION: Obtains the current effect-specific parameters. - // - // ARGUMENTS: - // EffectIndex - Index of an effect within this voice's effect chain. - // pParameters - Returns the current values of the effect-specific parameters. - // ParametersByteSize - Size of the pParameters array in bytes. - */\ - STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, \ - _Out_writes_bytes_(ParametersByteSize) void* pParameters, \ - UINT32 ParametersByteSize) PURE; \ - \ - /* NAME: IXAudio2Voice::SetFilterParameters - // DESCRIPTION: Sets this voice's filter parameters. - // - // ARGUMENTS: - // pParameters - Pointer to the filter's parameter structure. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(SetFilterParameters) (THIS_ _In_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetFilterParameters - // DESCRIPTION: Returns this voice's current filter parameters. - // - // ARGUMENTS: - // pParameters - Returns the filter parameters. - */\ - STDMETHOD_(void, GetFilterParameters) (THIS_ _Out_ XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \ - \ - /* NAME: IXAudio2Voice::SetOutputFilterParameters - // DESCRIPTION: Sets the filter parameters on one of this voice's sends. - // - // ARGUMENTS: - // pDestinationVoice - Destination voice of the send whose filter parameters will be set. - // pParameters - Pointer to the filter's parameter structure. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(SetOutputFilterParameters) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ - _In_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetOutputFilterParameters - // DESCRIPTION: Returns the filter parameters from one of this voice's sends. - // - // ARGUMENTS: - // pDestinationVoice - Destination voice of the send whose filter parameters will be read. - // pParameters - Returns the filter parameters. - */\ - STDMETHOD_(void, GetOutputFilterParameters) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ - _Out_ XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \ - \ - /* NAME: IXAudio2Voice::SetVolume - // DESCRIPTION: Sets this voice's overall volume level. - // - // ARGUMENTS: - // Volume - New overall volume level to be used, as an amplitude factor. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(SetVolume) (THIS_ float Volume, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetVolume - // DESCRIPTION: Obtains this voice's current overall volume level. - // - // ARGUMENTS: - // pVolume: Returns the voice's current overall volume level. - */\ - STDMETHOD_(void, GetVolume) (THIS_ _Out_ float* pVolume) PURE; \ - \ - /* NAME: IXAudio2Voice::SetChannelVolumes - // DESCRIPTION: Sets this voice's per-channel volume levels. - // - // ARGUMENTS: - // Channels - Used to confirm the voice's channel count. - // pVolumes - Array of per-channel volume levels to be used. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(SetChannelVolumes) (THIS_ UINT32 Channels, _In_reads_(Channels) const float* pVolumes, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetChannelVolumes - // DESCRIPTION: Returns this voice's current per-channel volume levels. - // - // ARGUMENTS: - // Channels - Used to confirm the voice's channel count. - // pVolumes - Returns an array of the current per-channel volume levels. - */\ - STDMETHOD_(void, GetChannelVolumes) (THIS_ UINT32 Channels, _Out_writes_(Channels) float* pVolumes) PURE; \ - \ - /* NAME: IXAudio2Voice::SetOutputMatrix - // DESCRIPTION: Sets the volume levels used to mix from each channel of this - // voice's output audio to each channel of a given destination - // voice's input audio. - // - // ARGUMENTS: - // pDestinationVoice - The destination voice whose mix matrix to change. - // SourceChannels - Used to confirm this voice's output channel count - // (the number of channels produced by the last effect in the chain). - // DestinationChannels - Confirms the destination voice's input channels. - // pLevelMatrix - Array of [SourceChannels * DestinationChannels] send - // levels. The level used to send from source channel S to destination - // channel D should be in pLevelMatrix[S + SourceChannels * D]. - // OperationSet - Used to identify this call as part of a deferred batch. - */\ - STDMETHOD(SetOutputMatrix) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ - UINT32 SourceChannels, UINT32 DestinationChannels, \ - _In_reads_(SourceChannels * DestinationChannels) const float* pLevelMatrix, \ - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ - \ - /* NAME: IXAudio2Voice::GetOutputMatrix - // DESCRIPTION: Obtains the volume levels used to send each channel of this - // voice's output audio to each channel of a given destination - // voice's input audio. - // - // ARGUMENTS: - // pDestinationVoice - The destination voice whose mix matrix to obtain. - // SourceChannels - Used to confirm this voice's output channel count - // (the number of channels produced by the last effect in the chain). - // DestinationChannels - Confirms the destination voice's input channels. - // pLevelMatrix - Array of send levels, as above. - */\ - STDMETHOD_(void, GetOutputMatrix) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ - UINT32 SourceChannels, UINT32 DestinationChannels, \ - _Out_writes_(SourceChannels * DestinationChannels) float* pLevelMatrix) PURE; \ - \ - /* NAME: IXAudio2Voice::DestroyVoice - // DESCRIPTION: Destroys this voice, stopping it if necessary and removing - // it from the XAudio2 graph. - */\ - STDMETHOD_(void, DestroyVoice) (THIS) PURE - - Declare_IXAudio2Voice_Methods(); -}; - - -/************************************************************************** - * - * IXAudio2SourceVoice: Source voice management interface. - * - **************************************************************************/ - -#undef INTERFACE -#define INTERFACE IXAudio2SourceVoice -DECLARE_INTERFACE_(IXAudio2SourceVoice, IXAudio2Voice) -{ - // Methods from IXAudio2Voice base interface - Declare_IXAudio2Voice_Methods(); - - // NAME: IXAudio2SourceVoice::Start - // DESCRIPTION: Makes this voice start consuming and processing audio. - // - // ARGUMENTS: - // Flags - Flags controlling how the voice should be started. - // OperationSet - Used to identify this call as part of a deferred batch. - // - STDMETHOD(Start) (THIS_ UINT32 Flags X2DEFAULT(0), UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; - - // NAME: IXAudio2SourceVoice::Stop - // DESCRIPTION: Makes this voice stop consuming audio. - // - // ARGUMENTS: - // Flags - Flags controlling how the voice should be stopped. - // OperationSet - Used to identify this call as part of a deferred batch. - // - STDMETHOD(Stop) (THIS_ UINT32 Flags X2DEFAULT(0), UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; - - // NAME: IXAudio2SourceVoice::SubmitSourceBuffer - // DESCRIPTION: Adds a new audio buffer to this voice's input queue. - // - // ARGUMENTS: - // pBuffer - Pointer to the buffer structure to be queued. - // pBufferWMA - Additional structure used only when submitting XWMA data. - // - STDMETHOD(SubmitSourceBuffer) (THIS_ _In_ const XAUDIO2_BUFFER* pBuffer, _In_opt_ const XAUDIO2_BUFFER_WMA* pBufferWMA X2DEFAULT(NULL)) PURE; - - // NAME: IXAudio2SourceVoice::FlushSourceBuffers - // DESCRIPTION: Removes all pending audio buffers from this voice's queue. - // - STDMETHOD(FlushSourceBuffers) (THIS) PURE; - - // NAME: IXAudio2SourceVoice::Discontinuity - // DESCRIPTION: Notifies the voice of an intentional break in the stream of - // audio buffers (e.g. the end of a sound), to prevent XAudio2 - // from interpreting an empty buffer queue as a glitch. - // - STDMETHOD(Discontinuity) (THIS) PURE; - - // NAME: IXAudio2SourceVoice::ExitLoop - // DESCRIPTION: Breaks out of the current loop when its end is reached. - // - // ARGUMENTS: - // OperationSet - Used to identify this call as part of a deferred batch. - // - STDMETHOD(ExitLoop) (THIS_ UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; - - // NAME: IXAudio2SourceVoice::GetState - // DESCRIPTION: Returns the number of buffers currently queued on this voice, - // the pContext value associated with the currently processing - // buffer (if any), and other voice state information. - // - // ARGUMENTS: - // pVoiceState - Returns the state information. - // Flags - Flags controlling what voice state is returned. - // - STDMETHOD_(void, GetState) (THIS_ _Out_ XAUDIO2_VOICE_STATE* pVoiceState, UINT32 Flags X2DEFAULT(0)) PURE; - - // NAME: IXAudio2SourceVoice::SetFrequencyRatio - // DESCRIPTION: Sets this voice's frequency adjustment, i.e. its pitch. - // - // ARGUMENTS: - // Ratio - Frequency change, expressed as source frequency / target frequency. - // OperationSet - Used to identify this call as part of a deferred batch. - // - STDMETHOD(SetFrequencyRatio) (THIS_ float Ratio, - UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; - - // NAME: IXAudio2SourceVoice::GetFrequencyRatio - // DESCRIPTION: Returns this voice's current frequency adjustment ratio. - // - // ARGUMENTS: - // pRatio - Returns the frequency adjustment. - // - STDMETHOD_(void, GetFrequencyRatio) (THIS_ _Out_ float* pRatio) PURE; - - // NAME: IXAudio2SourceVoice::SetSourceSampleRate - // DESCRIPTION: Reconfigures this voice to treat its source data as being - // at a different sample rate than the original one specified - // in CreateSourceVoice's pSourceFormat argument. - // - // ARGUMENTS: - // UINT32 - The intended sample rate of further submitted source data. - // - STDMETHOD(SetSourceSampleRate) (THIS_ UINT32 NewSourceSampleRate) PURE; -}; - - -/************************************************************************** - * - * IXAudio2SubmixVoice: Submixing voice management interface. - * - **************************************************************************/ - -#undef INTERFACE -#define INTERFACE IXAudio2SubmixVoice -DECLARE_INTERFACE_(IXAudio2SubmixVoice, IXAudio2Voice) -{ - // Methods from IXAudio2Voice base interface - Declare_IXAudio2Voice_Methods(); - - // There are currently no methods specific to submix voices. -}; - - -/************************************************************************** - * - * IXAudio2MasteringVoice: Mastering voice management interface. - * - **************************************************************************/ - -#undef INTERFACE -#define INTERFACE IXAudio2MasteringVoice -DECLARE_INTERFACE_(IXAudio2MasteringVoice, IXAudio2Voice) -{ - // Methods from IXAudio2Voice base interface - Declare_IXAudio2Voice_Methods(); - - // NAME: IXAudio2MasteringVoice::GetChannelMask - // DESCRIPTION: Returns the channel mask for this voice - // - // ARGUMENTS: - // pChannelMask - returns the channel mask for this voice. This corresponds - // to the dwChannelMask member of WAVEFORMATEXTENSIBLE. - // - STDMETHOD(GetChannelMask) (THIS_ _Out_ DWORD* pChannelmask) PURE; -}; - - -/************************************************************************** - * - * IXAudio2EngineCallback: Client notification interface for engine events. - * - * REMARKS: Contains methods to notify the client when certain events happen - * in the XAudio2 engine. This interface should be implemented by - * the client. XAudio2 will call these methods via the interface - * pointer provided by the client when it calls - * IXAudio2::RegisterForCallbacks. - * - **************************************************************************/ - -#undef INTERFACE -#define INTERFACE IXAudio2EngineCallback -DECLARE_INTERFACE(IXAudio2EngineCallback) -{ - // Called by XAudio2 just before an audio processing pass begins. - STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE; - - // Called just after an audio processing pass ends. - STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE; - - // Called in the event of a critical system error which requires XAudio2 - // to be closed down and restarted. The error code is given in Error. - STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE; -}; - - -/************************************************************************** - * - * IXAudio2VoiceCallback: Client notification interface for voice events. - * - * REMARKS: Contains methods to notify the client when certain events happen - * in an XAudio2 voice. This interface should be implemented by the - * client. XAudio2 will call these methods via an interface pointer - * provided by the client in the IXAudio2::CreateSourceVoice call. - * - **************************************************************************/ - -#undef INTERFACE -#define INTERFACE IXAudio2VoiceCallback -DECLARE_INTERFACE(IXAudio2VoiceCallback) -{ - // Called just before this voice's processing pass begins. - STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) PURE; - - // Called just after this voice's processing pass ends. - STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) PURE; - - // Called when this voice has just finished playing a buffer stream - // (as marked with the XAUDIO2_END_OF_STREAM flag on the last buffer). - STDMETHOD_(void, OnStreamEnd) (THIS) PURE; - - // Called when this voice is about to start processing a new buffer. - STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) PURE; - - // Called when this voice has just finished processing a buffer. - // The buffer can now be reused or destroyed. - STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) PURE; - - // Called when this voice has just reached the end position of a loop. - STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) PURE; - - // Called in the event of a critical error during voice processing, - // such as a failing xAPO or an error from the hardware XMA decoder. - // The voice may have to be destroyed and re-created to recover from - // the error. The callback arguments report which buffer was being - // processed when the error occurred, and its HRESULT code. - STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) PURE; -}; - - -/************************************************************************** - * - * Macros to make it easier to use the XAudio2 COM interfaces in C code. - * - **************************************************************************/ - -#ifndef __cplusplus - - // IXAudio2 -#define IXAudio2_QueryInterface(This,riid,ppvInterface) ((This)->lpVtbl->QueryInterface(This,riid,ppvInterface)) -#define IXAudio2_AddRef(This) ((This)->lpVtbl->AddRef(This)) -#define IXAudio2_Release(This) ((This)->lpVtbl->Release(This)) -#define IXAudio2_CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain) ((This)->lpVtbl->CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain)) -#define IXAudio2_CreateSubmixVoice(This,ppSubmixVoice,InputChannels,InputSampleRate,Flags,ProcessingStage,pSendList,pEffectChain) ((This)->lpVtbl->CreateSubmixVoice(This,ppSubmixVoice,InputChannels,InputSampleRate,Flags,ProcessingStage,pSendList,pEffectChain)) -#define IXAudio2_CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceId,pEffectChain,StreamCategory) ((This)->lpVtbl->CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceId,pEffectChain,StreamCategory)) -#define IXAudio2_StartEngine(This) ((This)->lpVtbl->StartEngine(This)) -#define IXAudio2_StopEngine(This) ((This)->lpVtbl->StopEngine(This)) -#define IXAudio2_CommitChanges(This,OperationSet) ((This)->lpVtbl->CommitChanges(This,OperationSet)) -#define IXAudio2_GetPerformanceData(This,pPerfData) ((This)->lpVtbl->GetPerformanceData(This,pPerfData)) -#define IXAudio2_SetDebugConfiguration(This,pDebugConfiguration,pReserved) ((This)->lpVtbl->SetDebugConfiguration(This,pDebugConfiguration,pReserved)) - -// IXAudio2Voice -#define IXAudio2Voice_GetVoiceDetails(This,pVoiceDetails) ((This)->lpVtbl->GetVoiceDetails(This,pVoiceDetails)) -#define IXAudio2Voice_SetOutputVoices(This,pSendList) ((This)->lpVtbl->SetOutputVoices(This,pSendList)) -#define IXAudio2Voice_SetEffectChain(This,pEffectChain) ((This)->lpVtbl->SetEffectChain(This,pEffectChain)) -#define IXAudio2Voice_EnableEffect(This,EffectIndex,OperationSet) ((This)->lpVtbl->EnableEffect(This,EffectIndex,OperationSet)) -#define IXAudio2Voice_DisableEffect(This,EffectIndex,OperationSet) ((This)->lpVtbl->DisableEffect(This,EffectIndex,OperationSet)) -#define IXAudio2Voice_GetEffectState(This,EffectIndex,pEnabled) ((This)->lpVtbl->GetEffectState(This,EffectIndex,pEnabled)) -#define IXAudio2Voice_SetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize, OperationSet) ((This)->lpVtbl->SetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize,OperationSet)) -#define IXAudio2Voice_GetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize) ((This)->lpVtbl->GetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize)) -#define IXAudio2Voice_SetFilterParameters(This,pParameters,OperationSet) ((This)->lpVtbl->SetFilterParameters(This,pParameters,OperationSet)) -#define IXAudio2Voice_GetFilterParameters(This,pParameters) ((This)->lpVtbl->GetFilterParameters(This,pParameters)) -#define IXAudio2Voice_SetOutputFilterParameters(This,pDestinationVoice,pParameters,OperationSet) ((This)->lpVtbl->SetOutputFilterParameters(This,pDestinationVoice,pParameters,OperationSet)) -#define IXAudio2Voice_GetOutputFilterParameters(This,pDestinationVoice,pParameters) ((This)->lpVtbl->GetOutputFilterParameters(This,pDestinationVoice,pParameters)) -#define IXAudio2Voice_SetVolume(This,Volume,OperationSet) ((This)->lpVtbl->SetVolume(This,Volume,OperationSet)) -#define IXAudio2Voice_GetVolume(This,pVolume) ((This)->lpVtbl->GetVolume(This,pVolume)) -#define IXAudio2Voice_SetChannelVolumes(This,Channels,pVolumes,OperationSet) ((This)->lpVtbl->SetChannelVolumes(This,Channels,pVolumes,OperationSet)) -#define IXAudio2Voice_GetChannelVolumes(This,Channels,pVolumes) ((This)->lpVtbl->GetChannelVolumes(This,Channels,pVolumes)) -#define IXAudio2Voice_SetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix,OperationSet) ((This)->lpVtbl->SetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix,OperationSet)) -#define IXAudio2Voice_GetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix) ((This)->lpVtbl->GetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix)) -#define IXAudio2Voice_DestroyVoice(This) ((This)->lpVtbl->DestroyVoice(This)) - -// IXAudio2SourceVoice -#define IXAudio2SourceVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails -#define IXAudio2SourceVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices -#define IXAudio2SourceVoice_SetEffectChain IXAudio2Voice_SetEffectChain -#define IXAudio2SourceVoice_EnableEffect IXAudio2Voice_EnableEffect -#define IXAudio2SourceVoice_DisableEffect IXAudio2Voice_DisableEffect -#define IXAudio2SourceVoice_GetEffectState IXAudio2Voice_GetEffectState -#define IXAudio2SourceVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters -#define IXAudio2SourceVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters -#define IXAudio2SourceVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters -#define IXAudio2SourceVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters -#define IXAudio2SourceVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters -#define IXAudio2SourceVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters -#define IXAudio2SourceVoice_SetVolume IXAudio2Voice_SetVolume -#define IXAudio2SourceVoice_GetVolume IXAudio2Voice_GetVolume -#define IXAudio2SourceVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes -#define IXAudio2SourceVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes -#define IXAudio2SourceVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix -#define IXAudio2SourceVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix -#define IXAudio2SourceVoice_DestroyVoice IXAudio2Voice_DestroyVoice -#define IXAudio2SourceVoice_Start(This,Flags,OperationSet) ((This)->lpVtbl->Start(This,Flags,OperationSet)) -#define IXAudio2SourceVoice_Stop(This,Flags,OperationSet) ((This)->lpVtbl->Stop(This,Flags,OperationSet)) -#define IXAudio2SourceVoice_SubmitSourceBuffer(This,pBuffer,pBufferWMA) ((This)->lpVtbl->SubmitSourceBuffer(This,pBuffer,pBufferWMA)) -#define IXAudio2SourceVoice_FlushSourceBuffers(This) ((This)->lpVtbl->FlushSourceBuffers(This)) -#define IXAudio2SourceVoice_Discontinuity(This) ((This)->lpVtbl->Discontinuity(This)) -#define IXAudio2SourceVoice_ExitLoop(This,OperationSet) ((This)->lpVtbl->ExitLoop(This,OperationSet)) -#define IXAudio2SourceVoice_GetState(This,pVoiceState,Flags) ((This)->lpVtbl->GetState(This,pVoiceState,Flags)) -#define IXAudio2SourceVoice_SetFrequencyRatio(This,Ratio,OperationSet) ((This)->lpVtbl->SetFrequencyRatio(This,Ratio,OperationSet)) -#define IXAudio2SourceVoice_GetFrequencyRatio(This,pRatio) ((This)->lpVtbl->GetFrequencyRatio(This,pRatio)) -#define IXAudio2SourceVoice_SetSourceSampleRate(This,NewSourceSampleRate) ((This)->lpVtbl->SetSourceSampleRate(This,NewSourceSampleRate)) - -// IXAudio2SubmixVoice -#define IXAudio2SubmixVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails -#define IXAudio2SubmixVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices -#define IXAudio2SubmixVoice_SetEffectChain IXAudio2Voice_SetEffectChain -#define IXAudio2SubmixVoice_EnableEffect IXAudio2Voice_EnableEffect -#define IXAudio2SubmixVoice_DisableEffect IXAudio2Voice_DisableEffect -#define IXAudio2SubmixVoice_GetEffectState IXAudio2Voice_GetEffectState -#define IXAudio2SubmixVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters -#define IXAudio2SubmixVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters -#define IXAudio2SubmixVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters -#define IXAudio2SubmixVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters -#define IXAudio2SubmixVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters -#define IXAudio2SubmixVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters -#define IXAudio2SubmixVoice_SetVolume IXAudio2Voice_SetVolume -#define IXAudio2SubmixVoice_GetVolume IXAudio2Voice_GetVolume -#define IXAudio2SubmixVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes -#define IXAudio2SubmixVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes -#define IXAudio2SubmixVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix -#define IXAudio2SubmixVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix -#define IXAudio2SubmixVoice_DestroyVoice IXAudio2Voice_DestroyVoice - -/* IXAudio2MasteringVoice */ -#define IXAudio2MasteringVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails -#define IXAudio2MasteringVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices -#define IXAudio2MasteringVoice_SetEffectChain IXAudio2Voice_SetEffectChain -#define IXAudio2MasteringVoice_EnableEffect IXAudio2Voice_EnableEffect -#define IXAudio2MasteringVoice_DisableEffect IXAudio2Voice_DisableEffect -#define IXAudio2MasteringVoice_GetEffectState IXAudio2Voice_GetEffectState -#define IXAudio2MasteringVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters -#define IXAudio2MasteringVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters -#define IXAudio2MasteringVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters -#define IXAudio2MasteringVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters -#define IXAudio2MasteringVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters -#define IXAudio2MasteringVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters -#define IXAudio2MasteringVoice_SetVolume IXAudio2Voice_SetVolume -#define IXAudio2MasteringVoice_GetVolume IXAudio2Voice_GetVolume -#define IXAudio2MasteringVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes -#define IXAudio2MasteringVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes -#define IXAudio2MasteringVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix -#define IXAudio2MasteringVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix -#define IXAudio2MasteringVoice_DestroyVoice IXAudio2Voice_DestroyVoice -#define IXAudio2MasteringVoice_GetChannelMask(This,pChannelMask) ((This)->lpVtbl->GetChannelMask(This,pChannelMask)) - -#endif /* #ifndef __cplusplus */ - - -/************************************************************************** - * - * Utility functions used to convert from pitch in semitones and volume - * in decibels to the frequency and amplitude ratio units used by XAudio2. - * These are only defined if the client #defines XAUDIO2_HELPER_FUNCTIONS - * prior to #including xaudio2.h. - * - **************************************************************************/ - -#ifdef XAUDIO2_HELPER_FUNCTIONS - -#define _USE_MATH_DEFINES /* Make math.h define M_PI */ -#include /* For powf, log10f, sinf and asinf */ - -/* Calculate the argument to SetVolume from a decibel value */ -static INLINE float XAudio2DecibelsToAmplitudeRatio(float Decibels) -{ - return powf(10.0f, Decibels / 20.0f); -} - -/* Recover a volume in decibels from an amplitude factor */ -static INLINE float XAudio2AmplitudeRatioToDecibels(float Volume) -{ - if (Volume == 0) - return -3.402823466e+38f; /* Smallest float value (-FLT_MAX) */ - return 20.0f * log10f(Volume); -} - -/* Calculate the argument to SetFrequencyRatio from a semitone value */ -static INLINE float XAudio2SemitonesToFrequencyRatio(float Semitones) -{ - /* FrequencyRatio = 2 ^ Octaves +/* RetroArch - A frontend for libretro. + * Copyright (C) 2018 - Krzysztof HaƂadyn + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + + /************************************************************************** + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * File: xaudio2.h + * Content: Declarations for the XAudio2 game audio API. + * + **************************************************************************/ + + /* Modified slightly to build without requiring the WinRT compiler since that is only available in C++ sources */ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifndef __XAUDIO2_INCLUDED__ +#define __XAUDIO2_INCLUDED__ + +#include + +#include + +#if(_WIN32_WINNT < _WIN32_WINNT_WIN8) +#error "This version of XAudio2 is available only in Windows 8 or later. Use the XAudio2 headers and libraries from the DirectX SDK with applications that target Windows 7 and earlier versions." +#endif // (_WIN32_WINNT < _WIN32_WINNT_WIN8) + +#include + +#pragma region Application Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_TV_APP | WINAPI_PARTITION_TV_TITLE) + +// Current name of the DLL shipped in the same SDK as this header. +// The name reflects the current version +#if(_WIN32_WINNT >= _WIN32_WINNT_WIN10) +#define XAUDIO2_DLL_A "xaudio2_9.dll" +#define XAUDIO2_DLL_W L"xaudio2_9.dll" +#define XAUDIO2D_DLL_A "xaudio2_9d.dll" +#define XAUDIO2D_DLL_W L"xaudio2_9d.dll" +#else +#define XAUDIO2_DLL_A "xaudio2_8.dll" +#define XAUDIO2_DLL_W L"xaudio2_8.dll" +#define XAUDIO2D_DLL_A "xaudio2_8.dll" +#define XAUDIO2D_DLL_W L"xaudio2_8.dll" +#endif + +#ifdef UNICODE +#define XAUDIO2_DLL XAUDIO2_DLL_W +#define XAUDIO2D_DLL XAUDIO2D_DLL_W +#else +#define XAUDIO2_DLL XAUDIO2_DLL_A +#define XAUDIO2D_DLL XAUDIO2D_DLL_A +#endif + + +/************************************************************************** + * + * XAudio2 COM object class and interface IDs. + * + **************************************************************************/ + +#include + +#if defined(__cplusplus__) && defined(__WINRT__) + +#if(_WIN32_WINNT >= _WIN32_WINNT_WIN10) + // XAudio 2.9 +interface __declspec(uuid("2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D")) IXAudio2; +#else + // XAudio 2.8 +interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2; +#endif + +#else + + /* Modified for C support */ +#define DEFINE_GUID_X(n, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + static const GUID n = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#define DEFINE_CLSID_X(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + DEFINE_GUID_X(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) +#define DEFINE_IID_X(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + DEFINE_GUID_X(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) + +#if(_WIN32_WINNT >= _WIN32_WINNT_WIN10) +DEFINE_IID_X(IXAudio2, 2B02E3CF, 2E0B, 4ec3, BE, 45, 1B, 2A, 3F, E7, 21, 0D); +#else +DEFINE_IID_X(IXAudio2, 60d8dac8, 5aa1, 4e8e, b5, 97, 2f, 5e, 28, 83, d4, 84); +#endif + +#endif + + +// Ignore the rest of this header if only the GUID definitions were requested +#ifndef GUID_DEFS_ONLY + +#include // Windows COM declarations +#include // Markers for documenting API semantics +#include // Basic data types and constants for audio work +#include // For AUDIO_STREAM_CATEGORY + +// All structures defined in this file use tight field packing +#pragma pack(push, 1) + + +/************************************************************************** + * + * XAudio2 constants, flags and error codes. + * + **************************************************************************/ + + // Numeric boundary values +#define XAUDIO2_MAX_BUFFER_BYTES 0x80000000 // Maximum bytes allowed in a source buffer +#define XAUDIO2_MAX_QUEUED_BUFFERS 64 // Maximum buffers allowed in a voice queue +#define XAUDIO2_MAX_BUFFERS_SYSTEM 2 // Maximum buffers allowed for system threads (Xbox 360 only) +#define XAUDIO2_MAX_AUDIO_CHANNELS 64 // Maximum channels in an audio stream +#define XAUDIO2_MIN_SAMPLE_RATE 1000 // Minimum audio sample rate supported +#define XAUDIO2_MAX_SAMPLE_RATE 200000 // Maximum audio sample rate supported +#define XAUDIO2_MAX_VOLUME_LEVEL 16777216.0f // Maximum acceptable volume level (2^24) +#define XAUDIO2_MIN_FREQ_RATIO (1/1024.0f) // Minimum SetFrequencyRatio argument +#define XAUDIO2_MAX_FREQ_RATIO 1024.0f // Maximum MaxFrequencyRatio argument +#define XAUDIO2_DEFAULT_FREQ_RATIO 2.0f // Default MaxFrequencyRatio argument +#define XAUDIO2_MAX_FILTER_ONEOVERQ 1.5f // Maximum XAUDIO2_FILTER_PARAMETERS.OneOverQ +#define XAUDIO2_MAX_FILTER_FREQUENCY 1.0f // Maximum XAUDIO2_FILTER_PARAMETERS.Frequency +#define XAUDIO2_MAX_LOOP_COUNT 254 // Maximum non-infinite XAUDIO2_BUFFER.LoopCount +#define XAUDIO2_MAX_INSTANCES 8 // Maximum simultaneous XAudio2 objects on Xbox 360 + +// For XMA voices on Xbox 360 there is an additional restriction on the MaxFrequencyRatio +// argument and the voice's sample rate: the product of these numbers cannot exceed 600000 +// for one-channel voices or 300000 for voices with more than one channel. +#define XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MONO 600000 +#define XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MULTICHANNEL 300000 + +// Numeric values with special meanings +#define XAUDIO2_COMMIT_NOW 0 // Used as an OperationSet argument +#define XAUDIO2_COMMIT_ALL 0 // Used in IXAudio2::CommitChanges +#define XAUDIO2_INVALID_OPSET (UINT32)(-1) // Not allowed for OperationSet arguments +#define XAUDIO2_NO_LOOP_REGION 0 // Used in XAUDIO2_BUFFER.LoopCount +#define XAUDIO2_LOOP_INFINITE 255 // Used in XAUDIO2_BUFFER.LoopCount +#define XAUDIO2_DEFAULT_CHANNELS 0 // Used in CreateMasteringVoice +#define XAUDIO2_DEFAULT_SAMPLERATE 0 // Used in CreateMasteringVoice + +// Flags +#define XAUDIO2_DEBUG_ENGINE 0x0001 // Used in XAudio2Create +#define XAUDIO2_VOICE_NOPITCH 0x0002 // Used in IXAudio2::CreateSourceVoice +#define XAUDIO2_VOICE_NOSRC 0x0004 // Used in IXAudio2::CreateSourceVoice +#define XAUDIO2_VOICE_USEFILTER 0x0008 // Used in IXAudio2::CreateSource/SubmixVoice +#define XAUDIO2_PLAY_TAILS 0x0020 // Used in IXAudio2SourceVoice::Stop +#define XAUDIO2_END_OF_STREAM 0x0040 // Used in XAUDIO2_BUFFER.Flags +#define XAUDIO2_SEND_USEFILTER 0x0080 // Used in XAUDIO2_SEND_DESCRIPTOR.Flags +#define XAUDIO2_VOICE_NOSAMPLESPLAYED 0x0100 // Used in IXAudio2SourceVoice::GetState +#define XAUDIO2_STOP_ENGINE_WHEN_IDLE 0x2000 // Used in XAudio2Create to force the engine to Stop when no source voices are Started, and Start when a voice is Started +#define XAUDIO2_1024_QUANTUM 0x8000 // Used in XAudio2Create to specify nondefault processing quantum of 21.33 ms (1024 samples at 48KHz) +#define XAUDIO2_NO_VIRTUAL_AUDIO_CLIENT 0x10000 // Used in CreateMasteringVoice to create a virtual audio client + +// Default parameters for the built-in filter +#define XAUDIO2_DEFAULT_FILTER_TYPE LowPassFilter +#define XAUDIO2_DEFAULT_FILTER_FREQUENCY XAUDIO2_MAX_FILTER_FREQUENCY +#define XAUDIO2_DEFAULT_FILTER_ONEOVERQ 1.0f + +// Internal XAudio2 constants +// The audio frame quantum can be calculated by reducing the fraction: +// SamplesPerAudioFrame / SamplesPerSecond +#define XAUDIO2_QUANTUM_NUMERATOR 1 // On Windows, XAudio2 processes audio +#define XAUDIO2_QUANTUM_DENOMINATOR 100 // in 10ms chunks (= 1/100 seconds) +#define XAUDIO2_QUANTUM_MS (1000.0f * XAUDIO2_QUANTUM_NUMERATOR / XAUDIO2_QUANTUM_DENOMINATOR) + +// XAudio2 error codes +#define FACILITY_XAUDIO2 0x896 +#define XAUDIO2_E_INVALID_CALL 0x88960001 // An API call or one of its arguments was illegal +#define XAUDIO2_E_XMA_DECODER_ERROR 0x88960002 // The XMA hardware suffered an unrecoverable error +#define XAUDIO2_E_XAPO_CREATION_FAILED 0x88960003 // XAudio2 failed to initialize an XAPO effect +#define XAUDIO2_E_DEVICE_INVALIDATED 0x88960004 // An audio device became unusable (unplugged, etc) + +/************************************************************************** + * + * Forward declarations for the XAudio2 interfaces. + * + **************************************************************************/ + +#ifdef __cplusplus +#define FWD_DECLARE(x) interface x +#else +#define FWD_DECLARE(x) typedef interface x x +#endif + +FWD_DECLARE(IXAudio2); +FWD_DECLARE(IXAudio2Voice); +FWD_DECLARE(IXAudio2SourceVoice); +FWD_DECLARE(IXAudio2SubmixVoice); +FWD_DECLARE(IXAudio2MasteringVoice); +FWD_DECLARE(IXAudio2EngineCallback); +FWD_DECLARE(IXAudio2VoiceCallback); + + +/************************************************************************** + * + * XAudio2 structures and enumerations. + * + **************************************************************************/ + + // Used in XAudio2Create, specifies which CPU(s) to use. +typedef UINT32 XAUDIO2_PROCESSOR; +#define Processor1 0x00000001 +#define Processor2 0x00000002 +#define Processor3 0x00000004 +#define Processor4 0x00000008 +#define Processor5 0x00000010 +#define Processor6 0x00000020 +#define Processor7 0x00000040 +#define Processor8 0x00000080 +#define Processor9 0x00000100 +#define Processor10 0x00000200 +#define Processor11 0x00000400 +#define Processor12 0x00000800 +#define Processor13 0x00001000 +#define Processor14 0x00002000 +#define Processor15 0x00004000 +#define Processor16 0x00008000 +#define Processor17 0x00010000 +#define Processor18 0x00020000 +#define Processor19 0x00040000 +#define Processor20 0x00080000 +#define Processor21 0x00100000 +#define Processor22 0x00200000 +#define Processor23 0x00400000 +#define Processor24 0x00800000 +#define Processor25 0x01000000 +#define Processor26 0x02000000 +#define Processor27 0x04000000 +#define Processor28 0x08000000 +#define Processor29 0x10000000 +#define Processor30 0x20000000 +#define Processor31 0x40000000 +#define Processor32 0x80000000 +#define XAUDIO2_ANY_PROCESSOR 0xffffffff +#define XAUDIO2_DEFAULT_PROCESSOR Processor1 + +// Returned by IXAudio2Voice::GetVoiceDetails +typedef struct XAUDIO2_VOICE_DETAILS +{ + UINT32 CreationFlags; // Flags the voice was created with. + UINT32 ActiveFlags; // Flags currently active. + UINT32 InputChannels; // Channels in the voice's input audio. + UINT32 InputSampleRate; // Sample rate of the voice's input audio. +} XAUDIO2_VOICE_DETAILS; + +// Used in XAUDIO2_VOICE_SENDS below +typedef struct XAUDIO2_SEND_DESCRIPTOR +{ + UINT32 Flags; // Either 0 or XAUDIO2_SEND_USEFILTER. + IXAudio2Voice* pOutputVoice; // This send's destination voice. +} XAUDIO2_SEND_DESCRIPTOR; + +// Used in the voice creation functions and in IXAudio2Voice::SetOutputVoices +typedef struct XAUDIO2_VOICE_SENDS +{ + UINT32 SendCount; // Number of sends from this voice. + XAUDIO2_SEND_DESCRIPTOR* pSends; // Array of SendCount send descriptors. +} XAUDIO2_VOICE_SENDS; + +// Used in XAUDIO2_EFFECT_CHAIN below +typedef struct XAUDIO2_EFFECT_DESCRIPTOR +{ + IUnknown* pEffect; // Pointer to the effect object's IUnknown interface. + BOOL InitialState; // TRUE if the effect should begin in the enabled state. + UINT32 OutputChannels; // How many output channels the effect should produce. +} XAUDIO2_EFFECT_DESCRIPTOR; + +// Used in the voice creation functions and in IXAudio2Voice::SetEffectChain +typedef struct XAUDIO2_EFFECT_CHAIN +{ + UINT32 EffectCount; // Number of effects in this voice's effect chain. + XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors; // Array of effect descriptors. +} XAUDIO2_EFFECT_CHAIN; + +// Used in XAUDIO2_FILTER_PARAMETERS below +typedef enum XAUDIO2_FILTER_TYPE +{ + LowPassFilter, // Attenuates frequencies above the cutoff frequency (state-variable filter). + BandPassFilter, // Attenuates frequencies outside a given range (state-variable filter). + HighPassFilter, // Attenuates frequencies below the cutoff frequency (state-variable filter). + NotchFilter, // Attenuates frequencies inside a given range (state-variable filter). + LowPassOnePoleFilter, // Attenuates frequencies above the cutoff frequency (one-pole filter, XAUDIO2_FILTER_PARAMETERS.OneOverQ has no effect) + HighPassOnePoleFilter // Attenuates frequencies below the cutoff frequency (one-pole filter, XAUDIO2_FILTER_PARAMETERS.OneOverQ has no effect) +} XAUDIO2_FILTER_TYPE; + +// Used in IXAudio2Voice::Set/GetFilterParameters and Set/GetOutputFilterParameters +typedef struct XAUDIO2_FILTER_PARAMETERS +{ + XAUDIO2_FILTER_TYPE Type; // Filter type. + float Frequency; // Filter coefficient. + // must be >= 0 and <= XAUDIO2_MAX_FILTER_FREQUENCY + // See XAudio2CutoffFrequencyToRadians() for state-variable filter types and + // XAudio2CutoffFrequencyToOnePoleCoefficient() for one-pole filter types. + float OneOverQ; // Reciprocal of the filter's quality factor Q; + // must be > 0 and <= XAUDIO2_MAX_FILTER_ONEOVERQ. + // Has no effect for one-pole filters. +} XAUDIO2_FILTER_PARAMETERS; + +// Used in IXAudio2SourceVoice::SubmitSourceBuffer +typedef struct XAUDIO2_BUFFER +{ + UINT32 Flags; // Either 0 or XAUDIO2_END_OF_STREAM. + UINT32 AudioBytes; // Size of the audio data buffer in bytes. + const BYTE* pAudioData; // Pointer to the audio data buffer. + UINT32 PlayBegin; // First sample in this buffer to be played. + UINT32 PlayLength; // Length of the region to be played in samples, + // or 0 to play the whole buffer. + UINT32 LoopBegin; // First sample of the region to be looped. + UINT32 LoopLength; // Length of the desired loop region in samples, + // or 0 to loop the entire buffer. + UINT32 LoopCount; // Number of times to repeat the loop region, + // or XAUDIO2_LOOP_INFINITE to loop forever. + void* pContext; // Context value to be passed back in callbacks. +} XAUDIO2_BUFFER; + +// Used in IXAudio2SourceVoice::SubmitSourceBuffer when submitting XWMA data. +// NOTE: If an XWMA sound is submitted in more than one buffer, each buffer's +// pDecodedPacketCumulativeBytes[PacketCount-1] value must be subtracted from +// all the entries in the next buffer's pDecodedPacketCumulativeBytes array. +// And whether a sound is submitted in more than one buffer or not, the final +// buffer of the sound should use the XAUDIO2_END_OF_STREAM flag, or else the +// client must call IXAudio2SourceVoice::Discontinuity after submitting it. +typedef struct XAUDIO2_BUFFER_WMA +{ + const UINT32* pDecodedPacketCumulativeBytes; // Decoded packet's cumulative size array. + // Each element is the number of bytes accumulated + // when the corresponding XWMA packet is decoded in + // order. The array must have PacketCount elements. + UINT32 PacketCount; // Number of XWMA packets submitted. Must be >= 1 and + // divide evenly into XAUDIO2_BUFFER.AudioBytes. +} XAUDIO2_BUFFER_WMA; + +// Returned by IXAudio2SourceVoice::GetState +typedef struct XAUDIO2_VOICE_STATE +{ + void* pCurrentBufferContext; // The pContext value provided in the XAUDIO2_BUFFER + // that is currently being processed, or NULL if + // there are no buffers in the queue. + UINT32 BuffersQueued; // Number of buffers currently queued on the voice + // (including the one that is being processed). + UINT64 SamplesPlayed; // Total number of samples produced by the voice since + // it began processing the current audio stream. + // If XAUDIO2_VOICE_NOSAMPLESPLAYED is specified + // in the call to IXAudio2SourceVoice::GetState, + // this member will not be calculated, saving CPU. +} XAUDIO2_VOICE_STATE; + +// Returned by IXAudio2::GetPerformanceData +typedef struct XAUDIO2_PERFORMANCE_DATA +{ + // CPU usage information + UINT64 AudioCyclesSinceLastQuery; // CPU cycles spent on audio processing since the + // last call to StartEngine or GetPerformanceData. + UINT64 TotalCyclesSinceLastQuery; // Total CPU cycles elapsed since the last call + // (only counts the CPU XAudio2 is running on). + UINT32 MinimumCyclesPerQuantum; // Fewest CPU cycles spent processing any one + // audio quantum since the last call. + UINT32 MaximumCyclesPerQuantum; // Most CPU cycles spent processing any one + // audio quantum since the last call. + + // Memory usage information + UINT32 MemoryUsageInBytes; // Total heap space currently in use. + + // Audio latency and glitching information + UINT32 CurrentLatencyInSamples; // Minimum delay from when a sample is read from a + // source buffer to when it reaches the speakers. + UINT32 GlitchesSinceEngineStarted; // Audio dropouts since the engine was started. + + // Data about XAudio2's current workload + UINT32 ActiveSourceVoiceCount; // Source voices currently playing. + UINT32 TotalSourceVoiceCount; // Source voices currently existing. + UINT32 ActiveSubmixVoiceCount; // Submix voices currently playing/existing. + + UINT32 ActiveResamplerCount; // Resample xAPOs currently active. + UINT32 ActiveMatrixMixCount; // MatrixMix xAPOs currently active. + + // Usage of the hardware XMA decoder (Xbox 360 only) + UINT32 ActiveXmaSourceVoices; // Number of source voices decoding XMA data. + UINT32 ActiveXmaStreams; // A voice can use more than one XMA stream. +} XAUDIO2_PERFORMANCE_DATA; + +// Used in IXAudio2::SetDebugConfiguration +typedef struct XAUDIO2_DEBUG_CONFIGURATION +{ + UINT32 TraceMask; // Bitmap of enabled debug message types. + UINT32 BreakMask; // Message types that will break into the debugger. + BOOL LogThreadID; // Whether to log the thread ID with each message. + BOOL LogFileline; // Whether to log the source file and line number. + BOOL LogFunctionName; // Whether to log the function name. + BOOL LogTiming; // Whether to log message timestamps. +} XAUDIO2_DEBUG_CONFIGURATION; + +// Values for the TraceMask and BreakMask bitmaps. Only ERRORS and WARNINGS +// are valid in BreakMask. WARNINGS implies ERRORS, DETAIL implies INFO, and +// FUNC_CALLS implies API_CALLS. By default, TraceMask is ERRORS and WARNINGS +// and all the other settings are zero. +#define XAUDIO2_LOG_ERRORS 0x0001 // For handled errors with serious effects. +#define XAUDIO2_LOG_WARNINGS 0x0002 // For handled errors that may be recoverable. +#define XAUDIO2_LOG_INFO 0x0004 // Informational chit-chat (e.g. state changes). +#define XAUDIO2_LOG_DETAIL 0x0008 // More detailed chit-chat. +#define XAUDIO2_LOG_API_CALLS 0x0010 // Public API function entries and exits. +#define XAUDIO2_LOG_FUNC_CALLS 0x0020 // Internal function entries and exits. +#define XAUDIO2_LOG_TIMING 0x0040 // Delays detected and other timing data. +#define XAUDIO2_LOG_LOCKS 0x0080 // Usage of critical sections and mutexes. +#define XAUDIO2_LOG_MEMORY 0x0100 // Memory heap usage information. +#define XAUDIO2_LOG_STREAMING 0x1000 // Audio streaming information. + + +/************************************************************************** + * + * IXAudio2: Top-level XAudio2 COM interface. + * + **************************************************************************/ + + // Use default arguments if compiling as C++ +#ifdef __cplusplus +#define X2DEFAULT(x) =x +#else +#define X2DEFAULT(x) +#endif + +#undef INTERFACE +#define INTERFACE IXAudio2 +DECLARE_INTERFACE_(IXAudio2, IUnknown) +{ + // NAME: IXAudio2::QueryInterface + // DESCRIPTION: Queries for a given COM interface on the XAudio2 object. + // Only IID_IUnknown and IID_IXAudio2 are supported. + // + // ARGUMENTS: + // riid - IID of the interface to be obtained. + // ppvInterface - Returns a pointer to the requested interface. + // + STDMETHOD(QueryInterface) (THIS_ REFIID riid, _Outptr_ void** ppvInterface) PURE; + + // NAME: IXAudio2::AddRef + // DESCRIPTION: Adds a reference to the XAudio2 object. + // + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + + // NAME: IXAudio2::Release + // DESCRIPTION: Releases a reference to the XAudio2 object. + // + STDMETHOD_(ULONG, Release) (THIS) PURE; + + // NAME: IXAudio2::RegisterForCallbacks + // DESCRIPTION: Adds a new client to receive XAudio2's engine callbacks. + // + // ARGUMENTS: + // pCallback - Callback interface to be called during each processing pass. + // + STDMETHOD(RegisterForCallbacks) (_In_ IXAudio2EngineCallback* pCallback) PURE; + + // NAME: IXAudio2::UnregisterForCallbacks + // DESCRIPTION: Removes an existing receiver of XAudio2 engine callbacks. + // + // ARGUMENTS: + // pCallback - Previously registered callback interface to be removed. + // + STDMETHOD_(void, UnregisterForCallbacks) (_In_ IXAudio2EngineCallback* pCallback) PURE; + + // NAME: IXAudio2::CreateSourceVoice + // DESCRIPTION: Creates and configures a source voice. + // + // ARGUMENTS: + // ppSourceVoice - Returns the new object's IXAudio2SourceVoice interface. + // pSourceFormat - Format of the audio that will be fed to the voice. + // Flags - XAUDIO2_VOICE flags specifying the source voice's behavior. + // MaxFrequencyRatio - Maximum SetFrequencyRatio argument to be allowed. + // pCallback - Optional pointer to a client-provided callback interface. + // pSendList - Optional list of voices this voice should send audio to. + // pEffectChain - Optional list of effects to apply to the audio data. + // + STDMETHOD(CreateSourceVoice) (THIS_ _Outptr_ IXAudio2SourceVoice** ppSourceVoice, + _In_ const WAVEFORMATEX* pSourceFormat, + UINT32 Flags X2DEFAULT(0), + float MaxFrequencyRatio X2DEFAULT(XAUDIO2_DEFAULT_FREQ_RATIO), + _In_opt_ IXAudio2VoiceCallback* pCallback X2DEFAULT(NULL), + _In_opt_ const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL), + _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; + + // NAME: IXAudio2::CreateSubmixVoice + // DESCRIPTION: Creates and configures a submix voice. + // + // ARGUMENTS: + // ppSubmixVoice - Returns the new object's IXAudio2SubmixVoice interface. + // InputChannels - Number of channels in this voice's input audio data. + // InputSampleRate - Sample rate of this voice's input audio data. + // Flags - XAUDIO2_VOICE flags specifying the submix voice's behavior. + // ProcessingStage - Arbitrary number that determines the processing order. + // pSendList - Optional list of voices this voice should send audio to. + // pEffectChain - Optional list of effects to apply to the audio data. + // + STDMETHOD(CreateSubmixVoice) (THIS_ _Outptr_ IXAudio2SubmixVoice** ppSubmixVoice, + UINT32 InputChannels, UINT32 InputSampleRate, + UINT32 Flags X2DEFAULT(0), UINT32 ProcessingStage X2DEFAULT(0), + _In_opt_ const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL), + _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; + + + // NAME: IXAudio2::CreateMasteringVoice + // DESCRIPTION: Creates and configures a mastering voice. + // + // ARGUMENTS: + // ppMasteringVoice - Returns the new object's IXAudio2MasteringVoice interface. + // InputChannels - Number of channels in this voice's input audio data. + // InputSampleRate - Sample rate of this voice's input audio data. + // Flags - XAUDIO2_VOICE flags specifying the mastering voice's behavior. + // szDeviceId - Identifier of the device to receive the output audio. + // pEffectChain - Optional list of effects to apply to the audio data. + // StreamCategory - The audio stream category to use for this mastering voice + // + STDMETHOD(CreateMasteringVoice) (THIS_ _Outptr_ IXAudio2MasteringVoice** ppMasteringVoice, + UINT32 InputChannels X2DEFAULT(XAUDIO2_DEFAULT_CHANNELS), + UINT32 InputSampleRate X2DEFAULT(XAUDIO2_DEFAULT_SAMPLERATE), + UINT32 Flags X2DEFAULT(0), _In_opt_z_ LPCWSTR szDeviceId X2DEFAULT(NULL), + _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL), + _In_ AUDIO_STREAM_CATEGORY StreamCategory X2DEFAULT(AudioCategory_GameEffects)) PURE; + + // NAME: IXAudio2::StartEngine + // DESCRIPTION: Creates and starts the audio processing thread. + // + STDMETHOD(StartEngine) (THIS) PURE; + + // NAME: IXAudio2::StopEngine + // DESCRIPTION: Stops and destroys the audio processing thread. + // + STDMETHOD_(void, StopEngine) (THIS) PURE; + + // NAME: IXAudio2::CommitChanges + // DESCRIPTION: Atomically applies a set of operations previously tagged + // with a given identifier. + // + // ARGUMENTS: + // OperationSet - Identifier of the set of operations to be applied. + // + STDMETHOD(CommitChanges) (THIS_ UINT32 OperationSet) PURE; + + // NAME: IXAudio2::GetPerformanceData + // DESCRIPTION: Returns current resource usage details: memory, CPU, etc. + // + // ARGUMENTS: + // pPerfData - Returns the performance data structure. + // + STDMETHOD_(void, GetPerformanceData) (THIS_ _Out_ XAUDIO2_PERFORMANCE_DATA* pPerfData) PURE; + + // NAME: IXAudio2::SetDebugConfiguration + // DESCRIPTION: Configures XAudio2's debug output (in debug builds only). + // + // ARGUMENTS: + // pDebugConfiguration - Structure describing the debug output behavior. + // pReserved - Optional parameter; must be NULL. + // + STDMETHOD_(void, SetDebugConfiguration) (THIS_ _In_opt_ const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration, + _Reserved_ void* pReserved X2DEFAULT(NULL)) PURE; +}; + + +/************************************************************************** + * + * IXAudio2Voice: Base voice management interface. + * + **************************************************************************/ + +#undef INTERFACE +#define INTERFACE IXAudio2Voice +DECLARE_INTERFACE(IXAudio2Voice) +{ + // These methods are declared in a macro so that the same declarations + // can be used in the derived voice types (IXAudio2SourceVoice, etc). + +#define Declare_IXAudio2Voice_Methods() \ + \ + /* NAME: IXAudio2Voice::GetVoiceDetails + // DESCRIPTION: Returns the basic characteristics of this voice. + // + // ARGUMENTS: + // pVoiceDetails - Returns the voice's details. + */\ + STDMETHOD_(void, GetVoiceDetails) (THIS_ _Out_ XAUDIO2_VOICE_DETAILS* pVoiceDetails) PURE; \ + \ + /* NAME: IXAudio2Voice::SetOutputVoices + // DESCRIPTION: Replaces the set of submix/mastering voices that receive + // this voice's output. + // + // ARGUMENTS: + // pSendList - Optional list of voices this voice should send audio to. + */\ + STDMETHOD(SetOutputVoices) (THIS_ _In_opt_ const XAUDIO2_VOICE_SENDS* pSendList) PURE; \ + \ + /* NAME: IXAudio2Voice::SetEffectChain + // DESCRIPTION: Replaces this voice's current effect chain with a new one. + // + // ARGUMENTS: + // pEffectChain - Structure describing the new effect chain to be used. + */\ + STDMETHOD(SetEffectChain) (THIS_ _In_opt_ const XAUDIO2_EFFECT_CHAIN* pEffectChain) PURE; \ + \ + /* NAME: IXAudio2Voice::EnableEffect + // DESCRIPTION: Enables an effect in this voice's effect chain. + // + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(EnableEffect) (THIS_ UINT32 EffectIndex, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::DisableEffect + // DESCRIPTION: Disables an effect in this voice's effect chain. + // + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(DisableEffect) (THIS_ UINT32 EffectIndex, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetEffectState + // DESCRIPTION: Returns the running state of an effect. + // + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // pEnabled - Returns the enabled/disabled state of the given effect. + */\ + STDMETHOD_(void, GetEffectState) (THIS_ UINT32 EffectIndex, _Out_ BOOL* pEnabled) PURE; \ + \ + /* NAME: IXAudio2Voice::SetEffectParameters + // DESCRIPTION: Sets effect-specific parameters. + // + // REMARKS: Unlike IXAPOParameters::SetParameters, this method may + // be called from any thread. XAudio2 implements + // appropriate synchronization to copy the parameters to the + // realtime audio processing thread. + // + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // pParameters - Pointer to an effect-specific parameters block. + // ParametersByteSize - Size of the pParameters array in bytes. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(SetEffectParameters) (THIS_ UINT32 EffectIndex, \ + _In_reads_bytes_(ParametersByteSize) const void* pParameters, \ + UINT32 ParametersByteSize, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetEffectParameters + // DESCRIPTION: Obtains the current effect-specific parameters. + // + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // pParameters - Returns the current values of the effect-specific parameters. + // ParametersByteSize - Size of the pParameters array in bytes. + */\ + STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, \ + _Out_writes_bytes_(ParametersByteSize) void* pParameters, \ + UINT32 ParametersByteSize) PURE; \ + \ + /* NAME: IXAudio2Voice::SetFilterParameters + // DESCRIPTION: Sets this voice's filter parameters. + // + // ARGUMENTS: + // pParameters - Pointer to the filter's parameter structure. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(SetFilterParameters) (THIS_ _In_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetFilterParameters + // DESCRIPTION: Returns this voice's current filter parameters. + // + // ARGUMENTS: + // pParameters - Returns the filter parameters. + */\ + STDMETHOD_(void, GetFilterParameters) (THIS_ _Out_ XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \ + \ + /* NAME: IXAudio2Voice::SetOutputFilterParameters + // DESCRIPTION: Sets the filter parameters on one of this voice's sends. + // + // ARGUMENTS: + // pDestinationVoice - Destination voice of the send whose filter parameters will be set. + // pParameters - Pointer to the filter's parameter structure. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(SetOutputFilterParameters) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ + _In_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetOutputFilterParameters + // DESCRIPTION: Returns the filter parameters from one of this voice's sends. + // + // ARGUMENTS: + // pDestinationVoice - Destination voice of the send whose filter parameters will be read. + // pParameters - Returns the filter parameters. + */\ + STDMETHOD_(void, GetOutputFilterParameters) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ + _Out_ XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \ + \ + /* NAME: IXAudio2Voice::SetVolume + // DESCRIPTION: Sets this voice's overall volume level. + // + // ARGUMENTS: + // Volume - New overall volume level to be used, as an amplitude factor. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(SetVolume) (THIS_ float Volume, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetVolume + // DESCRIPTION: Obtains this voice's current overall volume level. + // + // ARGUMENTS: + // pVolume: Returns the voice's current overall volume level. + */\ + STDMETHOD_(void, GetVolume) (THIS_ _Out_ float* pVolume) PURE; \ + \ + /* NAME: IXAudio2Voice::SetChannelVolumes + // DESCRIPTION: Sets this voice's per-channel volume levels. + // + // ARGUMENTS: + // Channels - Used to confirm the voice's channel count. + // pVolumes - Array of per-channel volume levels to be used. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(SetChannelVolumes) (THIS_ UINT32 Channels, _In_reads_(Channels) const float* pVolumes, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetChannelVolumes + // DESCRIPTION: Returns this voice's current per-channel volume levels. + // + // ARGUMENTS: + // Channels - Used to confirm the voice's channel count. + // pVolumes - Returns an array of the current per-channel volume levels. + */\ + STDMETHOD_(void, GetChannelVolumes) (THIS_ UINT32 Channels, _Out_writes_(Channels) float* pVolumes) PURE; \ + \ + /* NAME: IXAudio2Voice::SetOutputMatrix + // DESCRIPTION: Sets the volume levels used to mix from each channel of this + // voice's output audio to each channel of a given destination + // voice's input audio. + // + // ARGUMENTS: + // pDestinationVoice - The destination voice whose mix matrix to change. + // SourceChannels - Used to confirm this voice's output channel count + // (the number of channels produced by the last effect in the chain). + // DestinationChannels - Confirms the destination voice's input channels. + // pLevelMatrix - Array of [SourceChannels * DestinationChannels] send + // levels. The level used to send from source channel S to destination + // channel D should be in pLevelMatrix[S + SourceChannels * D]. + // OperationSet - Used to identify this call as part of a deferred batch. + */\ + STDMETHOD(SetOutputMatrix) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ + UINT32 SourceChannels, UINT32 DestinationChannels, \ + _In_reads_(SourceChannels * DestinationChannels) const float* pLevelMatrix, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + \ + /* NAME: IXAudio2Voice::GetOutputMatrix + // DESCRIPTION: Obtains the volume levels used to send each channel of this + // voice's output audio to each channel of a given destination + // voice's input audio. + // + // ARGUMENTS: + // pDestinationVoice - The destination voice whose mix matrix to obtain. + // SourceChannels - Used to confirm this voice's output channel count + // (the number of channels produced by the last effect in the chain). + // DestinationChannels - Confirms the destination voice's input channels. + // pLevelMatrix - Array of send levels, as above. + */\ + STDMETHOD_(void, GetOutputMatrix) (THIS_ _In_opt_ IXAudio2Voice* pDestinationVoice, \ + UINT32 SourceChannels, UINT32 DestinationChannels, \ + _Out_writes_(SourceChannels * DestinationChannels) float* pLevelMatrix) PURE; \ + \ + /* NAME: IXAudio2Voice::DestroyVoice + // DESCRIPTION: Destroys this voice, stopping it if necessary and removing + // it from the XAudio2 graph. + */\ + STDMETHOD_(void, DestroyVoice) (THIS) PURE + + Declare_IXAudio2Voice_Methods(); +}; + + +/************************************************************************** + * + * IXAudio2SourceVoice: Source voice management interface. + * + **************************************************************************/ + +#undef INTERFACE +#define INTERFACE IXAudio2SourceVoice +DECLARE_INTERFACE_(IXAudio2SourceVoice, IXAudio2Voice) +{ + // Methods from IXAudio2Voice base interface + Declare_IXAudio2Voice_Methods(); + + // NAME: IXAudio2SourceVoice::Start + // DESCRIPTION: Makes this voice start consuming and processing audio. + // + // ARGUMENTS: + // Flags - Flags controlling how the voice should be started. + // OperationSet - Used to identify this call as part of a deferred batch. + // + STDMETHOD(Start) (THIS_ UINT32 Flags X2DEFAULT(0), UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + + // NAME: IXAudio2SourceVoice::Stop + // DESCRIPTION: Makes this voice stop consuming audio. + // + // ARGUMENTS: + // Flags - Flags controlling how the voice should be stopped. + // OperationSet - Used to identify this call as part of a deferred batch. + // + STDMETHOD(Stop) (THIS_ UINT32 Flags X2DEFAULT(0), UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + + // NAME: IXAudio2SourceVoice::SubmitSourceBuffer + // DESCRIPTION: Adds a new audio buffer to this voice's input queue. + // + // ARGUMENTS: + // pBuffer - Pointer to the buffer structure to be queued. + // pBufferWMA - Additional structure used only when submitting XWMA data. + // + STDMETHOD(SubmitSourceBuffer) (THIS_ _In_ const XAUDIO2_BUFFER* pBuffer, _In_opt_ const XAUDIO2_BUFFER_WMA* pBufferWMA X2DEFAULT(NULL)) PURE; + + // NAME: IXAudio2SourceVoice::FlushSourceBuffers + // DESCRIPTION: Removes all pending audio buffers from this voice's queue. + // + STDMETHOD(FlushSourceBuffers) (THIS) PURE; + + // NAME: IXAudio2SourceVoice::Discontinuity + // DESCRIPTION: Notifies the voice of an intentional break in the stream of + // audio buffers (e.g. the end of a sound), to prevent XAudio2 + // from interpreting an empty buffer queue as a glitch. + // + STDMETHOD(Discontinuity) (THIS) PURE; + + // NAME: IXAudio2SourceVoice::ExitLoop + // DESCRIPTION: Breaks out of the current loop when its end is reached. + // + // ARGUMENTS: + // OperationSet - Used to identify this call as part of a deferred batch. + // + STDMETHOD(ExitLoop) (THIS_ UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + + // NAME: IXAudio2SourceVoice::GetState + // DESCRIPTION: Returns the number of buffers currently queued on this voice, + // the pContext value associated with the currently processing + // buffer (if any), and other voice state information. + // + // ARGUMENTS: + // pVoiceState - Returns the state information. + // Flags - Flags controlling what voice state is returned. + // + STDMETHOD_(void, GetState) (THIS_ _Out_ XAUDIO2_VOICE_STATE* pVoiceState, UINT32 Flags X2DEFAULT(0)) PURE; + + // NAME: IXAudio2SourceVoice::SetFrequencyRatio + // DESCRIPTION: Sets this voice's frequency adjustment, i.e. its pitch. + // + // ARGUMENTS: + // Ratio - Frequency change, expressed as source frequency / target frequency. + // OperationSet - Used to identify this call as part of a deferred batch. + // + STDMETHOD(SetFrequencyRatio) (THIS_ float Ratio, + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + + // NAME: IXAudio2SourceVoice::GetFrequencyRatio + // DESCRIPTION: Returns this voice's current frequency adjustment ratio. + // + // ARGUMENTS: + // pRatio - Returns the frequency adjustment. + // + STDMETHOD_(void, GetFrequencyRatio) (THIS_ _Out_ float* pRatio) PURE; + + // NAME: IXAudio2SourceVoice::SetSourceSampleRate + // DESCRIPTION: Reconfigures this voice to treat its source data as being + // at a different sample rate than the original one specified + // in CreateSourceVoice's pSourceFormat argument. + // + // ARGUMENTS: + // UINT32 - The intended sample rate of further submitted source data. + // + STDMETHOD(SetSourceSampleRate) (THIS_ UINT32 NewSourceSampleRate) PURE; +}; + + +/************************************************************************** + * + * IXAudio2SubmixVoice: Submixing voice management interface. + * + **************************************************************************/ + +#undef INTERFACE +#define INTERFACE IXAudio2SubmixVoice +DECLARE_INTERFACE_(IXAudio2SubmixVoice, IXAudio2Voice) +{ + // Methods from IXAudio2Voice base interface + Declare_IXAudio2Voice_Methods(); + + // There are currently no methods specific to submix voices. +}; + + +/************************************************************************** + * + * IXAudio2MasteringVoice: Mastering voice management interface. + * + **************************************************************************/ + +#undef INTERFACE +#define INTERFACE IXAudio2MasteringVoice +DECLARE_INTERFACE_(IXAudio2MasteringVoice, IXAudio2Voice) +{ + // Methods from IXAudio2Voice base interface + Declare_IXAudio2Voice_Methods(); + + // NAME: IXAudio2MasteringVoice::GetChannelMask + // DESCRIPTION: Returns the channel mask for this voice + // + // ARGUMENTS: + // pChannelMask - returns the channel mask for this voice. This corresponds + // to the dwChannelMask member of WAVEFORMATEXTENSIBLE. + // + STDMETHOD(GetChannelMask) (THIS_ _Out_ DWORD* pChannelmask) PURE; +}; + + +/************************************************************************** + * + * IXAudio2EngineCallback: Client notification interface for engine events. + * + * REMARKS: Contains methods to notify the client when certain events happen + * in the XAudio2 engine. This interface should be implemented by + * the client. XAudio2 will call these methods via the interface + * pointer provided by the client when it calls + * IXAudio2::RegisterForCallbacks. + * + **************************************************************************/ + +#undef INTERFACE +#define INTERFACE IXAudio2EngineCallback +DECLARE_INTERFACE(IXAudio2EngineCallback) +{ + // Called by XAudio2 just before an audio processing pass begins. + STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE; + + // Called just after an audio processing pass ends. + STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE; + + // Called in the event of a critical system error which requires XAudio2 + // to be closed down and restarted. The error code is given in Error. + STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE; +}; + + +/************************************************************************** + * + * IXAudio2VoiceCallback: Client notification interface for voice events. + * + * REMARKS: Contains methods to notify the client when certain events happen + * in an XAudio2 voice. This interface should be implemented by the + * client. XAudio2 will call these methods via an interface pointer + * provided by the client in the IXAudio2::CreateSourceVoice call. + * + **************************************************************************/ + +#undef INTERFACE +#define INTERFACE IXAudio2VoiceCallback +DECLARE_INTERFACE(IXAudio2VoiceCallback) +{ + // Called just before this voice's processing pass begins. + STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) PURE; + + // Called just after this voice's processing pass ends. + STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) PURE; + + // Called when this voice has just finished playing a buffer stream + // (as marked with the XAUDIO2_END_OF_STREAM flag on the last buffer). + STDMETHOD_(void, OnStreamEnd) (THIS) PURE; + + // Called when this voice is about to start processing a new buffer. + STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) PURE; + + // Called when this voice has just finished processing a buffer. + // The buffer can now be reused or destroyed. + STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) PURE; + + // Called when this voice has just reached the end position of a loop. + STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) PURE; + + // Called in the event of a critical error during voice processing, + // such as a failing xAPO or an error from the hardware XMA decoder. + // The voice may have to be destroyed and re-created to recover from + // the error. The callback arguments report which buffer was being + // processed when the error occurred, and its HRESULT code. + STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) PURE; +}; + + +/************************************************************************** + * + * Macros to make it easier to use the XAudio2 COM interfaces in C code. + * + **************************************************************************/ + +#ifndef __cplusplus + + // IXAudio2 +#define IXAudio2_QueryInterface(This,riid,ppvInterface) ((This)->lpVtbl->QueryInterface(This,riid,ppvInterface)) +#define IXAudio2_AddRef(This) ((This)->lpVtbl->AddRef(This)) +#define IXAudio2_Release(This) ((This)->lpVtbl->Release(This)) +#define IXAudio2_CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain) ((This)->lpVtbl->CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain)) +#define IXAudio2_CreateSubmixVoice(This,ppSubmixVoice,InputChannels,InputSampleRate,Flags,ProcessingStage,pSendList,pEffectChain) ((This)->lpVtbl->CreateSubmixVoice(This,ppSubmixVoice,InputChannels,InputSampleRate,Flags,ProcessingStage,pSendList,pEffectChain)) +#define IXAudio2_CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceId,pEffectChain,StreamCategory) ((This)->lpVtbl->CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceId,pEffectChain,StreamCategory)) +#define IXAudio2_StartEngine(This) ((This)->lpVtbl->StartEngine(This)) +#define IXAudio2_StopEngine(This) ((This)->lpVtbl->StopEngine(This)) +#define IXAudio2_CommitChanges(This,OperationSet) ((This)->lpVtbl->CommitChanges(This,OperationSet)) +#define IXAudio2_GetPerformanceData(This,pPerfData) ((This)->lpVtbl->GetPerformanceData(This,pPerfData)) +#define IXAudio2_SetDebugConfiguration(This,pDebugConfiguration,pReserved) ((This)->lpVtbl->SetDebugConfiguration(This,pDebugConfiguration,pReserved)) + +// IXAudio2Voice +#define IXAudio2Voice_GetVoiceDetails(This,pVoiceDetails) ((This)->lpVtbl->GetVoiceDetails(This,pVoiceDetails)) +#define IXAudio2Voice_SetOutputVoices(This,pSendList) ((This)->lpVtbl->SetOutputVoices(This,pSendList)) +#define IXAudio2Voice_SetEffectChain(This,pEffectChain) ((This)->lpVtbl->SetEffectChain(This,pEffectChain)) +#define IXAudio2Voice_EnableEffect(This,EffectIndex,OperationSet) ((This)->lpVtbl->EnableEffect(This,EffectIndex,OperationSet)) +#define IXAudio2Voice_DisableEffect(This,EffectIndex,OperationSet) ((This)->lpVtbl->DisableEffect(This,EffectIndex,OperationSet)) +#define IXAudio2Voice_GetEffectState(This,EffectIndex,pEnabled) ((This)->lpVtbl->GetEffectState(This,EffectIndex,pEnabled)) +#define IXAudio2Voice_SetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize, OperationSet) ((This)->lpVtbl->SetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize,OperationSet)) +#define IXAudio2Voice_GetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize) ((This)->lpVtbl->GetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize)) +#define IXAudio2Voice_SetFilterParameters(This,pParameters,OperationSet) ((This)->lpVtbl->SetFilterParameters(This,pParameters,OperationSet)) +#define IXAudio2Voice_GetFilterParameters(This,pParameters) ((This)->lpVtbl->GetFilterParameters(This,pParameters)) +#define IXAudio2Voice_SetOutputFilterParameters(This,pDestinationVoice,pParameters,OperationSet) ((This)->lpVtbl->SetOutputFilterParameters(This,pDestinationVoice,pParameters,OperationSet)) +#define IXAudio2Voice_GetOutputFilterParameters(This,pDestinationVoice,pParameters) ((This)->lpVtbl->GetOutputFilterParameters(This,pDestinationVoice,pParameters)) +#define IXAudio2Voice_SetVolume(This,Volume,OperationSet) ((This)->lpVtbl->SetVolume(This,Volume,OperationSet)) +#define IXAudio2Voice_GetVolume(This,pVolume) ((This)->lpVtbl->GetVolume(This,pVolume)) +#define IXAudio2Voice_SetChannelVolumes(This,Channels,pVolumes,OperationSet) ((This)->lpVtbl->SetChannelVolumes(This,Channels,pVolumes,OperationSet)) +#define IXAudio2Voice_GetChannelVolumes(This,Channels,pVolumes) ((This)->lpVtbl->GetChannelVolumes(This,Channels,pVolumes)) +#define IXAudio2Voice_SetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix,OperationSet) ((This)->lpVtbl->SetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix,OperationSet)) +#define IXAudio2Voice_GetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix) ((This)->lpVtbl->GetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix)) +#define IXAudio2Voice_DestroyVoice(This) ((This)->lpVtbl->DestroyVoice(This)) + +// IXAudio2SourceVoice +#define IXAudio2SourceVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails +#define IXAudio2SourceVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices +#define IXAudio2SourceVoice_SetEffectChain IXAudio2Voice_SetEffectChain +#define IXAudio2SourceVoice_EnableEffect IXAudio2Voice_EnableEffect +#define IXAudio2SourceVoice_DisableEffect IXAudio2Voice_DisableEffect +#define IXAudio2SourceVoice_GetEffectState IXAudio2Voice_GetEffectState +#define IXAudio2SourceVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters +#define IXAudio2SourceVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters +#define IXAudio2SourceVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters +#define IXAudio2SourceVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters +#define IXAudio2SourceVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters +#define IXAudio2SourceVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters +#define IXAudio2SourceVoice_SetVolume IXAudio2Voice_SetVolume +#define IXAudio2SourceVoice_GetVolume IXAudio2Voice_GetVolume +#define IXAudio2SourceVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes +#define IXAudio2SourceVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes +#define IXAudio2SourceVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix +#define IXAudio2SourceVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix +#define IXAudio2SourceVoice_DestroyVoice IXAudio2Voice_DestroyVoice +#define IXAudio2SourceVoice_Start(This,Flags,OperationSet) ((This)->lpVtbl->Start(This,Flags,OperationSet)) +#define IXAudio2SourceVoice_Stop(This,Flags,OperationSet) ((This)->lpVtbl->Stop(This,Flags,OperationSet)) +#define IXAudio2SourceVoice_SubmitSourceBuffer(This,pBuffer,pBufferWMA) ((This)->lpVtbl->SubmitSourceBuffer(This,pBuffer,pBufferWMA)) +#define IXAudio2SourceVoice_FlushSourceBuffers(This) ((This)->lpVtbl->FlushSourceBuffers(This)) +#define IXAudio2SourceVoice_Discontinuity(This) ((This)->lpVtbl->Discontinuity(This)) +#define IXAudio2SourceVoice_ExitLoop(This,OperationSet) ((This)->lpVtbl->ExitLoop(This,OperationSet)) +#define IXAudio2SourceVoice_GetState(This,pVoiceState,Flags) ((This)->lpVtbl->GetState(This,pVoiceState,Flags)) +#define IXAudio2SourceVoice_SetFrequencyRatio(This,Ratio,OperationSet) ((This)->lpVtbl->SetFrequencyRatio(This,Ratio,OperationSet)) +#define IXAudio2SourceVoice_GetFrequencyRatio(This,pRatio) ((This)->lpVtbl->GetFrequencyRatio(This,pRatio)) +#define IXAudio2SourceVoice_SetSourceSampleRate(This,NewSourceSampleRate) ((This)->lpVtbl->SetSourceSampleRate(This,NewSourceSampleRate)) + +// IXAudio2SubmixVoice +#define IXAudio2SubmixVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails +#define IXAudio2SubmixVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices +#define IXAudio2SubmixVoice_SetEffectChain IXAudio2Voice_SetEffectChain +#define IXAudio2SubmixVoice_EnableEffect IXAudio2Voice_EnableEffect +#define IXAudio2SubmixVoice_DisableEffect IXAudio2Voice_DisableEffect +#define IXAudio2SubmixVoice_GetEffectState IXAudio2Voice_GetEffectState +#define IXAudio2SubmixVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters +#define IXAudio2SubmixVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters +#define IXAudio2SubmixVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters +#define IXAudio2SubmixVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters +#define IXAudio2SubmixVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters +#define IXAudio2SubmixVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters +#define IXAudio2SubmixVoice_SetVolume IXAudio2Voice_SetVolume +#define IXAudio2SubmixVoice_GetVolume IXAudio2Voice_GetVolume +#define IXAudio2SubmixVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes +#define IXAudio2SubmixVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes +#define IXAudio2SubmixVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix +#define IXAudio2SubmixVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix +#define IXAudio2SubmixVoice_DestroyVoice IXAudio2Voice_DestroyVoice + +/* IXAudio2MasteringVoice */ +#define IXAudio2MasteringVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails +#define IXAudio2MasteringVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices +#define IXAudio2MasteringVoice_SetEffectChain IXAudio2Voice_SetEffectChain +#define IXAudio2MasteringVoice_EnableEffect IXAudio2Voice_EnableEffect +#define IXAudio2MasteringVoice_DisableEffect IXAudio2Voice_DisableEffect +#define IXAudio2MasteringVoice_GetEffectState IXAudio2Voice_GetEffectState +#define IXAudio2MasteringVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters +#define IXAudio2MasteringVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters +#define IXAudio2MasteringVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters +#define IXAudio2MasteringVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters +#define IXAudio2MasteringVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters +#define IXAudio2MasteringVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters +#define IXAudio2MasteringVoice_SetVolume IXAudio2Voice_SetVolume +#define IXAudio2MasteringVoice_GetVolume IXAudio2Voice_GetVolume +#define IXAudio2MasteringVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes +#define IXAudio2MasteringVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes +#define IXAudio2MasteringVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix +#define IXAudio2MasteringVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix +#define IXAudio2MasteringVoice_DestroyVoice IXAudio2Voice_DestroyVoice +#define IXAudio2MasteringVoice_GetChannelMask(This,pChannelMask) ((This)->lpVtbl->GetChannelMask(This,pChannelMask)) + +#endif /* #ifndef __cplusplus */ + + +/************************************************************************** + * + * Utility functions used to convert from pitch in semitones and volume + * in decibels to the frequency and amplitude ratio units used by XAudio2. + * These are only defined if the client #defines XAUDIO2_HELPER_FUNCTIONS + * prior to #including xaudio2.h. + * + **************************************************************************/ + +#ifdef XAUDIO2_HELPER_FUNCTIONS + +#define _USE_MATH_DEFINES /* Make math.h define M_PI */ +#include /* For powf, log10f, sinf and asinf */ + +/* Calculate the argument to SetVolume from a decibel value */ +static INLINE float XAudio2DecibelsToAmplitudeRatio(float Decibels) +{ + return powf(10.0f, Decibels / 20.0f); +} + +/* Recover a volume in decibels from an amplitude factor */ +static INLINE float XAudio2AmplitudeRatioToDecibels(float Volume) +{ + if (Volume == 0) + return -3.402823466e+38f; /* Smallest float value (-FLT_MAX) */ + return 20.0f * log10f(Volume); +} + +/* Calculate the argument to SetFrequencyRatio from a semitone value */ +static INLINE float XAudio2SemitonesToFrequencyRatio(float Semitones) +{ + /* FrequencyRatio = 2 ^ Octaves * = 2 ^ (Semitones / 12) - */ - return powf(2.0f, Semitones / 12.0f); -} - -/* Recover a pitch in semitones from a frequency ratio */ -static INLINE float XAudio2FrequencyRatioToSemitones(float FrequencyRatio) -{ - /* Semitones = 12 * log2(FrequencyRatio) + */ + return powf(2.0f, Semitones / 12.0f); +} + +/* Recover a pitch in semitones from a frequency ratio */ +static INLINE float XAudio2FrequencyRatioToSemitones(float FrequencyRatio) +{ + /* Semitones = 12 * log2(FrequencyRatio) * = 12 * log2(10) * log10(FrequencyRatio) - */ - return 39.86313713864835f * log10f(FrequencyRatio); -} - -/* Convert from filter cutoff frequencies expressed in Hertz to the radian - * frequency values used in XAUDIO2_FILTER_PARAMETERS.Frequency, state-variable - * filter types only. Use XAudio2CutoffFrequencyToOnePoleCoefficient() for one-pole filter types. - * Note that the highest CutoffFrequency supported is SampleRate/6. + */ + return 39.86313713864835f * log10f(FrequencyRatio); +} + +/* Convert from filter cutoff frequencies expressed in Hertz to the radian + * frequency values used in XAUDIO2_FILTER_PARAMETERS.Frequency, state-variable + * filter types only. Use XAudio2CutoffFrequencyToOnePoleCoefficient() for one-pole filter types. + * Note that the highest CutoffFrequency supported is SampleRate/6. * Higher values of CutoffFrequency will return XAUDIO2_MAX_FILTER_FREQUENCY. - */ -static INLINE float XAudio2CutoffFrequencyToRadians(float CutoffFrequency, UINT32 SampleRate) -{ - if ((UINT32)(CutoffFrequency * 6.0f) >= SampleRate) - return XAUDIO2_MAX_FILTER_FREQUENCY; - return 2.0f * sinf((float)M_PI * CutoffFrequency / SampleRate); -} - -/* Convert from radian frequencies back to absolute frequencies in Hertz */ -static INLINE float XAudio2RadiansToCutoffFrequency(float Radians, float SampleRate) -{ - return SampleRate * asinf(Radians / 2.0f) / (float)M_PI; -} - -/* Convert from filter cutoff frequencies expressed in Hertz to the filter - * coefficients used with XAUDIO2_FILTER_PARAMETERS.Frequency, - * LowPassOnePoleFilter and HighPassOnePoleFilter filter types only. + */ +static INLINE float XAudio2CutoffFrequencyToRadians(float CutoffFrequency, UINT32 SampleRate) +{ + if ((UINT32)(CutoffFrequency * 6.0f) >= SampleRate) + return XAUDIO2_MAX_FILTER_FREQUENCY; + return 2.0f * sinf((float)M_PI * CutoffFrequency / SampleRate); +} + +/* Convert from radian frequencies back to absolute frequencies in Hertz */ +static INLINE float XAudio2RadiansToCutoffFrequency(float Radians, float SampleRate) +{ + return SampleRate * asinf(Radians / 2.0f) / (float)M_PI; +} + +/* Convert from filter cutoff frequencies expressed in Hertz to the filter + * coefficients used with XAUDIO2_FILTER_PARAMETERS.Frequency, + * LowPassOnePoleFilter and HighPassOnePoleFilter filter types only. * Use XAudio2CutoffFrequencyToRadians() for state-variable filter types. - */ -static INLINE float XAudio2CutoffFrequencyToOnePoleCoefficient(float CutoffFrequency, UINT32 SampleRate) -{ - if ((UINT32)CutoffFrequency >= SampleRate) - return XAUDIO2_MAX_FILTER_FREQUENCY; - return (1.0f - powf(1.0f - 2.0f * CutoffFrequency / SampleRate, 2.0f)); -} - - -#endif // #ifdef XAUDIO2_HELPER_FUNCTIONS - - -/************************************************************************** - * - * XAudio2Create: Top-level function that creates an XAudio2 instance. - * - * ARGUMENTS: - * - * Flags - Flags specifying the XAudio2 object's behavior. - * - * XAudio2Processor - An XAUDIO2_PROCESSOR value that specifies the - * hardware threads (Xbox) or processors (Windows) that XAudio2 - * will use. Note that XAudio2 supports concurrent processing on - * multiple threads, using any combination of XAUDIO2_PROCESSOR - * flags. The values are platform-specific; platform-independent - * code can use XAUDIO2_DEFAULT_PROCESSOR to use the default on - * each platform. - * - **************************************************************************/ - -#ifdef __cplusplus__ - -#if (defined XAUDIO2_EXPORT) - /* We're building xaudio2.dll */ -#define XAUDIO2_STDAPI extern "C" __declspec(dllexport) HRESULT __stdcall -#else - /* We're an xaudio2 client */ -#define XAUDIO2_STDAPI extern "C" __declspec(dllimport) HRESULT __stdcall -#endif - -#else - - /* Modified for C support */ - -#if (defined XAUDIO2_EXPORT) - /* We're building xaudio2.dll */ -#define XAUDIO2_STDAPI __declspec(dllexport) HRESULT __stdcall -#else - /* We're an xaudio2 client */ -#define XAUDIO2_STDAPI __declspec(dllimport) HRESULT __stdcall -#endif - -#endif - -#if (NTDDI_VERSION >= NTDDI_WIN10_RS5) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -XAUDIO2_STDAPI XAudio2CreateWithVersionInfo(_Outptr_ IXAudio2** ppXAudio2, - UINT32 Flags X2DEFAULT(0), - XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR), - DWORD ntddiVersion X2DEFAULT(NTDDI_VERSION)); - -static INLINE HRESULT XAudio2Create(_Outptr_ IXAudio2** ppXAudio2, - UINT32 Flags X2DEFAULT(0), - XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)) -{ - /* When compiled for RS5 or later, try to invoke XAudio2CreateWithVersionInfo. - * Need to use LoadLibrary in case the app is running on an older OS. */ - typedef HRESULT(__stdcall *XAudio2CreateWithVersionInfoFunc)(_Outptr_ IXAudio2**, UINT32, XAUDIO2_PROCESSOR, DWORD); - typedef HRESULT(__stdcall *XAudio2CreateInfoFunc)(_Outptr_ IXAudio2**, UINT32, XAUDIO2_PROCESSOR); - - static HMODULE s_dllInstance = NULL; - static XAudio2CreateWithVersionInfoFunc s_pfnAudio2CreateWithVersion = NULL; - static XAudio2CreateInfoFunc s_pfnAudio2Create = NULL; - - if (s_dllInstance == NULL) - { - s_dllInstance = LoadLibraryEx(XAUDIO2_DLL, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (s_dllInstance == NULL) - return HRESULT_FROM_WIN32(GetLastError()); - - s_pfnAudio2CreateWithVersion = (XAudio2CreateWithVersionInfoFunc)(void*)GetProcAddress(s_dllInstance, "XAudio2CreateWithVersionInfo"); - if (s_pfnAudio2CreateWithVersion == NULL) - { - s_pfnAudio2Create = (XAudio2CreateInfoFunc)(void*)GetProcAddress(s_dllInstance, "XAudio2Create"); - if (s_pfnAudio2Create == NULL) - return HRESULT_FROM_WIN32(GetLastError()); - } - } - - if (s_pfnAudio2CreateWithVersion != NULL) - return (*s_pfnAudio2CreateWithVersion)(ppXAudio2, Flags, XAudio2Processor, NTDDI_VERSION); - return (*s_pfnAudio2Create)(ppXAudio2, Flags, XAudio2Processor); -} -#else -/* RS4 or older, or not a desktop app */ -XAUDIO2_STDAPI XAudio2Create(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0), - XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)); -#endif - -/* Undo the #pragma pack(push, 1) directive at the top of this file */ -#pragma pack(pop) - -#endif /* #ifndef GUID_DEFS_ONLY */ - -#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_TV_APP | WINAPI_PARTITION_TV_TITLE) */ -#pragma endregion - + */ +static INLINE float XAudio2CutoffFrequencyToOnePoleCoefficient(float CutoffFrequency, UINT32 SampleRate) +{ + if ((UINT32)CutoffFrequency >= SampleRate) + return XAUDIO2_MAX_FILTER_FREQUENCY; + return (1.0f - powf(1.0f - 2.0f * CutoffFrequency / SampleRate, 2.0f)); +} + + +#endif // #ifdef XAUDIO2_HELPER_FUNCTIONS + + +/************************************************************************** + * + * XAudio2Create: Top-level function that creates an XAudio2 instance. + * + * ARGUMENTS: + * + * Flags - Flags specifying the XAudio2 object's behavior. + * + * XAudio2Processor - An XAUDIO2_PROCESSOR value that specifies the + * hardware threads (Xbox) or processors (Windows) that XAudio2 + * will use. Note that XAudio2 supports concurrent processing on + * multiple threads, using any combination of XAUDIO2_PROCESSOR + * flags. The values are platform-specific; platform-independent + * code can use XAUDIO2_DEFAULT_PROCESSOR to use the default on + * each platform. + * + **************************************************************************/ + +#ifdef __cplusplus__ + +#if (defined XAUDIO2_EXPORT) + /* We're building xaudio2.dll */ +#define XAUDIO2_STDAPI extern "C" __declspec(dllexport) HRESULT __stdcall +#else + /* We're an xaudio2 client */ +#define XAUDIO2_STDAPI extern "C" __declspec(dllimport) HRESULT __stdcall +#endif + +#else + + /* Modified for C support */ + +#if (defined XAUDIO2_EXPORT) + /* We're building xaudio2.dll */ +#define XAUDIO2_STDAPI __declspec(dllexport) HRESULT __stdcall +#else + /* We're an xaudio2 client */ +#define XAUDIO2_STDAPI __declspec(dllimport) HRESULT __stdcall +#endif + +#endif + +#if (NTDDI_VERSION >= NTDDI_WIN10_RS5) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +XAUDIO2_STDAPI XAudio2CreateWithVersionInfo(_Outptr_ IXAudio2** ppXAudio2, + UINT32 Flags X2DEFAULT(0), + XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR), + DWORD ntddiVersion X2DEFAULT(NTDDI_VERSION)); + +static INLINE HRESULT XAudio2Create(_Outptr_ IXAudio2** ppXAudio2, + UINT32 Flags X2DEFAULT(0), + XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)) +{ + /* When compiled for RS5 or later, try to invoke XAudio2CreateWithVersionInfo. + * Need to use LoadLibrary in case the app is running on an older OS. */ + typedef HRESULT(__stdcall *XAudio2CreateWithVersionInfoFunc)(_Outptr_ IXAudio2**, UINT32, XAUDIO2_PROCESSOR, DWORD); + typedef HRESULT(__stdcall *XAudio2CreateInfoFunc)(_Outptr_ IXAudio2**, UINT32, XAUDIO2_PROCESSOR); + + static HMODULE s_dllInstance = NULL; + static XAudio2CreateWithVersionInfoFunc s_pfnAudio2CreateWithVersion = NULL; + static XAudio2CreateInfoFunc s_pfnAudio2Create = NULL; + + if (s_dllInstance == NULL) + { + s_dllInstance = LoadLibraryEx(XAUDIO2_DLL, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (s_dllInstance == NULL) + return HRESULT_FROM_WIN32(GetLastError()); + + s_pfnAudio2CreateWithVersion = (XAudio2CreateWithVersionInfoFunc)(void*)GetProcAddress(s_dllInstance, "XAudio2CreateWithVersionInfo"); + if (s_pfnAudio2CreateWithVersion == NULL) + { + s_pfnAudio2Create = (XAudio2CreateInfoFunc)(void*)GetProcAddress(s_dllInstance, "XAudio2Create"); + if (s_pfnAudio2Create == NULL) + return HRESULT_FROM_WIN32(GetLastError()); + } + } + + if (s_pfnAudio2CreateWithVersion != NULL) + return (*s_pfnAudio2CreateWithVersion)(ppXAudio2, Flags, XAudio2Processor, NTDDI_VERSION); + return (*s_pfnAudio2Create)(ppXAudio2, Flags, XAudio2Processor); +} +#else +/* RS4 or older, or not a desktop app */ +XAUDIO2_STDAPI XAudio2Create(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0), + XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)); +#endif + +/* Undo the #pragma pack(push, 1) directive at the top of this file */ +#pragma pack(pop) + +#endif /* #ifndef GUID_DEFS_ONLY */ + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_TV_APP | WINAPI_PARTITION_TV_TITLE) */ +#pragma endregion + #endif /* #ifndef __XAUDIO2_INCLUDED__ */ diff --git a/cheevos/cheevos.h b/cheevos/cheevos.h index ec25ae0019..c65c2afbc9 100644 --- a/cheevos/cheevos.h +++ b/cheevos/cheevos.h @@ -1,171 +1,171 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2018 - Andre Leiradella - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __RARCH_CHEEVOS_OLD_H -#define __RARCH_CHEEVOS_OLD_H - -#ifdef HAVE_NEW_CHEEVOS -#include "../cheevos-new/cheevos.h" -#else - -#include -#include - -#include - -#include - -RETRO_BEGIN_DECLS - -/***************************************************************************** -Setup - mainly for debugging -*****************************************************************************/ - -/* Define this macro to get extra-verbose log for cheevos. */ -#undef CHEEVOS_VERBOSE - -/***************************************************************************** -End of setup -*****************************************************************************/ - -#define CHEEVOS_TAG "[CHEEVOS]: " - -#ifdef CHEEVOS_VERBOSE - -#define CHEEVOS_LOG RARCH_LOG -#define CHEEVOS_ERR RARCH_ERR - -#else - -void cheevos_log(const char *fmt, ...); - -#define CHEEVOS_LOG cheevos_log -#define CHEEVOS_ERR cheevos_log - -#endif - -typedef struct cheevos_ctx_desc -{ - unsigned idx; - char *s; - size_t len; -} cheevos_ctx_desc_t; - -typedef enum -{ - CHEEVOS_CONSOLE_NONE = 0, - /* Don't change those, the values match the console IDs - * at retroachievements.org. */ - CHEEVOS_CONSOLE_MEGA_DRIVE = 1, - CHEEVOS_CONSOLE_NINTENDO_64 = 2, - CHEEVOS_CONSOLE_SUPER_NINTENDO = 3, - CHEEVOS_CONSOLE_GAMEBOY = 4, - CHEEVOS_CONSOLE_GAMEBOY_ADVANCE = 5, - CHEEVOS_CONSOLE_GAMEBOY_COLOR = 6, - CHEEVOS_CONSOLE_NINTENDO = 7, - CHEEVOS_CONSOLE_PC_ENGINE = 8, - CHEEVOS_CONSOLE_SEGA_CD = 9, - CHEEVOS_CONSOLE_SEGA_32X = 10, - CHEEVOS_CONSOLE_MASTER_SYSTEM = 11, - CHEEVOS_CONSOLE_PLAYSTATION = 12, - CHEEVOS_CONSOLE_ATARI_LYNX = 13, - CHEEVOS_CONSOLE_NEOGEO_POCKET = 14, - CHEEVOS_CONSOLE_GAME_GEAR = 15, - CHEEVOS_CONSOLE_GAMECUBE = 16, - CHEEVOS_CONSOLE_ATARI_JAGUAR = 17, - CHEEVOS_CONSOLE_NINTENDO_DS = 18, - CHEEVOS_CONSOLE_WII = 19, - CHEEVOS_CONSOLE_WII_U = 20, - CHEEVOS_CONSOLE_PLAYSTATION_2 = 21, - CHEEVOS_CONSOLE_XBOX = 22, - CHEEVOS_CONSOLE_SKYNET = 23, - CHEEVOS_CONSOLE_XBOX_ONE = 24, - CHEEVOS_CONSOLE_ATARI_2600 = 25, - CHEEVOS_CONSOLE_MS_DOS = 26, - CHEEVOS_CONSOLE_ARCADE = 27, - CHEEVOS_CONSOLE_VIRTUAL_BOY = 28, - CHEEVOS_CONSOLE_MSX = 29, - CHEEVOS_CONSOLE_COMMODORE_64 = 30, - CHEEVOS_CONSOLE_ZX81 = 31, - CHEEVOS_CONSOLE_ATARI_7800 = 51 -} cheevos_console_t; - -enum -{ - CHEEVOS_DIRTY_TITLE = 1 << 0, - CHEEVOS_DIRTY_DESC = 1 << 1, - CHEEVOS_DIRTY_POINTS = 1 << 2, - CHEEVOS_DIRTY_AUTHOR = 1 << 3, - CHEEVOS_DIRTY_ID = 1 << 4, - CHEEVOS_DIRTY_BADGE = 1 << 5, - CHEEVOS_DIRTY_CONDITIONS = 1 << 6, - CHEEVOS_DIRTY_VOTES = 1 << 7, - CHEEVOS_DIRTY_DESCRIPTION = 1 << 8, - - CHEEVOS_DIRTY_ALL = (1 << 9) - 1 -}; - -enum -{ - CHEEVOS_ACTIVE_SOFTCORE = 1 << 0, - CHEEVOS_ACTIVE_HARDCORE = 1 << 1 -}; - -enum -{ - CHEEVOS_FORMAT_FRAMES = 0, - CHEEVOS_FORMAT_SECS, - CHEEVOS_FORMAT_MILLIS, - CHEEVOS_FORMAT_SCORE, - CHEEVOS_FORMAT_VALUE, - CHEEVOS_FORMAT_OTHER -}; - -bool cheevos_load(const void *data); - -void cheevos_reset_game(void); - -void cheevos_populate_menu(void *data); - -bool cheevos_get_description(cheevos_ctx_desc_t *desc); - -bool cheevos_apply_cheats(bool *data_bool); - -bool cheevos_unload(void); - -bool cheevos_toggle_hardcore_mode(void); - -void cheevos_test(void); - -bool cheevos_set_cheats(void); - -void cheevos_set_support_cheevos(bool state); - -bool cheevos_get_support_cheevos(void); - -cheevos_console_t cheevos_get_console(void); - -extern bool cheevos_loaded; -extern bool cheevos_hardcore_active; -extern bool cheevos_hardcore_paused; -extern bool cheevos_state_loaded_flag; -extern int cheats_are_enabled; -extern int cheats_were_enabled; - -RETRO_END_DECLS - -#endif - -#endif /* __RARCH_CHEEVOS_H */ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2018 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __RARCH_CHEEVOS_OLD_H +#define __RARCH_CHEEVOS_OLD_H + +#ifdef HAVE_NEW_CHEEVOS +#include "../cheevos-new/cheevos.h" +#else + +#include +#include + +#include + +#include + +RETRO_BEGIN_DECLS + +/***************************************************************************** +Setup - mainly for debugging +*****************************************************************************/ + +/* Define this macro to get extra-verbose log for cheevos. */ +#undef CHEEVOS_VERBOSE + +/***************************************************************************** +End of setup +*****************************************************************************/ + +#define CHEEVOS_TAG "[CHEEVOS]: " + +#ifdef CHEEVOS_VERBOSE + +#define CHEEVOS_LOG RARCH_LOG +#define CHEEVOS_ERR RARCH_ERR + +#else + +void cheevos_log(const char *fmt, ...); + +#define CHEEVOS_LOG cheevos_log +#define CHEEVOS_ERR cheevos_log + +#endif + +typedef struct cheevos_ctx_desc +{ + unsigned idx; + char *s; + size_t len; +} cheevos_ctx_desc_t; + +typedef enum +{ + CHEEVOS_CONSOLE_NONE = 0, + /* Don't change those, the values match the console IDs + * at retroachievements.org. */ + CHEEVOS_CONSOLE_MEGA_DRIVE = 1, + CHEEVOS_CONSOLE_NINTENDO_64 = 2, + CHEEVOS_CONSOLE_SUPER_NINTENDO = 3, + CHEEVOS_CONSOLE_GAMEBOY = 4, + CHEEVOS_CONSOLE_GAMEBOY_ADVANCE = 5, + CHEEVOS_CONSOLE_GAMEBOY_COLOR = 6, + CHEEVOS_CONSOLE_NINTENDO = 7, + CHEEVOS_CONSOLE_PC_ENGINE = 8, + CHEEVOS_CONSOLE_SEGA_CD = 9, + CHEEVOS_CONSOLE_SEGA_32X = 10, + CHEEVOS_CONSOLE_MASTER_SYSTEM = 11, + CHEEVOS_CONSOLE_PLAYSTATION = 12, + CHEEVOS_CONSOLE_ATARI_LYNX = 13, + CHEEVOS_CONSOLE_NEOGEO_POCKET = 14, + CHEEVOS_CONSOLE_GAME_GEAR = 15, + CHEEVOS_CONSOLE_GAMECUBE = 16, + CHEEVOS_CONSOLE_ATARI_JAGUAR = 17, + CHEEVOS_CONSOLE_NINTENDO_DS = 18, + CHEEVOS_CONSOLE_WII = 19, + CHEEVOS_CONSOLE_WII_U = 20, + CHEEVOS_CONSOLE_PLAYSTATION_2 = 21, + CHEEVOS_CONSOLE_XBOX = 22, + CHEEVOS_CONSOLE_SKYNET = 23, + CHEEVOS_CONSOLE_XBOX_ONE = 24, + CHEEVOS_CONSOLE_ATARI_2600 = 25, + CHEEVOS_CONSOLE_MS_DOS = 26, + CHEEVOS_CONSOLE_ARCADE = 27, + CHEEVOS_CONSOLE_VIRTUAL_BOY = 28, + CHEEVOS_CONSOLE_MSX = 29, + CHEEVOS_CONSOLE_COMMODORE_64 = 30, + CHEEVOS_CONSOLE_ZX81 = 31, + CHEEVOS_CONSOLE_ATARI_7800 = 51 +} cheevos_console_t; + +enum +{ + CHEEVOS_DIRTY_TITLE = 1 << 0, + CHEEVOS_DIRTY_DESC = 1 << 1, + CHEEVOS_DIRTY_POINTS = 1 << 2, + CHEEVOS_DIRTY_AUTHOR = 1 << 3, + CHEEVOS_DIRTY_ID = 1 << 4, + CHEEVOS_DIRTY_BADGE = 1 << 5, + CHEEVOS_DIRTY_CONDITIONS = 1 << 6, + CHEEVOS_DIRTY_VOTES = 1 << 7, + CHEEVOS_DIRTY_DESCRIPTION = 1 << 8, + + CHEEVOS_DIRTY_ALL = (1 << 9) - 1 +}; + +enum +{ + CHEEVOS_ACTIVE_SOFTCORE = 1 << 0, + CHEEVOS_ACTIVE_HARDCORE = 1 << 1 +}; + +enum +{ + CHEEVOS_FORMAT_FRAMES = 0, + CHEEVOS_FORMAT_SECS, + CHEEVOS_FORMAT_MILLIS, + CHEEVOS_FORMAT_SCORE, + CHEEVOS_FORMAT_VALUE, + CHEEVOS_FORMAT_OTHER +}; + +bool cheevos_load(const void *data); + +void cheevos_reset_game(void); + +void cheevos_populate_menu(void *data); + +bool cheevos_get_description(cheevos_ctx_desc_t *desc); + +bool cheevos_apply_cheats(bool *data_bool); + +bool cheevos_unload(void); + +bool cheevos_toggle_hardcore_mode(void); + +void cheevos_test(void); + +bool cheevos_set_cheats(void); + +void cheevos_set_support_cheevos(bool state); + +bool cheevos_get_support_cheevos(void); + +cheevos_console_t cheevos_get_console(void); + +extern bool cheevos_loaded; +extern bool cheevos_hardcore_active; +extern bool cheevos_hardcore_paused; +extern bool cheevos_state_loaded_flag; +extern int cheats_are_enabled; +extern int cheats_were_enabled; + +RETRO_END_DECLS + +#endif + +#endif /* __RARCH_CHEEVOS_H */ diff --git a/cheevos/cond.c b/cheevos/cond.c index 850e1238e6..9f665900c9 100644 --- a/cheevos/cond.c +++ b/cheevos/cond.c @@ -1,189 +1,189 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2017 - Andre Leiradella - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include "cond.h" -#include "var.h" - -#include "../retroarch.h" -#include "../verbosity.h" - -/***************************************************************************** -Parsing -*****************************************************************************/ - -static cheevos_cond_op_t cheevos_cond_parse_operator(const char** memaddr) -{ - const char *str = *memaddr; - cheevos_cond_op_t op; - - if (*str == '=' && str[1] == '=') - { - op = CHEEVOS_COND_OP_EQUALS; - str += 2; - } - else if (*str == '=') - { - op = CHEEVOS_COND_OP_EQUALS; - str++; - } - else if (*str == '!' && str[1] == '=') - { - op = CHEEVOS_COND_OP_NOT_EQUAL_TO; - str += 2; - } - else if (*str == '<' && str[1] == '=') - { - op = CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL; - str += 2; - } - else if (*str == '<') - { - op = CHEEVOS_COND_OP_LESS_THAN; - str++; - } - else if (*str == '>' && str[1] == '=') - { - op = CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL; - str += 2; - } - else if (*str == '>') - { - op = CHEEVOS_COND_OP_GREATER_THAN; - str++; - } - else - { - CHEEVOS_ERR(CHEEVOS_TAG "unknown operator %c\n.", *str); - op = CHEEVOS_COND_OP_EQUALS; - } - - *memaddr = str; - return op; -} - -void cheevos_cond_parse(cheevos_cond_t* cond, const char** memaddr) -{ - const char* str = *memaddr; - cond->type = CHEEVOS_COND_TYPE_STANDARD; - - if (*str != 0 && str[1] == ':') - { - int skip = 2; - - switch (*str) - { - case 'R': - cond->type = CHEEVOS_COND_TYPE_RESET_IF; - break; - case 'P': - cond->type = CHEEVOS_COND_TYPE_PAUSE_IF; - break; - case 'A': - cond->type = CHEEVOS_COND_TYPE_ADD_SOURCE; - break; - case 'B': - cond->type = CHEEVOS_COND_TYPE_SUB_SOURCE; - break; - case 'C': - cond->type = CHEEVOS_COND_TYPE_ADD_HITS; - break; - default: - skip = 0; - break; - } - - str += skip; - } - - cheevos_var_parse(&cond->source, &str); - cond->op = cheevos_cond_parse_operator(&str); - cheevos_var_parse(&cond->target, &str); - cond->curr_hits = 0; - - if (*str == '(' || *str == '.') - { - char* end; - cond->req_hits = (unsigned)strtol(str + 1, &end, 10); - str = end + (*end == ')' || *end == '.'); - } - else - cond->req_hits = 0; - - *memaddr = str; -} - -unsigned cheevos_cond_count_in_set(const char* memaddr, unsigned which) -{ - cheevos_cond_t dummy; - unsigned index = 0; - unsigned count = 0; - - for (;;) - { - for (;;) - { - cheevos_cond_parse(&dummy, &memaddr); - - if (index == which) - count++; - - if (*memaddr != '_') - break; - - memaddr++; - } - - index++; - - if (*memaddr != 'S') - break; - - memaddr++; - } - - return count; -} - -void cheevos_cond_parse_in_set(cheevos_cond_t* cond, const char* memaddr, unsigned which) -{ - cheevos_cond_t dummy; - unsigned index = 0; - - for (;;) - { - for (;;) - { - if (index == which) - { - cheevos_cond_parse(cond, &memaddr); - cond++; - } - else - cheevos_cond_parse(&dummy, &memaddr); - - if (*memaddr != '_') - break; - - memaddr++; - } - - index++; - - if (*memaddr != 'S') - break; - - memaddr++; - } -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2017 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "cond.h" +#include "var.h" + +#include "../retroarch.h" +#include "../verbosity.h" + +/***************************************************************************** +Parsing +*****************************************************************************/ + +static cheevos_cond_op_t cheevos_cond_parse_operator(const char** memaddr) +{ + const char *str = *memaddr; + cheevos_cond_op_t op; + + if (*str == '=' && str[1] == '=') + { + op = CHEEVOS_COND_OP_EQUALS; + str += 2; + } + else if (*str == '=') + { + op = CHEEVOS_COND_OP_EQUALS; + str++; + } + else if (*str == '!' && str[1] == '=') + { + op = CHEEVOS_COND_OP_NOT_EQUAL_TO; + str += 2; + } + else if (*str == '<' && str[1] == '=') + { + op = CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL; + str += 2; + } + else if (*str == '<') + { + op = CHEEVOS_COND_OP_LESS_THAN; + str++; + } + else if (*str == '>' && str[1] == '=') + { + op = CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL; + str += 2; + } + else if (*str == '>') + { + op = CHEEVOS_COND_OP_GREATER_THAN; + str++; + } + else + { + CHEEVOS_ERR(CHEEVOS_TAG "unknown operator %c\n.", *str); + op = CHEEVOS_COND_OP_EQUALS; + } + + *memaddr = str; + return op; +} + +void cheevos_cond_parse(cheevos_cond_t* cond, const char** memaddr) +{ + const char* str = *memaddr; + cond->type = CHEEVOS_COND_TYPE_STANDARD; + + if (*str != 0 && str[1] == ':') + { + int skip = 2; + + switch (*str) + { + case 'R': + cond->type = CHEEVOS_COND_TYPE_RESET_IF; + break; + case 'P': + cond->type = CHEEVOS_COND_TYPE_PAUSE_IF; + break; + case 'A': + cond->type = CHEEVOS_COND_TYPE_ADD_SOURCE; + break; + case 'B': + cond->type = CHEEVOS_COND_TYPE_SUB_SOURCE; + break; + case 'C': + cond->type = CHEEVOS_COND_TYPE_ADD_HITS; + break; + default: + skip = 0; + break; + } + + str += skip; + } + + cheevos_var_parse(&cond->source, &str); + cond->op = cheevos_cond_parse_operator(&str); + cheevos_var_parse(&cond->target, &str); + cond->curr_hits = 0; + + if (*str == '(' || *str == '.') + { + char* end; + cond->req_hits = (unsigned)strtol(str + 1, &end, 10); + str = end + (*end == ')' || *end == '.'); + } + else + cond->req_hits = 0; + + *memaddr = str; +} + +unsigned cheevos_cond_count_in_set(const char* memaddr, unsigned which) +{ + cheevos_cond_t dummy; + unsigned index = 0; + unsigned count = 0; + + for (;;) + { + for (;;) + { + cheevos_cond_parse(&dummy, &memaddr); + + if (index == which) + count++; + + if (*memaddr != '_') + break; + + memaddr++; + } + + index++; + + if (*memaddr != 'S') + break; + + memaddr++; + } + + return count; +} + +void cheevos_cond_parse_in_set(cheevos_cond_t* cond, const char* memaddr, unsigned which) +{ + cheevos_cond_t dummy; + unsigned index = 0; + + for (;;) + { + for (;;) + { + if (index == which) + { + cheevos_cond_parse(cond, &memaddr); + cond++; + } + else + cheevos_cond_parse(&dummy, &memaddr); + + if (*memaddr != '_') + break; + + memaddr++; + } + + index++; + + if (*memaddr != 'S') + break; + + memaddr++; + } +} diff --git a/cheevos/cond.h b/cheevos/cond.h index e42d12655d..ee7cb668a1 100644 --- a/cheevos/cond.h +++ b/cheevos/cond.h @@ -1,63 +1,63 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2017 - Andre Leiradella - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __RARCH_CHEEVOS_COND_H -#define __RARCH_CHEEVOS_COND_H - -#include "var.h" - -#include - -RETRO_BEGIN_DECLS - -typedef enum -{ - CHEEVOS_COND_TYPE_STANDARD, - CHEEVOS_COND_TYPE_PAUSE_IF, - CHEEVOS_COND_TYPE_RESET_IF, - CHEEVOS_COND_TYPE_ADD_SOURCE, - CHEEVOS_COND_TYPE_SUB_SOURCE, - CHEEVOS_COND_TYPE_ADD_HITS -} cheevos_cond_type_t; - -typedef enum -{ - CHEEVOS_COND_OP_EQUALS, - CHEEVOS_COND_OP_LESS_THAN, - CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL, - CHEEVOS_COND_OP_GREATER_THAN, - CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL, - CHEEVOS_COND_OP_NOT_EQUAL_TO -} cheevos_cond_op_t; - -typedef struct -{ - cheevos_cond_type_t type; - unsigned req_hits; - unsigned curr_hits; - char pause; - - cheevos_var_t source; - cheevos_cond_op_t op; - cheevos_var_t target; -} cheevos_cond_t; - -void cheevos_cond_parse(cheevos_cond_t* cond, const char** memaddr); -unsigned cheevos_cond_count_in_set(const char* memaddr, unsigned which); -void cheevos_cond_parse_in_set(cheevos_cond_t* cond, const char* memaddr, unsigned which); - -RETRO_END_DECLS - -#endif /* __RARCH_CHEEVOS_COND_H */ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2017 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __RARCH_CHEEVOS_COND_H +#define __RARCH_CHEEVOS_COND_H + +#include "var.h" + +#include + +RETRO_BEGIN_DECLS + +typedef enum +{ + CHEEVOS_COND_TYPE_STANDARD, + CHEEVOS_COND_TYPE_PAUSE_IF, + CHEEVOS_COND_TYPE_RESET_IF, + CHEEVOS_COND_TYPE_ADD_SOURCE, + CHEEVOS_COND_TYPE_SUB_SOURCE, + CHEEVOS_COND_TYPE_ADD_HITS +} cheevos_cond_type_t; + +typedef enum +{ + CHEEVOS_COND_OP_EQUALS, + CHEEVOS_COND_OP_LESS_THAN, + CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL, + CHEEVOS_COND_OP_GREATER_THAN, + CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL, + CHEEVOS_COND_OP_NOT_EQUAL_TO +} cheevos_cond_op_t; + +typedef struct +{ + cheevos_cond_type_t type; + unsigned req_hits; + unsigned curr_hits; + char pause; + + cheevos_var_t source; + cheevos_cond_op_t op; + cheevos_var_t target; +} cheevos_cond_t; + +void cheevos_cond_parse(cheevos_cond_t* cond, const char** memaddr); +unsigned cheevos_cond_count_in_set(const char* memaddr, unsigned which); +void cheevos_cond_parse_in_set(cheevos_cond_t* cond, const char* memaddr, unsigned which); + +RETRO_END_DECLS + +#endif /* __RARCH_CHEEVOS_COND_H */ diff --git a/cheevos/coro.h b/cheevos/coro.h index c1a6881e24..e30616b5f2 100644 --- a/cheevos/coro.h +++ b/cheevos/coro.h @@ -1,75 +1,75 @@ -#ifndef CORO_H -#define CORO_H - -/* -Released under the CC0: https://creativecommons.org/publicdomain/zero/1.0/ -*/ - -/* Use at the beginning of the coroutine, you must have declared a variable coro_t* coro */ -#define CORO_ENTER() \ - { \ - CORO_again: ; \ - switch ( coro->step ) { \ - case CORO_BEGIN: ; - -/* Use to define labels which are targets to GOTO and GOSUB */ -#define CORO_SUB( x ) \ - case x: ; - -/* Use at the end of the coroutine */ -#define CORO_LEAVE() \ - } } \ - do { return 0; } while ( 0 ) - -/* Go to the x label */ -#define CORO_GOTO( x ) \ - do { \ - coro->step = ( x ); \ - goto CORO_again; \ - } while ( 0 ) - -/* Go to a subroutine, execution continues until the subroutine returns via RET */ -#define CORO_GOSUB( x ) \ - do { \ - coro->stack[ coro->sp++ ] = __LINE__; \ - coro->step = ( x ); \ - goto CORO_again; \ - case __LINE__: ; \ - } while ( 0 ) - -/* Returns from a subroutine */ -#define CORO_RET() \ - do { \ - coro->step = coro->stack[ --coro->sp ]; \ - goto CORO_again; \ - } while ( 0 ) - -/* Yields to the caller, execution continues from this point when the coroutine is resumed */ -#define CORO_YIELD() \ - do { \ - coro->step = __LINE__; \ - return 1; \ - case __LINE__: ; \ - } while ( 0 ) - -/* The coroutine entry point, never use 0 as a label */ -#define CORO_BEGIN 0 - -/* Sets up the coroutine */ -#define CORO_SETUP() \ - do { \ - coro->step = CORO_BEGIN; \ - coro->sp = 0; \ - } while ( 0 ) - -#define CORO_STOP() \ - do { \ - return 0; \ - } while ( 0 ) - -/* Add this macro to your coro_t structure containing the variables for the coroutine */ -#define CORO_FIELDS \ - int step, sp; \ - int stack[ 8 ]; - -#endif /* CORO_H */ +#ifndef CORO_H +#define CORO_H + +/* +Released under the CC0: https://creativecommons.org/publicdomain/zero/1.0/ +*/ + +/* Use at the beginning of the coroutine, you must have declared a variable coro_t* coro */ +#define CORO_ENTER() \ + { \ + CORO_again: ; \ + switch ( coro->step ) { \ + case CORO_BEGIN: ; + +/* Use to define labels which are targets to GOTO and GOSUB */ +#define CORO_SUB( x ) \ + case x: ; + +/* Use at the end of the coroutine */ +#define CORO_LEAVE() \ + } } \ + do { return 0; } while ( 0 ) + +/* Go to the x label */ +#define CORO_GOTO( x ) \ + do { \ + coro->step = ( x ); \ + goto CORO_again; \ + } while ( 0 ) + +/* Go to a subroutine, execution continues until the subroutine returns via RET */ +#define CORO_GOSUB( x ) \ + do { \ + coro->stack[ coro->sp++ ] = __LINE__; \ + coro->step = ( x ); \ + goto CORO_again; \ + case __LINE__: ; \ + } while ( 0 ) + +/* Returns from a subroutine */ +#define CORO_RET() \ + do { \ + coro->step = coro->stack[ --coro->sp ]; \ + goto CORO_again; \ + } while ( 0 ) + +/* Yields to the caller, execution continues from this point when the coroutine is resumed */ +#define CORO_YIELD() \ + do { \ + coro->step = __LINE__; \ + return 1; \ + case __LINE__: ; \ + } while ( 0 ) + +/* The coroutine entry point, never use 0 as a label */ +#define CORO_BEGIN 0 + +/* Sets up the coroutine */ +#define CORO_SETUP() \ + do { \ + coro->step = CORO_BEGIN; \ + coro->sp = 0; \ + } while ( 0 ) + +#define CORO_STOP() \ + do { \ + return 0; \ + } while ( 0 ) + +/* Add this macro to your coro_t structure containing the variables for the coroutine */ +#define CORO_FIELDS \ + int step, sp; \ + int stack[ 8 ]; + +#endif /* CORO_H */ diff --git a/cheevos/var.c b/cheevos/var.c index ba7d17ec28..18c8955dac 100644 --- a/cheevos/var.c +++ b/cheevos/var.c @@ -1,415 +1,415 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2017 - Andre Leiradella - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include - -#include - -#include "var.h" - -#include "../retroarch.h" -#include "../core.h" -#include "../verbosity.h" - -/***************************************************************************** -Parsing -*****************************************************************************/ - -static cheevos_var_size_t cheevos_var_parse_prefix(const char** memaddr) -{ - /* Careful not to use ABCDEF here, this denotes part of an actual variable! */ - const char* str = *memaddr; - cheevos_var_size_t size; - - switch (toupper((unsigned char)*str++)) - { - case 'M': - size = CHEEVOS_VAR_SIZE_BIT_0; - break; - case 'N': - size = CHEEVOS_VAR_SIZE_BIT_1; - break; - case 'O': - size = CHEEVOS_VAR_SIZE_BIT_2; - break; - case 'P': - size = CHEEVOS_VAR_SIZE_BIT_3; - break; - case 'Q': - size = CHEEVOS_VAR_SIZE_BIT_4; - break; - case 'R': - size = CHEEVOS_VAR_SIZE_BIT_5; - break; - case 'S': - size = CHEEVOS_VAR_SIZE_BIT_6; - break; - case 'T': - size = CHEEVOS_VAR_SIZE_BIT_7; - break; - case 'L': - size = CHEEVOS_VAR_SIZE_NIBBLE_LOWER; - break; - case 'U': - size = CHEEVOS_VAR_SIZE_NIBBLE_UPPER; - break; - case 'H': - size = CHEEVOS_VAR_SIZE_EIGHT_BITS; - break; - case 'X': - size = CHEEVOS_VAR_SIZE_THIRTYTWO_BITS; - break; - default: - str--; - /* fall through */ - case ' ': - size = CHEEVOS_VAR_SIZE_SIXTEEN_BITS; - break; - } - - *memaddr = str; - return size; -} - -static size_t cheevos_var_reduce(size_t addr, size_t mask) -{ - while (mask) - { - size_t tmp = (mask - 1) & ~mask; - addr = (addr & tmp) | ((addr >> 1) & ~tmp); - mask = (mask & (mask - 1)) >> 1; - } - - return addr; -} - -static size_t cheevos_var_highest_bit(size_t n) -{ - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n |= n >> 16; - - return n ^ (n >> 1); -} - -void cheevos_var_parse(cheevos_var_t* var, const char** memaddr) -{ - char *end = NULL; - const char *str = *memaddr; - unsigned base = 16; - - var->is_bcd = false; - - if (toupper((unsigned char)*str) == 'D' && str[1] == '0' && toupper((unsigned char)str[2]) == 'X') - { - /* d0x + 4 hex digits */ - str += 3; - var->type = CHEEVOS_VAR_TYPE_DELTA_MEM; - } - else if (toupper((unsigned char)*str) == 'B' && str[1] == '0' && toupper((unsigned char)str[2]) == 'X') - { - /* b0x (binary-coded decimal) */ - str += 3; - var->is_bcd = true; - var->type = CHEEVOS_VAR_TYPE_ADDRESS; - } - else if (*str == '0' && toupper((unsigned char)str[1]) == 'X') - { - /* 0x + 4 hex digits */ - str += 2; - var->type = CHEEVOS_VAR_TYPE_ADDRESS; - } - else - { - var->type = CHEEVOS_VAR_TYPE_VALUE_COMP; - - if (toupper((unsigned char)*str) == 'H') - str++; - else - { - if (toupper((unsigned char)*str) == 'V') - str++; - - base = 10; - } - } - - if (var->type != CHEEVOS_VAR_TYPE_VALUE_COMP) - { - var->size = cheevos_var_parse_prefix(&str); - } - - var->value = (unsigned)strtol(str, &end, base); - *memaddr = end; -} - -void cheevos_var_patch_addr(cheevos_var_t* var, cheevos_console_t console) -{ - rarch_system_info_t *system = runloop_get_system_info(); - - var->bank_id = -1; - - if (console == CHEEVOS_CONSOLE_NINTENDO) - { - if (var->value >= 0x0800 && var->value < 0x2000) - { - CHEEVOS_LOG(CHEEVOS_TAG "NES memory address in mirrorred RAM %X, adjusted to %X\n", var->value, var->value & 0x07ff); - var->value &= 0x07ff; - } - } - else if (console == CHEEVOS_CONSOLE_GAMEBOY_COLOR) - { - if (var->value >= 0xe000 && var->value <= 0xfdff) - { - CHEEVOS_LOG(CHEEVOS_TAG "GBC memory address in echo RAM %X, adjusted to %X\n", var->value, var->value - 0x2000); - var->value -= 0x2000; - } - } - - if (system->mmaps.num_descriptors != 0) - { - const rarch_memory_descriptor_t *desc = NULL; - const rarch_memory_descriptor_t *end = NULL; - - /* Patch the address to correctly map it to the mmaps */ - if (console == CHEEVOS_CONSOLE_GAMEBOY_ADVANCE) - { - if (var->value < 0x8000) /* Internal RAM */ - { - CHEEVOS_LOG(CHEEVOS_TAG "GBA memory address %X adjusted to %X\n", var->value, var->value + 0x3000000); - var->value += 0x3000000; - } - else /* Work RAM */ - { - CHEEVOS_LOG(CHEEVOS_TAG "GBA memory address %X adjusted to %X\n", var->value, var->value + 0x2000000 - 0x8000); - var->value += 0x2000000 - 0x8000; - } - } - else if (console == CHEEVOS_CONSOLE_PC_ENGINE) - { - CHEEVOS_LOG(CHEEVOS_TAG "PCE memory address %X adjusted to %X\n", var->value, var->value + 0x1f0000); - var->value += 0x1f0000; - } - else if (console == CHEEVOS_CONSOLE_SUPER_NINTENDO) - { - if (var->value < 0x020000) /* Work RAM */ - { - CHEEVOS_LOG(CHEEVOS_TAG "SNES memory address %X adjusted to %X\n", var->value, var->value + 0x7e0000); - var->value += 0x7e0000; - } - else /* Save RAM */ - { - CHEEVOS_LOG(CHEEVOS_TAG "SNES memory address %X adjusted to %X\n", var->value, var->value + 0x006000 - 0x020000); - var->value += 0x006000 - 0x020000; - } - } - - desc = system->mmaps.descriptors; - end = desc + system->mmaps.num_descriptors; - - for (; desc < end; desc++) - { - if (((desc->core.start ^ var->value) & desc->core.select) == 0) - { - unsigned addr = var->value; - var->bank_id = (int)(desc - system->mmaps.descriptors); - var->value = (unsigned)cheevos_var_reduce( - (addr - desc->core.start) & desc->disconnect_mask, - desc->core.disconnect); - - if (var->value >= desc->core.len) - var->value -= cheevos_var_highest_bit(var->value); - - var->value += desc->core.offset; - - CHEEVOS_LOG(CHEEVOS_TAG "address %X set to descriptor %d at offset %X\n", addr, var->bank_id + 1, var->value); - break; - } - } - } - else - { - unsigned i; - - for (i = 0; i < 4; i++) - { - retro_ctx_memory_info_t meminfo; - - switch (i) - { - case 0: - meminfo.id = RETRO_MEMORY_SYSTEM_RAM; - break; - case 1: - meminfo.id = RETRO_MEMORY_SAVE_RAM; - break; - case 2: - meminfo.id = RETRO_MEMORY_VIDEO_RAM; - break; - case 3: - meminfo.id = RETRO_MEMORY_RTC; - break; - } - - core_get_memory(&meminfo); - - if (var->value < meminfo.size) - { - var->bank_id = i; - break; - } - - /* HACK subtract the correct amount of bytes to reach the save RAM */ - if (i == 0 && console == CHEEVOS_CONSOLE_NINTENDO) - var->value -= 0x6000; - else - var->value -= meminfo.size; - } - } -} - -/***************************************************************************** -Testing -*****************************************************************************/ - -uint8_t* cheevos_var_get_memory(const cheevos_var_t* var) -{ - uint8_t* memory = NULL; - - if (var->bank_id >= 0) - { - rarch_system_info_t* system = runloop_get_system_info(); - - if (system->mmaps.num_descriptors != 0) - memory = (uint8_t*)system->mmaps.descriptors[var->bank_id].core.ptr; - else - { - retro_ctx_memory_info_t meminfo = {NULL, 0, 0}; - - switch (var->bank_id) - { - case 0: - meminfo.id = RETRO_MEMORY_SYSTEM_RAM; - break; - case 1: - meminfo.id = RETRO_MEMORY_SAVE_RAM; - break; - case 2: - meminfo.id = RETRO_MEMORY_VIDEO_RAM; - break; - case 3: - meminfo.id = RETRO_MEMORY_RTC; - break; - default: - CHEEVOS_ERR(CHEEVOS_TAG "invalid bank id: %s\n", var->bank_id); - break; - } - - core_get_memory(&meminfo); - memory = (uint8_t*)meminfo.data; - } - - if (memory) - memory += var->value; - } - - return memory; -} - -unsigned cheevos_var_get_value(cheevos_var_t* var) -{ - const uint8_t* memory = NULL; - unsigned value = 0; - - switch (var->type) - { - case CHEEVOS_VAR_TYPE_VALUE_COMP: - value = var->value; - break; - - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - memory = cheevos_var_get_memory(var); - - if (memory) - { - value = memory[0]; - - switch (var->size) - { - case CHEEVOS_VAR_SIZE_BIT_0: - value &= 1; - break; - case CHEEVOS_VAR_SIZE_BIT_1: - value = (value >> 1) & 1; - break; - case CHEEVOS_VAR_SIZE_BIT_2: - value = (value >> 2) & 1; - break; - case CHEEVOS_VAR_SIZE_BIT_3: - value = (value >> 3) & 1; - break; - case CHEEVOS_VAR_SIZE_BIT_4: - value = (value >> 4) & 1; - break; - case CHEEVOS_VAR_SIZE_BIT_5: - value = (value >> 5) & 1; - break; - case CHEEVOS_VAR_SIZE_BIT_6: - value = (value >> 6) & 1; - break; - case CHEEVOS_VAR_SIZE_BIT_7: - value = (value >> 7) & 1; - break; - case CHEEVOS_VAR_SIZE_NIBBLE_LOWER: - value &= 0x0f; - break; - case CHEEVOS_VAR_SIZE_NIBBLE_UPPER: - value = (value >> 4) & 0x0f; - break; - case CHEEVOS_VAR_SIZE_EIGHT_BITS: - break; - case CHEEVOS_VAR_SIZE_SIXTEEN_BITS: - value |= memory[1] << 8; - break; - case CHEEVOS_VAR_SIZE_THIRTYTWO_BITS: - value |= memory[1] << 8; - value |= memory[2] << 16; - value |= memory[3] << 24; - break; - } - } - - if (var->type == CHEEVOS_VAR_TYPE_DELTA_MEM) - { - unsigned previous = var->previous; - var->previous = value; - value = previous; - } - - break; - - case CHEEVOS_VAR_TYPE_DYNAMIC_VAR: - /* We shouldn't get here... */ - break; - } - - if(var->is_bcd) - return (((value >> 4) & 0xf) * 10) + (value & 0xf); - return value; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2017 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include + +#include + +#include "var.h" + +#include "../retroarch.h" +#include "../core.h" +#include "../verbosity.h" + +/***************************************************************************** +Parsing +*****************************************************************************/ + +static cheevos_var_size_t cheevos_var_parse_prefix(const char** memaddr) +{ + /* Careful not to use ABCDEF here, this denotes part of an actual variable! */ + const char* str = *memaddr; + cheevos_var_size_t size; + + switch (toupper((unsigned char)*str++)) + { + case 'M': + size = CHEEVOS_VAR_SIZE_BIT_0; + break; + case 'N': + size = CHEEVOS_VAR_SIZE_BIT_1; + break; + case 'O': + size = CHEEVOS_VAR_SIZE_BIT_2; + break; + case 'P': + size = CHEEVOS_VAR_SIZE_BIT_3; + break; + case 'Q': + size = CHEEVOS_VAR_SIZE_BIT_4; + break; + case 'R': + size = CHEEVOS_VAR_SIZE_BIT_5; + break; + case 'S': + size = CHEEVOS_VAR_SIZE_BIT_6; + break; + case 'T': + size = CHEEVOS_VAR_SIZE_BIT_7; + break; + case 'L': + size = CHEEVOS_VAR_SIZE_NIBBLE_LOWER; + break; + case 'U': + size = CHEEVOS_VAR_SIZE_NIBBLE_UPPER; + break; + case 'H': + size = CHEEVOS_VAR_SIZE_EIGHT_BITS; + break; + case 'X': + size = CHEEVOS_VAR_SIZE_THIRTYTWO_BITS; + break; + default: + str--; + /* fall through */ + case ' ': + size = CHEEVOS_VAR_SIZE_SIXTEEN_BITS; + break; + } + + *memaddr = str; + return size; +} + +static size_t cheevos_var_reduce(size_t addr, size_t mask) +{ + while (mask) + { + size_t tmp = (mask - 1) & ~mask; + addr = (addr & tmp) | ((addr >> 1) & ~tmp); + mask = (mask & (mask - 1)) >> 1; + } + + return addr; +} + +static size_t cheevos_var_highest_bit(size_t n) +{ + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + + return n ^ (n >> 1); +} + +void cheevos_var_parse(cheevos_var_t* var, const char** memaddr) +{ + char *end = NULL; + const char *str = *memaddr; + unsigned base = 16; + + var->is_bcd = false; + + if (toupper((unsigned char)*str) == 'D' && str[1] == '0' && toupper((unsigned char)str[2]) == 'X') + { + /* d0x + 4 hex digits */ + str += 3; + var->type = CHEEVOS_VAR_TYPE_DELTA_MEM; + } + else if (toupper((unsigned char)*str) == 'B' && str[1] == '0' && toupper((unsigned char)str[2]) == 'X') + { + /* b0x (binary-coded decimal) */ + str += 3; + var->is_bcd = true; + var->type = CHEEVOS_VAR_TYPE_ADDRESS; + } + else if (*str == '0' && toupper((unsigned char)str[1]) == 'X') + { + /* 0x + 4 hex digits */ + str += 2; + var->type = CHEEVOS_VAR_TYPE_ADDRESS; + } + else + { + var->type = CHEEVOS_VAR_TYPE_VALUE_COMP; + + if (toupper((unsigned char)*str) == 'H') + str++; + else + { + if (toupper((unsigned char)*str) == 'V') + str++; + + base = 10; + } + } + + if (var->type != CHEEVOS_VAR_TYPE_VALUE_COMP) + { + var->size = cheevos_var_parse_prefix(&str); + } + + var->value = (unsigned)strtol(str, &end, base); + *memaddr = end; +} + +void cheevos_var_patch_addr(cheevos_var_t* var, cheevos_console_t console) +{ + rarch_system_info_t *system = runloop_get_system_info(); + + var->bank_id = -1; + + if (console == CHEEVOS_CONSOLE_NINTENDO) + { + if (var->value >= 0x0800 && var->value < 0x2000) + { + CHEEVOS_LOG(CHEEVOS_TAG "NES memory address in mirrorred RAM %X, adjusted to %X\n", var->value, var->value & 0x07ff); + var->value &= 0x07ff; + } + } + else if (console == CHEEVOS_CONSOLE_GAMEBOY_COLOR) + { + if (var->value >= 0xe000 && var->value <= 0xfdff) + { + CHEEVOS_LOG(CHEEVOS_TAG "GBC memory address in echo RAM %X, adjusted to %X\n", var->value, var->value - 0x2000); + var->value -= 0x2000; + } + } + + if (system->mmaps.num_descriptors != 0) + { + const rarch_memory_descriptor_t *desc = NULL; + const rarch_memory_descriptor_t *end = NULL; + + /* Patch the address to correctly map it to the mmaps */ + if (console == CHEEVOS_CONSOLE_GAMEBOY_ADVANCE) + { + if (var->value < 0x8000) /* Internal RAM */ + { + CHEEVOS_LOG(CHEEVOS_TAG "GBA memory address %X adjusted to %X\n", var->value, var->value + 0x3000000); + var->value += 0x3000000; + } + else /* Work RAM */ + { + CHEEVOS_LOG(CHEEVOS_TAG "GBA memory address %X adjusted to %X\n", var->value, var->value + 0x2000000 - 0x8000); + var->value += 0x2000000 - 0x8000; + } + } + else if (console == CHEEVOS_CONSOLE_PC_ENGINE) + { + CHEEVOS_LOG(CHEEVOS_TAG "PCE memory address %X adjusted to %X\n", var->value, var->value + 0x1f0000); + var->value += 0x1f0000; + } + else if (console == CHEEVOS_CONSOLE_SUPER_NINTENDO) + { + if (var->value < 0x020000) /* Work RAM */ + { + CHEEVOS_LOG(CHEEVOS_TAG "SNES memory address %X adjusted to %X\n", var->value, var->value + 0x7e0000); + var->value += 0x7e0000; + } + else /* Save RAM */ + { + CHEEVOS_LOG(CHEEVOS_TAG "SNES memory address %X adjusted to %X\n", var->value, var->value + 0x006000 - 0x020000); + var->value += 0x006000 - 0x020000; + } + } + + desc = system->mmaps.descriptors; + end = desc + system->mmaps.num_descriptors; + + for (; desc < end; desc++) + { + if (((desc->core.start ^ var->value) & desc->core.select) == 0) + { + unsigned addr = var->value; + var->bank_id = (int)(desc - system->mmaps.descriptors); + var->value = (unsigned)cheevos_var_reduce( + (addr - desc->core.start) & desc->disconnect_mask, + desc->core.disconnect); + + if (var->value >= desc->core.len) + var->value -= cheevos_var_highest_bit(var->value); + + var->value += desc->core.offset; + + CHEEVOS_LOG(CHEEVOS_TAG "address %X set to descriptor %d at offset %X\n", addr, var->bank_id + 1, var->value); + break; + } + } + } + else + { + unsigned i; + + for (i = 0; i < 4; i++) + { + retro_ctx_memory_info_t meminfo; + + switch (i) + { + case 0: + meminfo.id = RETRO_MEMORY_SYSTEM_RAM; + break; + case 1: + meminfo.id = RETRO_MEMORY_SAVE_RAM; + break; + case 2: + meminfo.id = RETRO_MEMORY_VIDEO_RAM; + break; + case 3: + meminfo.id = RETRO_MEMORY_RTC; + break; + } + + core_get_memory(&meminfo); + + if (var->value < meminfo.size) + { + var->bank_id = i; + break; + } + + /* HACK subtract the correct amount of bytes to reach the save RAM */ + if (i == 0 && console == CHEEVOS_CONSOLE_NINTENDO) + var->value -= 0x6000; + else + var->value -= meminfo.size; + } + } +} + +/***************************************************************************** +Testing +*****************************************************************************/ + +uint8_t* cheevos_var_get_memory(const cheevos_var_t* var) +{ + uint8_t* memory = NULL; + + if (var->bank_id >= 0) + { + rarch_system_info_t* system = runloop_get_system_info(); + + if (system->mmaps.num_descriptors != 0) + memory = (uint8_t*)system->mmaps.descriptors[var->bank_id].core.ptr; + else + { + retro_ctx_memory_info_t meminfo = {NULL, 0, 0}; + + switch (var->bank_id) + { + case 0: + meminfo.id = RETRO_MEMORY_SYSTEM_RAM; + break; + case 1: + meminfo.id = RETRO_MEMORY_SAVE_RAM; + break; + case 2: + meminfo.id = RETRO_MEMORY_VIDEO_RAM; + break; + case 3: + meminfo.id = RETRO_MEMORY_RTC; + break; + default: + CHEEVOS_ERR(CHEEVOS_TAG "invalid bank id: %s\n", var->bank_id); + break; + } + + core_get_memory(&meminfo); + memory = (uint8_t*)meminfo.data; + } + + if (memory) + memory += var->value; + } + + return memory; +} + +unsigned cheevos_var_get_value(cheevos_var_t* var) +{ + const uint8_t* memory = NULL; + unsigned value = 0; + + switch (var->type) + { + case CHEEVOS_VAR_TYPE_VALUE_COMP: + value = var->value; + break; + + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + memory = cheevos_var_get_memory(var); + + if (memory) + { + value = memory[0]; + + switch (var->size) + { + case CHEEVOS_VAR_SIZE_BIT_0: + value &= 1; + break; + case CHEEVOS_VAR_SIZE_BIT_1: + value = (value >> 1) & 1; + break; + case CHEEVOS_VAR_SIZE_BIT_2: + value = (value >> 2) & 1; + break; + case CHEEVOS_VAR_SIZE_BIT_3: + value = (value >> 3) & 1; + break; + case CHEEVOS_VAR_SIZE_BIT_4: + value = (value >> 4) & 1; + break; + case CHEEVOS_VAR_SIZE_BIT_5: + value = (value >> 5) & 1; + break; + case CHEEVOS_VAR_SIZE_BIT_6: + value = (value >> 6) & 1; + break; + case CHEEVOS_VAR_SIZE_BIT_7: + value = (value >> 7) & 1; + break; + case CHEEVOS_VAR_SIZE_NIBBLE_LOWER: + value &= 0x0f; + break; + case CHEEVOS_VAR_SIZE_NIBBLE_UPPER: + value = (value >> 4) & 0x0f; + break; + case CHEEVOS_VAR_SIZE_EIGHT_BITS: + break; + case CHEEVOS_VAR_SIZE_SIXTEEN_BITS: + value |= memory[1] << 8; + break; + case CHEEVOS_VAR_SIZE_THIRTYTWO_BITS: + value |= memory[1] << 8; + value |= memory[2] << 16; + value |= memory[3] << 24; + break; + } + } + + if (var->type == CHEEVOS_VAR_TYPE_DELTA_MEM) + { + unsigned previous = var->previous; + var->previous = value; + value = previous; + } + + break; + + case CHEEVOS_VAR_TYPE_DYNAMIC_VAR: + /* We shouldn't get here... */ + break; + } + + if(var->is_bcd) + return (((value >> 4) & 0xf) * 10) + (value & 0xf); + return value; +} diff --git a/cheevos/var.h b/cheevos/var.h index 416e2ae49e..ba85847e88 100644 --- a/cheevos/var.h +++ b/cheevos/var.h @@ -1,78 +1,78 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2018 - Andre Leiradella - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __RARCH_CHEEVOS_VAR_H -#define __RARCH_CHEEVOS_VAR_H - -#include - -#include "cheevos.h" - -#include - -RETRO_BEGIN_DECLS - -typedef enum -{ - CHEEVOS_VAR_SIZE_BIT_0 = 0, - CHEEVOS_VAR_SIZE_BIT_1, - CHEEVOS_VAR_SIZE_BIT_2, - CHEEVOS_VAR_SIZE_BIT_3, - CHEEVOS_VAR_SIZE_BIT_4, - CHEEVOS_VAR_SIZE_BIT_5, - CHEEVOS_VAR_SIZE_BIT_6, - CHEEVOS_VAR_SIZE_BIT_7, - CHEEVOS_VAR_SIZE_NIBBLE_LOWER, - CHEEVOS_VAR_SIZE_NIBBLE_UPPER, - /* Byte, */ - CHEEVOS_VAR_SIZE_EIGHT_BITS, /* =Byte, */ - CHEEVOS_VAR_SIZE_SIXTEEN_BITS, - CHEEVOS_VAR_SIZE_THIRTYTWO_BITS -} cheevos_var_size_t; - -typedef enum -{ - /* compare to the value of a live address in RAM */ - CHEEVOS_VAR_TYPE_ADDRESS = 0, - - /* a number. assume 32 bit */ - CHEEVOS_VAR_TYPE_VALUE_COMP, - - /* the value last known at this address. */ - CHEEVOS_VAR_TYPE_DELTA_MEM, - - /* a custom user-set variable */ - CHEEVOS_VAR_TYPE_DYNAMIC_VAR -} cheevos_var_type_t; - -typedef struct -{ - cheevos_var_size_t size; - cheevos_var_type_t type; - int bank_id; - bool is_bcd; - unsigned value; - unsigned previous; -} cheevos_var_t; - -void cheevos_var_parse(cheevos_var_t* var, const char** memaddr); -void cheevos_var_patch_addr(cheevos_var_t* var, cheevos_console_t console); - -uint8_t* cheevos_var_get_memory(const cheevos_var_t* var); -unsigned cheevos_var_get_value(cheevos_var_t* var); - -RETRO_END_DECLS - -#endif /* __RARCH_CHEEVOS_VAR_H */ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2018 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __RARCH_CHEEVOS_VAR_H +#define __RARCH_CHEEVOS_VAR_H + +#include + +#include "cheevos.h" + +#include + +RETRO_BEGIN_DECLS + +typedef enum +{ + CHEEVOS_VAR_SIZE_BIT_0 = 0, + CHEEVOS_VAR_SIZE_BIT_1, + CHEEVOS_VAR_SIZE_BIT_2, + CHEEVOS_VAR_SIZE_BIT_3, + CHEEVOS_VAR_SIZE_BIT_4, + CHEEVOS_VAR_SIZE_BIT_5, + CHEEVOS_VAR_SIZE_BIT_6, + CHEEVOS_VAR_SIZE_BIT_7, + CHEEVOS_VAR_SIZE_NIBBLE_LOWER, + CHEEVOS_VAR_SIZE_NIBBLE_UPPER, + /* Byte, */ + CHEEVOS_VAR_SIZE_EIGHT_BITS, /* =Byte, */ + CHEEVOS_VAR_SIZE_SIXTEEN_BITS, + CHEEVOS_VAR_SIZE_THIRTYTWO_BITS +} cheevos_var_size_t; + +typedef enum +{ + /* compare to the value of a live address in RAM */ + CHEEVOS_VAR_TYPE_ADDRESS = 0, + + /* a number. assume 32 bit */ + CHEEVOS_VAR_TYPE_VALUE_COMP, + + /* the value last known at this address. */ + CHEEVOS_VAR_TYPE_DELTA_MEM, + + /* a custom user-set variable */ + CHEEVOS_VAR_TYPE_DYNAMIC_VAR +} cheevos_var_type_t; + +typedef struct +{ + cheevos_var_size_t size; + cheevos_var_type_t type; + int bank_id; + bool is_bcd; + unsigned value; + unsigned previous; +} cheevos_var_t; + +void cheevos_var_parse(cheevos_var_t* var, const char** memaddr); +void cheevos_var_patch_addr(cheevos_var_t* var, cheevos_console_t console); + +uint8_t* cheevos_var_get_memory(const cheevos_var_t* var); +unsigned cheevos_var_get_value(cheevos_var_t* var); + +RETRO_END_DECLS + +#endif /* __RARCH_CHEEVOS_VAR_H */ diff --git a/ctr/exec-3dsx/exec_3dsx.h b/ctr/exec-3dsx/exec_3dsx.h index d260331cb0..c4a90a081c 100644 --- a/ctr/exec-3dsx/exec_3dsx.h +++ b/ctr/exec-3dsx/exec_3dsx.h @@ -1,9 +1,9 @@ -#ifndef EXEC_3DSX_H -#define EXEC_3DSX_H - -//since 3dsx programs are not guaranteed access to the OS, the 3dsx bootloader run by the exploit must run the next program -//your program must have no extra threads running when this is called, these limits do not apply to exec_cia -int exec_3dsx_no_path_in_args(const char* path, const char** args); -int exec_3dsx(const char* path, const char** args); - +#ifndef EXEC_3DSX_H +#define EXEC_3DSX_H + +//since 3dsx programs are not guaranteed access to the OS, the 3dsx bootloader run by the exploit must run the next program +//your program must have no extra threads running when this is called, these limits do not apply to exec_cia +int exec_3dsx_no_path_in_args(const char* path, const char** args); +int exec_3dsx(const char* path, const char** args); + #endif \ No newline at end of file diff --git a/ctr/exec-3dsx/exec_cia.h b/ctr/exec-3dsx/exec_cia.h index 4c751de922..3de723b74d 100644 --- a/ctr/exec-3dsx/exec_cia.h +++ b/ctr/exec-3dsx/exec_cia.h @@ -1,6 +1,6 @@ -#ifndef EXEC_CIA_H -#define EXEC_CIA_H - -int exec_cia(const char* path, const char** args); - +#ifndef EXEC_CIA_H +#define EXEC_CIA_H + +int exec_cia(const char* path, const char** args); + #endif \ No newline at end of file diff --git a/ctr/exec-3dsx/mini-hb-menu/common.h b/ctr/exec-3dsx/mini-hb-menu/common.h index ef354d46d2..633a297f9d 100644 --- a/ctr/exec-3dsx/mini-hb-menu/common.h +++ b/ctr/exec-3dsx/mini-hb-menu/common.h @@ -1,95 +1,95 @@ -#pragma once - -// C stdlib includes -#include -#include -#include -#include -#include -#include -#include -#include - -// 3DS includes -#include <3ds.h> - - -#define ENTRY_ARGBUFSIZE 0x400 -#define NUM_SERVICESTHATMATTER 5 - -typedef enum -{ - StrId_Loading = 0, - StrId_Directory, - StrId_DefaultLongTitle, - StrId_DefaultPublisher, - StrId_IOError, - StrId_CouldNotOpenFile, - - StrId_NoAppsFound_Title, - StrId_NoAppsFound_Msg, - - StrId_Reboot, - StrId_ReturnToHome, - - StrId_TitleSelector, - StrId_ErrorReadingTitleMetadata, - StrId_NoTitlesFound, - StrId_SelectTitle, - - StrId_NoTargetTitleSupport, - StrId_MissingTargetTitle, - - StrId_NetLoader, - StrId_NetLoaderUnavailable, - StrId_NetLoaderOffline, - StrId_NetLoaderError, - StrId_NetLoaderActive, - StrId_NetLoaderTransferring, - - StrId_Max, -} StrId; - - -typedef struct -{ - char* dst; - u32 buf[ENTRY_ARGBUFSIZE/sizeof(u32)]; -} argData_s; - -typedef struct -{ - bool scanned; - u32 sectionSizes[3]; - bool servicesThatMatter[NUM_SERVICESTHATMATTER]; -} executableMetadata_s; - -typedef struct -{ - u32 num; - u32 text_end; - u32 data_address; - u32 data_size; - u32 processLinearOffset; - u32 processHookAddress; - u32 processAppCodeAddress; - u32 processHookTidLow, processHookTidHigh; - u32 mediatype; - bool capabilities[0x10]; // {socuAccess, csndAccess, qtmAccess, nfcAccess, httpcAccess, reserved...} -} memmap_header_t; - -typedef struct -{ - u32 src, dst, size; -} memmap_entry_t; - -typedef struct -{ - memmap_header_t header; - memmap_entry_t map[]; -} memmap_t; - -#define memmapSize(m) (sizeof(memmap_header_t) + sizeof(memmap_entry_t)*(m)->header.num) - - -#include "launch.h" +#pragma once + +// C stdlib includes +#include +#include +#include +#include +#include +#include +#include +#include + +// 3DS includes +#include <3ds.h> + + +#define ENTRY_ARGBUFSIZE 0x400 +#define NUM_SERVICESTHATMATTER 5 + +typedef enum +{ + StrId_Loading = 0, + StrId_Directory, + StrId_DefaultLongTitle, + StrId_DefaultPublisher, + StrId_IOError, + StrId_CouldNotOpenFile, + + StrId_NoAppsFound_Title, + StrId_NoAppsFound_Msg, + + StrId_Reboot, + StrId_ReturnToHome, + + StrId_TitleSelector, + StrId_ErrorReadingTitleMetadata, + StrId_NoTitlesFound, + StrId_SelectTitle, + + StrId_NoTargetTitleSupport, + StrId_MissingTargetTitle, + + StrId_NetLoader, + StrId_NetLoaderUnavailable, + StrId_NetLoaderOffline, + StrId_NetLoaderError, + StrId_NetLoaderActive, + StrId_NetLoaderTransferring, + + StrId_Max, +} StrId; + + +typedef struct +{ + char* dst; + u32 buf[ENTRY_ARGBUFSIZE/sizeof(u32)]; +} argData_s; + +typedef struct +{ + bool scanned; + u32 sectionSizes[3]; + bool servicesThatMatter[NUM_SERVICESTHATMATTER]; +} executableMetadata_s; + +typedef struct +{ + u32 num; + u32 text_end; + u32 data_address; + u32 data_size; + u32 processLinearOffset; + u32 processHookAddress; + u32 processAppCodeAddress; + u32 processHookTidLow, processHookTidHigh; + u32 mediatype; + bool capabilities[0x10]; // {socuAccess, csndAccess, qtmAccess, nfcAccess, httpcAccess, reserved...} +} memmap_header_t; + +typedef struct +{ + u32 src, dst, size; +} memmap_entry_t; + +typedef struct +{ + memmap_header_t header; + memmap_entry_t map[]; +} memmap_t; + +#define memmapSize(m) (sizeof(memmap_header_t) + sizeof(memmap_entry_t)*(m)->header.num) + + +#include "launch.h" diff --git a/frontend/drivers/platform_ctr.c b/frontend/drivers/platform_ctr.c index 58fb331736..0eb6077a40 100644 --- a/frontend/drivers/platform_ctr.c +++ b/frontend/drivers/platform_ctr.c @@ -1,607 +1,607 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2014-2017 - Ali Bouhlel - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include <3ds.h> -#include <3ds/svc.h> -#include <3ds/os.h> -#include <3ds/services/cfgu.h> -#include <3ds/services/ptmu.h> -#include <3ds/services/mcuhwc.h> - -#include - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#ifndef IS_SALAMANDER -#include -#endif - -#include "../frontend_driver.h" -#include "../../verbosity.h" -#include "../../defaults.h" -#include "../../paths.h" -#include "retroarch.h" -#include "file_path_special.h" -#include "audio/audio_driver.h" - -#include "ctr/ctr_debug.h" -#include "ctr/exec-3dsx/exec_3dsx.h" -#include "ctr/exec-3dsx/exec_cia.h" - -#ifndef IS_SALAMANDER -#ifdef HAVE_MENU -#include "../../menu/menu_driver.h" -#endif -#endif - -static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE; -static const char* elf_path_cst = "sdmc:/retroarch/retroarch.3dsx"; - -static void get_first_valid_core(char* path_return) -{ - DIR* dir; - struct dirent* ent; - const char* extension = envIsHomebrew() ? ".3dsx" : ".cia"; - - path_return[0] = '\0'; - - dir = opendir("sdmc:/retroarch/cores"); - if (dir != NULL) - { - while (ent = readdir(dir)) - { - if (ent == NULL) - break; - if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension)) - { - strcpy(path_return, "sdmc:/retroarch/cores"); - strcat(path_return, "/"); - strcat(path_return, ent->d_name); - break; - } - } - closedir(dir); - } -} - -static void frontend_ctr_get_environment_settings(int* argc, char* argv[], - void* args, void* params_data) -{ - (void)args; - -#ifndef IS_SALAMANDER -#if defined(HAVE_LOGGER) - logger_init(); -#elif defined(HAVE_FILE_LOGGER) - retro_main_log_file_init("sdmc:/retroarch/retroarch-log.txt"); -#endif -#endif - - fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], elf_path_cst, sizeof(g_defaults.dirs[DEFAULT_DIR_PORT])); - RARCH_LOG("port dir: [%s]\n", g_defaults.dirs[DEFAULT_DIR_PORT]); - - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT], - "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT], - "media", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], g_defaults.dirs[DEFAULT_DIR_PORT], - "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], g_defaults.dirs[DEFAULT_DIR_CORE], - "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], g_defaults.dirs[DEFAULT_DIR_CORE], - "savestates", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], g_defaults.dirs[DEFAULT_DIR_CORE], - "savefiles", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_CORE], - "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], g_defaults.dirs[DEFAULT_DIR_CORE], - "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], g_defaults.dirs[DEFAULT_DIR_PORT], - "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_PORT], - "config/remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], g_defaults.dirs[DEFAULT_DIR_PORT], - "filters", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], g_defaults.dirs[DEFAULT_DIR_PORT], - "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], g_defaults.dirs[DEFAULT_DIR_PORT], - "database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR])); - fill_pathname_join(g_defaults.path.config, g_defaults.dirs[DEFAULT_DIR_PORT], - file_path_str(FILE_PATH_MAIN_CONFIG), sizeof(g_defaults.path.config)); -} - -static void frontend_ctr_deinit(void* data) -{ - Handle lcd_handle; - u32 parallax_layer_reg_state; - u8 not_2DS; - - extern PrintConsole* currentConsole; - - (void)data; - -#ifndef IS_SALAMANDER - verbosity_enable(); - -#ifdef HAVE_FILE_LOGGER - command_event(CMD_EVENT_LOG_FILE_DEINIT, NULL); -#endif - - if ((gfxBottomFramebuffers[0] == (u8*)currentConsole->frameBuffer) - && (ctr_fork_mode == FRONTEND_FORK_NONE)) - wait_for_input(); - - CFGU_GetModelNintendo2DS(¬_2DS); - - if (not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0) - { - u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = 0x00110040; - cmdbuf[1] = 2; - svcSendSyncRequest(lcd_handle); - svcCloseHandle(lcd_handle); - } - - parallax_layer_reg_state = (*(float*)0x1FF81080 == 0.0) ? 0x0 : 0x00010001; - GSPGPU_WriteHWRegs(0x202000, ¶llax_layer_reg_state, 4); - - mcuHwcExit(); - ptmuExit(); - cfguExit(); - ndspExit(); - csndExit(); - gfxTopRightFramebuffers[0] = NULL; - gfxTopRightFramebuffers[1] = NULL; - gfxExit(); -#endif -} - -static void frontend_ctr_exec(const char* path, bool should_load_game) -{ - char game_path[PATH_MAX]; - const char* arg_data[3]; - errorConf error_dialog; - char error_string[200 + PATH_MAX]; - int args = 0; - int error = 0; - - DEBUG_VAR(path); - DEBUG_STR(path); - - arg_data[0] = NULL; - - arg_data[args] = elf_path_cst; - arg_data[args + 1] = NULL; - args++; - - RARCH_LOG("Attempt to load core: [%s].\n", path); -#ifndef IS_SALAMANDER - if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT)) - { - strcpy(game_path, path_get(RARCH_PATH_CONTENT)); - arg_data[args] = game_path; - arg_data[args + 1] = NULL; - args++; - RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT)); - } -#endif - - if (path && path[0]) - { -#ifdef IS_SALAMANDER - struct stat sbuff; - bool file_exists; - - file_exists = stat(path, &sbuff) == 0; - if (!file_exists) - { - char core_path[PATH_MAX]; - - /* find first valid core and load it if the target core doesnt exist */ - get_first_valid_core(&core_path[0]); - - if (core_path[0] == '\0') - { - errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN); - errorText(&error_dialog, "There are no cores installed, install a core to continue."); - errorDisp(&error_dialog); - exit(0); - } - } -#endif - - if (envIsHomebrew()) - { - exec_3dsx_no_path_in_args(path, arg_data); - } - else - { - RARCH_WARN("\n"); - RARCH_WARN("\n"); - RARCH_WARN("Warning:\n"); - RARCH_WARN("First core launch may take 20\n"); - RARCH_WARN("seconds! Do not force quit\n"); - RARCH_WARN("before then or your memory\n"); - RARCH_WARN("card may be corrupted!\n"); - RARCH_WARN("\n"); - RARCH_WARN("\n"); - exec_cia(path, arg_data); - } - - errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN); - snprintf(error_string, sizeof(error_string), "Cant launch core:%s", path); - errorText(&error_dialog, error_string); - errorDisp(&error_dialog); - exit(0);//couldnt launch new core, but context is corrupt so we have to quit - } -} - -#ifndef IS_SALAMANDER -static bool frontend_ctr_set_fork(enum frontend_fork fork_mode) -{ - switch (fork_mode) - { - case FRONTEND_FORK_CORE: - RARCH_LOG("FRONTEND_FORK_CORE\n"); - ctr_fork_mode = fork_mode; - break; - case FRONTEND_FORK_CORE_WITH_ARGS: - RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n"); - ctr_fork_mode = fork_mode; - break; - case FRONTEND_FORK_RESTART: - RARCH_LOG("FRONTEND_FORK_RESTART\n"); - /* NOTE: We don't implement Salamander, so just turn - this into FRONTEND_FORK_CORE. */ - ctr_fork_mode = FRONTEND_FORK_CORE; - break; - case FRONTEND_FORK_NONE: - default: - return false; - } - - return true; -} -#endif - -static void frontend_ctr_exitspawn(char* s, size_t len) -{ - bool should_load_game = false; -#ifndef IS_SALAMANDER - if (ctr_fork_mode == FRONTEND_FORK_NONE) - return; - - switch (ctr_fork_mode) - { - case FRONTEND_FORK_CORE_WITH_ARGS: - should_load_game = true; - break; - default: - break; - } -#endif - frontend_ctr_exec(s, should_load_game); -} - -static void frontend_ctr_shutdown(bool unused) -{ - (void)unused; -} - -static void ctr_check_dspfirm(void) -{ - FILE* dsp_fp = fopen("sdmc:/3ds/dspfirm.cdc", "rb"); - - if (dsp_fp) - fclose(dsp_fp); - else - { - size_t code_size; - uint32_t* code_buffer = NULL; - uint32_t* ptr = NULL; - const uint32_t dsp1_magic = 0x31505344; /* "DSP1" */ - FILE* code_fp = fopen("sdmc:/3ds/code.bin", "rb"); - - if (code_fp) - { - fseek(code_fp, 0, SEEK_END); - code_size = ftell(code_fp); - fseek(code_fp, 0, SEEK_SET); - - code_buffer = (uint32_t*) malloc(code_size); - if (code_buffer) - { - fread(code_buffer, 1, code_size, code_fp); - - for (ptr = code_buffer + 0x40; ptr < (code_buffer + (code_size >> 2)); ptr++) - { - if (*ptr == dsp1_magic) - { - size_t dspfirm_size = ptr[1]; - ptr -= 0x40; - if ((ptr + (dspfirm_size >> 2)) > (code_buffer + (code_size >> 2))) - break; - - dsp_fp = fopen("sdmc:/3ds/dspfirm.cdc", "wb"); - if (!dsp_fp) - break; - fwrite(ptr, 1, dspfirm_size, dsp_fp); - fclose(dsp_fp); - break; - } - } - free(code_buffer); - } - fclose(code_fp); - } - else - { - RARCH_WARN("\n"); - RARCH_WARN("\n"); - RARCH_WARN("Warning:\n"); - RARCH_WARN("3DS DSP dump is missing.\n"); - RARCH_WARN("A working DSP dump is required\n"); - RARCH_WARN("for correct operation.\n"); - RARCH_WARN("\n"); - RARCH_WARN("\n"); - } - } -} - -__attribute__((weak)) Result svchax_init(bool patch_srv); -__attribute__((weak)) u32 __ctr_patch_services; - -void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id); - -static void frontend_ctr_init(void* data) -{ -#ifndef IS_SALAMANDER - (void)data; - - verbosity_enable(); - - gfxInit(GSP_BGR8_OES, GSP_RGB565_OES, false); - - u32 topSize = 400 * 240 * 3; - u32 bottomSize = 320 * 240 * 2; - linearFree(gfxTopLeftFramebuffers[0]); - linearFree(gfxTopLeftFramebuffers[1]); - linearFree(gfxBottomFramebuffers[0]); - linearFree(gfxBottomFramebuffers[1]); - linearFree(gfxTopRightFramebuffers[0]); - linearFree(gfxTopRightFramebuffers[1]); - - gfxTopLeftFramebuffers[0] = linearAlloc(topSize * 2); - gfxTopRightFramebuffers[0] = gfxTopLeftFramebuffers[0] + topSize; - - gfxTopLeftFramebuffers[1] = linearAlloc(topSize * 2); - gfxTopRightFramebuffers[1] = gfxTopLeftFramebuffers[1] + topSize; - - gfxBottomFramebuffers[0] = linearAlloc(bottomSize); - gfxBottomFramebuffers[1] = linearAlloc(bottomSize); - - gfxSetFramebufferInfo(GFX_TOP, 0); - gfxSetFramebufferInfo(GFX_BOTTOM, 0); - - gfxSet3D(true); - consoleInit(GFX_BOTTOM, NULL); - - /* enable access to all service calls when possible. */ - if (svchax_init) - { - osSetSpeedupEnable(false); - svchax_init(__ctr_patch_services); - } - osSetSpeedupEnable(true); - - if (csndInit() != 0) - audio_ctr_csnd = audio_null; - ctr_check_dspfirm(); - if (ndspInit() != 0) - audio_ctr_dsp = audio_null; - cfguInit(); - ptmuInit(); - mcuHwcInit(); -#endif -} - - -static int frontend_ctr_get_rating(void) -{ - u8 device_model = 0xFF; - CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/ - - switch (device_model) - { - case 0: - case 1: - case 3: - /*Old 3/2DS*/ - return 3; - - case 2: - case 4: - case 5: - /*New 3/2DS*/ - return 6; - - default: - /*Unknown Device Or Check Failed*/ - break; - } - - return -1; -} - -enum frontend_architecture frontend_ctr_get_architecture(void) -{ - return FRONTEND_ARCH_ARM; -} - -static int frontend_ctr_parse_drive_list(void* data, bool load_content) -{ -#ifndef IS_SALAMANDER - file_list_t* list = (file_list_t*)data; - enum msg_hash_enums enum_idx = load_content ? - MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR : - MSG_UNKNOWN; - - if (!list) - return -1; - - menu_entries_append_enum(list, - "sdmc:/", - msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), - enum_idx, - FILE_TYPE_DIRECTORY, 0, 0); -#endif - - return 0; -} - -static uint64_t frontend_ctr_get_mem_total(void) -{ - return osGetMemRegionSize(MEMREGION_ALL); -} - -static uint64_t frontend_ctr_get_mem_used(void) -{ - return osGetMemRegionUsed(MEMREGION_ALL); -} - -static enum frontend_powerstate frontend_ctr_get_powerstate(int* seconds, int* percent) -{ - u8 battery_percent = 0; - u8 charging = 0; - enum frontend_powerstate pwr_state = FRONTEND_POWERSTATE_NONE; - - mcuHwcGetBatteryLevel(&battery_percent); - *percent = battery_percent; - - /* 3ds does not support seconds of charge remaining */ - *seconds = -1; - - PTMU_GetBatteryChargeState(&charging); - if (charging) - { - if (battery_percent == 100) - pwr_state = FRONTEND_POWERSTATE_CHARGED; - else - pwr_state = FRONTEND_POWERSTATE_CHARGING; - } - else - pwr_state = FRONTEND_POWERSTATE_ON_POWER_SOURCE; - - return pwr_state; -} - -static void frontend_ctr_get_os(char* s, size_t len, int* major, int* minor) -{ - OS_VersionBin cver; - OS_VersionBin nver; - - strlcpy(s, "3DS OS", len); - Result data_invalid = osGetSystemVersionData(&nver, &cver); - if (data_invalid == 0) - { - *major = cver.mainver; - *minor = cver.minor; - } - else - { - *major = 0; - *minor = 0; - } - -} - -static void frontend_ctr_get_name(char* s, size_t len) -{ - u8 device_model = 0xFF; - CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/ - - switch (device_model) - { - case 0: - strlcpy(s, "Old 3DS", len); - break; - case 1: - strlcpy(s, "Old 3DS XL", len); - break; - case 2: - strlcpy(s, "New 3DS", len); - break; - case 3: - strlcpy(s, "Old 2DS", len); - break; - case 4: - strlcpy(s, "New 3DS XL", len); - break; - case 5: - strlcpy(s, "New 2DS XL", len); - break; - - default: - strlcpy(s, "Unknown Device", len); - break; - } -} - -frontend_ctx_driver_t frontend_ctx_ctr = -{ - frontend_ctr_get_environment_settings, - frontend_ctr_init, - frontend_ctr_deinit, - frontend_ctr_exitspawn, - NULL, /* process_args */ - frontend_ctr_exec, -#ifdef IS_SALAMANDER - NULL, -#else - frontend_ctr_set_fork, -#endif - frontend_ctr_shutdown, - frontend_ctr_get_name, - frontend_ctr_get_os, - frontend_ctr_get_rating, - NULL, /* load_content */ - frontend_ctr_get_architecture, - frontend_ctr_get_powerstate, - frontend_ctr_parse_drive_list, - frontend_ctr_get_mem_total, - frontend_ctr_get_mem_used, - NULL, /* install_signal_handler */ - NULL, /* get_signal_handler_state */ - NULL, /* set_signal_handler_state */ - NULL, /* destroy_signal_handler_state */ - NULL, /* attach_console */ - NULL, /* detach_console */ - NULL, /* watch_path_for_changes */ - NULL, /* check_for_path_changes */ - NULL, /* set_sustained_performance_mode */ - "ctr", -}; +/* RetroArch - A frontend for libretro. + * Copyright (C) 2014-2017 - Ali Bouhlel + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include <3ds.h> +#include <3ds/svc.h> +#include <3ds/os.h> +#include <3ds/services/cfgu.h> +#include <3ds/services/ptmu.h> +#include <3ds/services/mcuhwc.h> + +#include + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifndef IS_SALAMANDER +#include +#endif + +#include "../frontend_driver.h" +#include "../../verbosity.h" +#include "../../defaults.h" +#include "../../paths.h" +#include "retroarch.h" +#include "file_path_special.h" +#include "audio/audio_driver.h" + +#include "ctr/ctr_debug.h" +#include "ctr/exec-3dsx/exec_3dsx.h" +#include "ctr/exec-3dsx/exec_cia.h" + +#ifndef IS_SALAMANDER +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif +#endif + +static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE; +static const char* elf_path_cst = "sdmc:/retroarch/retroarch.3dsx"; + +static void get_first_valid_core(char* path_return) +{ + DIR* dir; + struct dirent* ent; + const char* extension = envIsHomebrew() ? ".3dsx" : ".cia"; + + path_return[0] = '\0'; + + dir = opendir("sdmc:/retroarch/cores"); + if (dir != NULL) + { + while (ent = readdir(dir)) + { + if (ent == NULL) + break; + if (strlen(ent->d_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension)) + { + strcpy(path_return, "sdmc:/retroarch/cores"); + strcat(path_return, "/"); + strcat(path_return, ent->d_name); + break; + } + } + closedir(dir); + } +} + +static void frontend_ctr_get_environment_settings(int* argc, char* argv[], + void* args, void* params_data) +{ + (void)args; + +#ifndef IS_SALAMANDER +#if defined(HAVE_LOGGER) + logger_init(); +#elif defined(HAVE_FILE_LOGGER) + retro_main_log_file_init("sdmc:/retroarch/retroarch-log.txt"); +#endif +#endif + + fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], elf_path_cst, sizeof(g_defaults.dirs[DEFAULT_DIR_PORT])); + RARCH_LOG("port dir: [%s]\n", g_defaults.dirs[DEFAULT_DIR_PORT]); + + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT], + "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT], + "media", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], g_defaults.dirs[DEFAULT_DIR_PORT], + "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], g_defaults.dirs[DEFAULT_DIR_CORE], + "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], g_defaults.dirs[DEFAULT_DIR_CORE], + "savestates", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], g_defaults.dirs[DEFAULT_DIR_CORE], + "savefiles", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_CORE], + "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], g_defaults.dirs[DEFAULT_DIR_CORE], + "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], g_defaults.dirs[DEFAULT_DIR_PORT], + "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_PORT], + "config/remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], g_defaults.dirs[DEFAULT_DIR_PORT], + "filters", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], g_defaults.dirs[DEFAULT_DIR_PORT], + "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], g_defaults.dirs[DEFAULT_DIR_PORT], + "database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR])); + fill_pathname_join(g_defaults.path.config, g_defaults.dirs[DEFAULT_DIR_PORT], + file_path_str(FILE_PATH_MAIN_CONFIG), sizeof(g_defaults.path.config)); +} + +static void frontend_ctr_deinit(void* data) +{ + Handle lcd_handle; + u32 parallax_layer_reg_state; + u8 not_2DS; + + extern PrintConsole* currentConsole; + + (void)data; + +#ifndef IS_SALAMANDER + verbosity_enable(); + +#ifdef HAVE_FILE_LOGGER + command_event(CMD_EVENT_LOG_FILE_DEINIT, NULL); +#endif + + if ((gfxBottomFramebuffers[0] == (u8*)currentConsole->frameBuffer) + && (ctr_fork_mode == FRONTEND_FORK_NONE)) + wait_for_input(); + + CFGU_GetModelNintendo2DS(¬_2DS); + + if (not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0) + { + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00110040; + cmdbuf[1] = 2; + svcSendSyncRequest(lcd_handle); + svcCloseHandle(lcd_handle); + } + + parallax_layer_reg_state = (*(float*)0x1FF81080 == 0.0) ? 0x0 : 0x00010001; + GSPGPU_WriteHWRegs(0x202000, ¶llax_layer_reg_state, 4); + + mcuHwcExit(); + ptmuExit(); + cfguExit(); + ndspExit(); + csndExit(); + gfxTopRightFramebuffers[0] = NULL; + gfxTopRightFramebuffers[1] = NULL; + gfxExit(); +#endif +} + +static void frontend_ctr_exec(const char* path, bool should_load_game) +{ + char game_path[PATH_MAX]; + const char* arg_data[3]; + errorConf error_dialog; + char error_string[200 + PATH_MAX]; + int args = 0; + int error = 0; + + DEBUG_VAR(path); + DEBUG_STR(path); + + arg_data[0] = NULL; + + arg_data[args] = elf_path_cst; + arg_data[args + 1] = NULL; + args++; + + RARCH_LOG("Attempt to load core: [%s].\n", path); +#ifndef IS_SALAMANDER + if (should_load_game && !path_is_empty(RARCH_PATH_CONTENT)) + { + strcpy(game_path, path_get(RARCH_PATH_CONTENT)); + arg_data[args] = game_path; + arg_data[args + 1] = NULL; + args++; + RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT)); + } +#endif + + if (path && path[0]) + { +#ifdef IS_SALAMANDER + struct stat sbuff; + bool file_exists; + + file_exists = stat(path, &sbuff) == 0; + if (!file_exists) + { + char core_path[PATH_MAX]; + + /* find first valid core and load it if the target core doesnt exist */ + get_first_valid_core(&core_path[0]); + + if (core_path[0] == '\0') + { + errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN); + errorText(&error_dialog, "There are no cores installed, install a core to continue."); + errorDisp(&error_dialog); + exit(0); + } + } +#endif + + if (envIsHomebrew()) + { + exec_3dsx_no_path_in_args(path, arg_data); + } + else + { + RARCH_WARN("\n"); + RARCH_WARN("\n"); + RARCH_WARN("Warning:\n"); + RARCH_WARN("First core launch may take 20\n"); + RARCH_WARN("seconds! Do not force quit\n"); + RARCH_WARN("before then or your memory\n"); + RARCH_WARN("card may be corrupted!\n"); + RARCH_WARN("\n"); + RARCH_WARN("\n"); + exec_cia(path, arg_data); + } + + errorInit(&error_dialog, ERROR_TEXT, CFG_LANGUAGE_EN); + snprintf(error_string, sizeof(error_string), "Cant launch core:%s", path); + errorText(&error_dialog, error_string); + errorDisp(&error_dialog); + exit(0);//couldnt launch new core, but context is corrupt so we have to quit + } +} + +#ifndef IS_SALAMANDER +static bool frontend_ctr_set_fork(enum frontend_fork fork_mode) +{ + switch (fork_mode) + { + case FRONTEND_FORK_CORE: + RARCH_LOG("FRONTEND_FORK_CORE\n"); + ctr_fork_mode = fork_mode; + break; + case FRONTEND_FORK_CORE_WITH_ARGS: + RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n"); + ctr_fork_mode = fork_mode; + break; + case FRONTEND_FORK_RESTART: + RARCH_LOG("FRONTEND_FORK_RESTART\n"); + /* NOTE: We don't implement Salamander, so just turn + this into FRONTEND_FORK_CORE. */ + ctr_fork_mode = FRONTEND_FORK_CORE; + break; + case FRONTEND_FORK_NONE: + default: + return false; + } + + return true; +} +#endif + +static void frontend_ctr_exitspawn(char* s, size_t len) +{ + bool should_load_game = false; +#ifndef IS_SALAMANDER + if (ctr_fork_mode == FRONTEND_FORK_NONE) + return; + + switch (ctr_fork_mode) + { + case FRONTEND_FORK_CORE_WITH_ARGS: + should_load_game = true; + break; + default: + break; + } +#endif + frontend_ctr_exec(s, should_load_game); +} + +static void frontend_ctr_shutdown(bool unused) +{ + (void)unused; +} + +static void ctr_check_dspfirm(void) +{ + FILE* dsp_fp = fopen("sdmc:/3ds/dspfirm.cdc", "rb"); + + if (dsp_fp) + fclose(dsp_fp); + else + { + size_t code_size; + uint32_t* code_buffer = NULL; + uint32_t* ptr = NULL; + const uint32_t dsp1_magic = 0x31505344; /* "DSP1" */ + FILE* code_fp = fopen("sdmc:/3ds/code.bin", "rb"); + + if (code_fp) + { + fseek(code_fp, 0, SEEK_END); + code_size = ftell(code_fp); + fseek(code_fp, 0, SEEK_SET); + + code_buffer = (uint32_t*) malloc(code_size); + if (code_buffer) + { + fread(code_buffer, 1, code_size, code_fp); + + for (ptr = code_buffer + 0x40; ptr < (code_buffer + (code_size >> 2)); ptr++) + { + if (*ptr == dsp1_magic) + { + size_t dspfirm_size = ptr[1]; + ptr -= 0x40; + if ((ptr + (dspfirm_size >> 2)) > (code_buffer + (code_size >> 2))) + break; + + dsp_fp = fopen("sdmc:/3ds/dspfirm.cdc", "wb"); + if (!dsp_fp) + break; + fwrite(ptr, 1, dspfirm_size, dsp_fp); + fclose(dsp_fp); + break; + } + } + free(code_buffer); + } + fclose(code_fp); + } + else + { + RARCH_WARN("\n"); + RARCH_WARN("\n"); + RARCH_WARN("Warning:\n"); + RARCH_WARN("3DS DSP dump is missing.\n"); + RARCH_WARN("A working DSP dump is required\n"); + RARCH_WARN("for correct operation.\n"); + RARCH_WARN("\n"); + RARCH_WARN("\n"); + } + } +} + +__attribute__((weak)) Result svchax_init(bool patch_srv); +__attribute__((weak)) u32 __ctr_patch_services; + +void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id); + +static void frontend_ctr_init(void* data) +{ +#ifndef IS_SALAMANDER + (void)data; + + verbosity_enable(); + + gfxInit(GSP_BGR8_OES, GSP_RGB565_OES, false); + + u32 topSize = 400 * 240 * 3; + u32 bottomSize = 320 * 240 * 2; + linearFree(gfxTopLeftFramebuffers[0]); + linearFree(gfxTopLeftFramebuffers[1]); + linearFree(gfxBottomFramebuffers[0]); + linearFree(gfxBottomFramebuffers[1]); + linearFree(gfxTopRightFramebuffers[0]); + linearFree(gfxTopRightFramebuffers[1]); + + gfxTopLeftFramebuffers[0] = linearAlloc(topSize * 2); + gfxTopRightFramebuffers[0] = gfxTopLeftFramebuffers[0] + topSize; + + gfxTopLeftFramebuffers[1] = linearAlloc(topSize * 2); + gfxTopRightFramebuffers[1] = gfxTopLeftFramebuffers[1] + topSize; + + gfxBottomFramebuffers[0] = linearAlloc(bottomSize); + gfxBottomFramebuffers[1] = linearAlloc(bottomSize); + + gfxSetFramebufferInfo(GFX_TOP, 0); + gfxSetFramebufferInfo(GFX_BOTTOM, 0); + + gfxSet3D(true); + consoleInit(GFX_BOTTOM, NULL); + + /* enable access to all service calls when possible. */ + if (svchax_init) + { + osSetSpeedupEnable(false); + svchax_init(__ctr_patch_services); + } + osSetSpeedupEnable(true); + + if (csndInit() != 0) + audio_ctr_csnd = audio_null; + ctr_check_dspfirm(); + if (ndspInit() != 0) + audio_ctr_dsp = audio_null; + cfguInit(); + ptmuInit(); + mcuHwcInit(); +#endif +} + + +static int frontend_ctr_get_rating(void) +{ + u8 device_model = 0xFF; + CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/ + + switch (device_model) + { + case 0: + case 1: + case 3: + /*Old 3/2DS*/ + return 3; + + case 2: + case 4: + case 5: + /*New 3/2DS*/ + return 6; + + default: + /*Unknown Device Or Check Failed*/ + break; + } + + return -1; +} + +enum frontend_architecture frontend_ctr_get_architecture(void) +{ + return FRONTEND_ARCH_ARM; +} + +static int frontend_ctr_parse_drive_list(void* data, bool load_content) +{ +#ifndef IS_SALAMANDER + file_list_t* list = (file_list_t*)data; + enum msg_hash_enums enum_idx = load_content ? + MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR : + MSG_UNKNOWN; + + if (!list) + return -1; + + menu_entries_append_enum(list, + "sdmc:/", + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + enum_idx, + FILE_TYPE_DIRECTORY, 0, 0); +#endif + + return 0; +} + +static uint64_t frontend_ctr_get_mem_total(void) +{ + return osGetMemRegionSize(MEMREGION_ALL); +} + +static uint64_t frontend_ctr_get_mem_used(void) +{ + return osGetMemRegionUsed(MEMREGION_ALL); +} + +static enum frontend_powerstate frontend_ctr_get_powerstate(int* seconds, int* percent) +{ + u8 battery_percent = 0; + u8 charging = 0; + enum frontend_powerstate pwr_state = FRONTEND_POWERSTATE_NONE; + + mcuHwcGetBatteryLevel(&battery_percent); + *percent = battery_percent; + + /* 3ds does not support seconds of charge remaining */ + *seconds = -1; + + PTMU_GetBatteryChargeState(&charging); + if (charging) + { + if (battery_percent == 100) + pwr_state = FRONTEND_POWERSTATE_CHARGED; + else + pwr_state = FRONTEND_POWERSTATE_CHARGING; + } + else + pwr_state = FRONTEND_POWERSTATE_ON_POWER_SOURCE; + + return pwr_state; +} + +static void frontend_ctr_get_os(char* s, size_t len, int* major, int* minor) +{ + OS_VersionBin cver; + OS_VersionBin nver; + + strlcpy(s, "3DS OS", len); + Result data_invalid = osGetSystemVersionData(&nver, &cver); + if (data_invalid == 0) + { + *major = cver.mainver; + *minor = cver.minor; + } + else + { + *major = 0; + *minor = 0; + } + +} + +static void frontend_ctr_get_name(char* s, size_t len) +{ + u8 device_model = 0xFF; + CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/ + + switch (device_model) + { + case 0: + strlcpy(s, "Old 3DS", len); + break; + case 1: + strlcpy(s, "Old 3DS XL", len); + break; + case 2: + strlcpy(s, "New 3DS", len); + break; + case 3: + strlcpy(s, "Old 2DS", len); + break; + case 4: + strlcpy(s, "New 3DS XL", len); + break; + case 5: + strlcpy(s, "New 2DS XL", len); + break; + + default: + strlcpy(s, "Unknown Device", len); + break; + } +} + +frontend_ctx_driver_t frontend_ctx_ctr = +{ + frontend_ctr_get_environment_settings, + frontend_ctr_init, + frontend_ctr_deinit, + frontend_ctr_exitspawn, + NULL, /* process_args */ + frontend_ctr_exec, +#ifdef IS_SALAMANDER + NULL, +#else + frontend_ctr_set_fork, +#endif + frontend_ctr_shutdown, + frontend_ctr_get_name, + frontend_ctr_get_os, + frontend_ctr_get_rating, + NULL, /* load_content */ + frontend_ctr_get_architecture, + frontend_ctr_get_powerstate, + frontend_ctr_parse_drive_list, + frontend_ctr_get_mem_total, + frontend_ctr_get_mem_used, + NULL, /* install_signal_handler */ + NULL, /* get_signal_handler_state */ + NULL, /* set_signal_handler_state */ + NULL, /* destroy_signal_handler_state */ + NULL, /* attach_console */ + NULL, /* detach_console */ + NULL, /* watch_path_for_changes */ + NULL, /* check_for_path_changes */ + NULL, /* set_sustained_performance_mode */ + "ctr", +}; diff --git a/frontend/drivers/platform_xdk.h b/frontend/drivers/platform_xdk.h index fa6121fca6..f2cc78ea63 100644 --- a/frontend/drivers/platform_xdk.h +++ b/frontend/drivers/platform_xdk.h @@ -1,1000 +1,1000 @@ -#ifdef _XBOX1 -#include - -// Don't do __declspec(dllimport) for things like emulators -#if defined(NTSYSAPI) && defined(DONT_IMPORT_INTERNAL) -#undef NTSYSAPI -#endif -#ifdef DONT_IMPORT_INTERNAL -#define NTSYSAPI -#endif - -// The normal headers don't have this...? -#define FASTCALL __fastcall - -// The usual NTSTATUS -typedef LONG NTSTATUS; - -// The usual NT_SUCCESS -#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) - -// Just for documentation -#define EXPORTNUM(x) - - -// Needed for object structures and related things -typedef CONST SHORT CSHORT; - - -// String types -typedef CHAR *PSZ; -typedef CONST CHAR *PCSZ; - -// ANSI_STRING -// Differences from NT: None. -typedef struct _STRING { - USHORT Length; - USHORT MaximumLength; - PCHAR Buffer; -} STRING; -typedef STRING *PSTRING; - -typedef STRING ANSI_STRING; -typedef PSTRING PANSI_STRING; - - -// IO Status Block type (UNVERIFIED) -// Differences from NT: None. -typedef struct _IO_STATUS_BLOCK { - union { - NTSTATUS Status; - PVOID Pointer; - }; - - ULONG_PTR Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; - -// APC routine -typedef -VOID -(NTAPI *PIO_APC_ROUTINE) ( - IN PVOID ApcContext, - IN PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG Reserved - ); - - -// Header for dispatcher objects -// Differences from NT: None. -typedef struct _DISPATCHER_HEADER { - UCHAR Type; - UCHAR Absolute; - UCHAR Size; - UCHAR Inserted; - LONG SignalState; - LIST_ENTRY WaitListHead; -} DISPATCHER_HEADER; - - -// Object types -#define NotificationTimerObject 8 -#define SynchronizationTimerObject 9 -#define DpcObject 19 - - -// Object Attributes type -// Differences from NT: There are no Length, SecurityDescriptor, or -// SecurityQualityOfService fields. Also, ObjectName is ANSI, not -// Unicode. -typedef struct _OBJECT_ATTRIBUTES { - HANDLE RootDirectory; - PANSI_STRING ObjectName; - ULONG Attributes; -} OBJECT_ATTRIBUTES; -typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; - -// Flags for OBJECT_ATTRIBUTES::Attributes -#define OBJ_INHERIT 0x00000002L -#define OBJ_PERMANENT 0x00000010L -#define OBJ_EXCLUSIVE 0x00000020L -#define OBJ_CASE_INSENSITIVE 0x00000040L -#define OBJ_OPENIF 0x00000080L -#define OBJ_OPENLINK 0x00000100L -#define OBJ_KERNEL_HANDLE 0x00000200L -#define OBJ_VALID_ATTRIBUTES 0x000003F2L - -// CreateDisposition values for NtCreateFile() -#define FILE_SUPERSEDE 0x00000000 -#define FILE_OPEN 0x00000001 -#define FILE_CREATE 0x00000002 -#define FILE_OPEN_IF 0x00000003 -#define FILE_OVERWRITE 0x00000004 -#define FILE_OVERWRITE_IF 0x00000005 -#define FILE_MAXIMUM_DISPOSITION 0x00000005 - -// CreateOption values for NtCreateFile() -// FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT is what CreateFile -// uses for most things when translating to NtCreateFile. -#define FILE_DIRECTORY_FILE 0x00000001 -#define FILE_WRITE_THROUGH 0x00000002 -#define FILE_SEQUENTIAL_ONLY 0x00000004 -#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 -#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 -#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 -#define FILE_NON_DIRECTORY_FILE 0x00000040 -#define FILE_CREATE_TREE_CONNECTION 0x00000080 -#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 -#define FILE_NO_EA_KNOWLEDGE 0x00000200 -#define FILE_OPEN_FOR_RECOVERY 0x00000400 -#define FILE_RANDOM_ACCESS 0x00000800 -#define FILE_DELETE_ON_CLOSE 0x00001000 -#define FILE_OPEN_BY_FILE_ID 0x00002000 -#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 -#define FILE_NO_COMPRESSION 0x00008000 -#define FILE_RESERVE_OPFILTER 0x00100000 -#define FILE_OPEN_REPARSE_POINT 0x00200000 -#define FILE_OPEN_NO_RECALL 0x00400000 -#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 -#define FILE_COPY_STRUCTURED_STORAGE 0x00000041 -#define FILE_STRUCTURED_STORAGE 0x00000441 -#define FILE_VALID_OPTION_FLAGS 0x00ffffff -#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 -#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 -#define FILE_VALID_SET_FLAGS 0x00000036 - - -// NtQueryVolumeInformation / NtSetVolumeInformation stuff -// Type of information to retrieve; FileFsSizeInformation and -// FileFsDeviceInformation are the only ones confirmed to work. -typedef enum _FSINFOCLASS { - FileFsVolumeInformation = 1, - FileFsLabelInformation, - FileFsSizeInformation, - FileFsDeviceInformation, - FileFsAttributeInformation, - FileFsControlInformation, - FileFsFullSizeInformation, - FileFsObjectInformation -} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; - -// Structure of FileFsSizeInformation -typedef struct _FILE_FS_SIZE_INFORMATION { - LARGE_INTEGER TotalAllocationUnits; - LARGE_INTEGER AvailableAllocationUnits; - ULONG SectorsPerAllocationUnit; - ULONG BytesPerSector; -} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; - -#define DEVICE_TYPE ULONG - -// Structure of FileFsDeviceInformation -typedef struct _FILE_FS_DEVICE_INFORMATION { - DEVICE_TYPE DeviceType; - ULONG Characteristics; -} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; - -// DEVICE_TYPEs (I took a guess as to which the XBOX might have.) -#define FILE_DEVICE_CD_ROM 0x00000002 -#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 -#define FILE_DEVICE_CONTROLLER 0x00000004 -#define FILE_DEVICE_DISK 0x00000007 -#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 -#define FILE_DEVICE_FILE_SYSTEM 0x00000009 -#define FILE_DEVICE_NULL 0x00000015 -#define FILE_DEVICE_SCREEN 0x0000001c -#define FILE_DEVICE_SOUND 0x0000001d -#define FILE_DEVICE_UNKNOWN 0x00000022 -#define FILE_DEVICE_VIDEO 0x00000023 -#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 -#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 - -// Characteristics -#define FILE_REMOVABLE_MEDIA 0x00000001 -#define FILE_READ_ONLY_DEVICE 0x00000002 -#define FILE_FLOPPY_DISKETTE 0x00000004 -#define FILE_WRITE_ONCE_MEDIA 0x00000008 -#define FILE_REMOTE_DEVICE 0x00000010 -#define FILE_DEVICE_IS_MOUNTED 0x00000020 -#define FILE_VIRTUAL_VOLUME 0x00000040 -#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 -#define FILE_DEVICE_SECURE_OPEN 0x00000100 - -/* Physical address - * Differences from NT: 32 bit address instead of 64. */ -typedef ULONG PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; - -/* NtCreateFile/NtOpenFile stuff */ -#define FILE_SUPERSEDED 0x00000000 -#define FILE_OPENED 0x00000001 -#define FILE_CREATED 0x00000002 -#define FILE_OVERWRITTEN 0x00000003 -#define FILE_EXISTS 0x00000004 -#define FILE_DOES_NOT_EXIST 0x00000005 - -// NtReadFile/NtWriteFile stuff -#define FILE_WRITE_TO_END_OF_FILE 0xffffffff -#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe - -// Device types -#define FILE_DEVICE_CD_ROM 0x00000002 -#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 -#define FILE_DEVICE_CONTROLLER 0x00000004 -#define FILE_DEVICE_SCSI FILE_DEVICE_CONTROLLER -#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER -#define FILE_DEVICE_DISK 0x00000007 -#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 -#define FILE_DEVICE_DVD 0x00000033 - -// Access types -#define FILE_ANY_ACCESS 0 -#define FILE_READ_ACCESS 0x0001 /* file & pipe */ -#define FILE_WRITE_ACCESS 0x0002 /* file & pipe */ - -// Method types -#define METHOD_BUFFERED 0 -#define METHOD_IN_DIRECT 1 -#define METHOD_OUT_DIRECT 2 -#define METHOD_NEITHER 3 - -// The all-important CTL_CODE -#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) - -// IDE/SCSI codes -// IOCTL_SCSI_PASS_THROUGH_DIRECT is the only one known to be used. -// Differences from NT: None. -#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_FREE_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_IDE_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// Special XBOX code? -#define IOCTL_CDROM_AUTHENTICATE_DISK CTL_CODE(FILE_DEVICE_CD_ROM, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) - -/* Structure for IOCTL_SCSI_PASS_THROUGH_DIRECT - * Differences from NT: None, believe it or not. */ -typedef struct _SCSI_PASS_THROUGH_DIRECT { - /*000*/ USHORT Length; - /*002*/ UCHAR ScsiStatus; - /*003*/ UCHAR PathId; - /*004*/ UCHAR TargetId; - /*005*/ UCHAR Lun; - /*006*/ UCHAR CdbLength; - /*007*/ UCHAR SenseInfoLength; - /*008*/ UCHAR DataIn; - /*00C*/ ULONG DataTransferLength; - /*010*/ ULONG TimeOutValue; - /*014*/ PVOID DataBuffer; - /*018*/ ULONG SenseInfoOffset; - /*01C*/ UCHAR Cdb[16]; -}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; - -/* DataIn fields for IOCTL_SCSI_PASS_THROUGH_DIRECT */ -#define SCSI_IOCTL_DATA_OUT 0 -#define SCSI_IOCTL_DATA_IN 1 -#define SCSI_IOCTL_DATA_UNSPECIFIED 2 - -/* Kernel object type (unsure about the structure...) */ -typedef struct _OBJECT_TYPE -{ - // Same prototype as ExAllocatePoolWithTag, because that's the usual one - PVOID - (NTAPI *AllocationFunction)( - SIZE_T NumberOfBytes, - ULONG Tag - ); - - // Same prototype as ExFreePool, because that's the usual one - VOID - (NTAPI *FreeFunction)( - IN PVOID P - ); - - // The prototypes of these are unknown - void *CloseFunction; - void *DeleteFunction; - void *ParseFunction; - - // Unknown DWORD... Size of this object type maybe? - void *DefaultObjectMaybe; - - // 4 letter tag for this object type - CHAR Tag[4]; -} OBJECT_TYPE; -typedef OBJECT_TYPE *POBJECT_TYPE; - -// Object types -extern POBJECT_TYPE IoFileObjectType; -extern POBJECT_TYPE ExEventObjectType; -extern POBJECT_TYPE ExSemaphoreObjectType; -extern POBJECT_TYPE IoCompletionObjectType; -extern POBJECT_TYPE IoDeviceObjectType; - - -// *_OBJECT and related structures (mostly opaque since I'm lazy) -typedef struct _DRIVER_OBJECT { - CSHORT Type; - CSHORT Size; - struct _DEVICE_OBJECT *DeviceObject; - // ... -} DRIVER_OBJECT; -typedef DRIVER_OBJECT *PDRIVER_OBJECT; - -typedef struct _DEVICE_OBJECT { - CSHORT Type; - USHORT Size; - LONG ReferenceCount; - PDRIVER_OBJECT DriverObject; - // ... -} DEVICE_OBJECT; -typedef DEVICE_OBJECT *PDEVICE_OBJECT; - -typedef struct _FILE_OBJECT { - CSHORT Type; - CSHORT Size; - PDEVICE_OBJECT DeviceObject; - // ... -} FILE_OBJECT; -typedef FILE_OBJECT *PFILE_OBJECT; - - -/* Thread information structures */ - -/* IRQL */ -typedef UCHAR KIRQL, *PKIRQL; -#define PASSIVE_LEVEL 0 // Passive release level -#define LOW_LEVEL 0 // Lowest interrupt level -#define APC_LEVEL 1 // APC interrupt level -#define DISPATCH_LEVEL 2 // Dispatcher level - -// Thread entry point -// NOTE: This is not a standard call! You can't call this function from C code! -// You push registers like stdcall, but ebp + 4 must point to the first argument before the call! -// -// Differences from NT: 2 parameters instead of 1; strange calling convention -typedef -VOID -(NTAPI *PKSTART_ROUTINE) ( - IN PVOID StartContext1, - IN PVOID StartContext2 - ); - -// Structure of a critical section -// Same as the XBOX's RTL_CRITICAL_SECTION, but with the more explicit header -typedef struct _KCRITICAL_SECTION -{ - // 000 Dispatcher header - DISPATCHER_HEADER Header; - // 010 Lock count of the critical section - LONG LockCount; - // 014 Recursion count of the critical section - LONG RecursionCount; - // 018 Thread ID of the thread that currently owns this critical section - ULONG OwningThread; -} KCRITICAL_SECTION, *PKCRITICAL_SECTION; - -// Structure of a thread object -typedef struct _KTHREAD -{ - // 000 Dispatcher header - DISPATCHER_HEADER Header; - // 010 Unknown - BYTE unknown[0x18]; - // 028 Pointer to TLS data - PVOID TlsData; - // ??? just padding - real size is unknown - BYTE unknown2[0x100]; -} KTHREAD, *PKTHREAD; - -// Structure of the data at FS -typedef struct _FS_STRUCTURE -{ - // 000 Current exception handler information - PVOID *ExceptionFrame; - // 004 Pointer to current TLS data top - PVOID TlsDataTop; - // 008 - BYTE unknown2[0x1C]; - // 024 Current IRQL of the OS - KIRQL CurrentIrql; - // 028 Thread structure of the current thread - PKTHREAD ThreadObject; - // ??? just padding - real size is unknown - BYTE unknown3[0x100]; -} FS_STRUCTURE, *PFS_STRUCTURE; - -// DPC routine -typedef -VOID -(*PKDEFERRED_ROUTINE) ( - IN struct _KDPC *Dpc, - IN PVOID DeferredContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2 - ); - -// DPC information -// It's not known which of these fields are used on XBOX. -typedef struct _KDPC { - CSHORT Type; - UCHAR Number; - UCHAR Importance; - LIST_ENTRY DpcListEntry; - PKDEFERRED_ROUTINE DeferredRoutine; - PVOID DeferredContext; - PVOID SystemArgument1; - PVOID SystemArgument2; - PULONG_PTR Lock; -} KDPC, *PKDPC; - - -// Timers -typedef enum _TIMER_TYPE { - NotificationTimer, - SynchronizationTimer - } TIMER_TYPE; - -typedef struct _KTIMER { - DISPATCHER_HEADER Header; - ULARGE_INTEGER DueTime; - LIST_ENTRY TimerListEntry; - struct _KDPC *Dpc; - LONG Period; -} KTIMER, *PKTIMER; - -/* XBE stuff - * Not used in any exported kernel calls, but still useful. - */ - -/* XBE header information */ -typedef struct _XBE_HEADER -{ - // 000 "XBEH" - CHAR Magic[4]; - // 004 RSA digital signature of the entire header area - UCHAR HeaderSignature[256]; - // 104 Base address of XBE image (must be 0x00010000?) - PVOID BaseAddress; - // 108 Size of all headers combined - other headers must be within this - ULONG HeaderSize; - // 10C Size of entire image - ULONG ImageSize; - // 110 Size of this header (always 0x178?) - ULONG XbeHeaderSize; - // 114 Image timestamp - unknown format - ULONG Timestamp; - // 118 Pointer to certificate data (must be within HeaderSize) - struct _XBE_CERTIFICATE *Certificate; - // 11C Number of sections - DWORD NumSections; - // 120 Pointer to section headers (must be within HeaderSize) - struct _XBE_SECTION *Sections; - // 124 Initialization flags - ULONG InitFlags; - // 128 Entry point (XOR'd; see xboxhacker.net) - PVOID EntryPoint; - // 12C Pointer to TLS directory - struct _XBE_TLS_DIRECTORY *TlsDirectory; - // 130 Stack commit size - ULONG StackCommit; - // 134 Heap reserve size - ULONG HeapReserve; - // 138 Heap commit size - ULONG HeapCommit; - // 13C PE base address (?) - PVOID PeBaseAddress; - // 140 PE image size (?) - ULONG PeImageSize; - // 144 PE checksum (?) - ULONG PeChecksum; - // 148 PE timestamp (?) - ULONG PeTimestamp; - // 14C PC path and filename to EXE file from which XBE is derived - PCSZ PcExePath; - // 150 PC filename (last part of PcExePath) from which XBE is derived - PCSZ PcExeFilename; - // 154 PC filename (Unicode version of PcExeFilename) - PWSTR PcExeFilenameUnicode; - // 158 Pointer to kernel thunk table (XOR'd; EFB1F152 debug) - ULONG_PTR *KernelThunkTable; - // 15C Non-kernel import table (debug only) - PVOID DebugImportTable; - // 160 Number of library headers - ULONG NumLibraries; - // 164 Pointer to library headers - struct _XBE_LIBRARY *Libraries; - // 168 Pointer to kernel library header - struct _XBE_LIBRARY *KernelLibrary; - // 16C Pointer to XAPI library - struct _XBE_LIBRARY *XapiLibrary; - // 170 Pointer to logo bitmap (NULL = use default of Microsoft) - PVOID LogoBitmap; - // 174 Size of logo bitmap - ULONG LogoBitmapSize; - // 178 -} XBE_HEADER, *PXBE_HEADER; - -// Certificate structure -typedef struct _XBE_CERTIFICATE { - // 000 Size of certificate - ULONG Size; - // 004 Certificate timestamp (unknown format) - ULONG Timestamp; - // 008 Title ID - ULONG TitleId; - // 00C Name of the game (Unicode) - WCHAR TitleName[40]; - // 05C Alternate title ID's (0-terminated) - ULONG AlternateTitleIds[16]; - // 09C Allowed media types - 1 bit match between XBE and media = boots - ULONG MediaTypes; - // 0A0 Allowed game regions - 1 bit match between this and XBOX = boots - ULONG GameRegion; - // 0A4 Allowed game ratings - 1 bit match between this and XBOX = boots - ULONG GameRating; - // 0A8 Disk number (?) - ULONG DiskNumber; - // 0AC Version (?) - ULONG Version; - // 0B0 LAN key for this game - UCHAR LanKey[16]; - // 0C0 Signature key for this game - UCHAR SignatureKey[16]; - // 0D0 Signature keys for the alternate title ID's - UCHAR AlternateSignatureKeys[16][16]; - // 1D0 -} XBE_CERTIFICATE, *PXBE_CERTIFICATE; - -// Section headers -typedef struct _XBE_SECTION { - // 000 Flags - ULONG Flags; - // 004 Virtual address (where this section loads in RAM) - PVOID VirtualAddress; - // 008 Virtual size (size of section in RAM; after FileSize it's 00'd) - ULONG VirtualSize; - // 00C File address (where in the file from which this section comes) - ULONG FileAddress; - // 010 File size (size of the section in the XBE file) - ULONG FileSize; - // 014 Pointer to section name - PCSZ SectionName; - // 018 Section reference count - when >= 1, section is loaded - LONG SectionReferenceCount; - // 01C Pointer to head shared page reference count - WORD *HeadReferenceCount; - // 020 Pointer to tail shared page reference count - WORD *TailReferenceCount; - // 024 SHA hash. Hash DWORD containing FileSize, then hash section. - DWORD ShaHash[5]; - // 038 -} XBE_SECTION, *PXBE_SECTION; - -/* TLS directory information needed later - * Library version data needed later */ - -/* Initialization flags */ -#define XBE_INIT_MOUNT_UTILITY 0x00000001 -#define XBE_INIT_FORMAT_UTILITY 0x00000002 -#define XBE_INIT_64M_RAM_ONLY 0x00000004 -#define XBE_INIT_DONT_SETUP_HDD 0x00000008 - -/* Region codes */ -#define XBE_REGION_US_CANADA 0x00000001 -#define XBE_REGION_JAPAN 0x00000002 -#define XBE_REGION_ELSEWHERE 0x00000004 -#define XBE_REGION_DEBUG 0x80000000 - -/* Media types */ -#define XBE_MEDIA_HDD 0x00000001 -#define XBE_MEDIA_XBOX_DVD 0x00000002 -#define XBE_MEDIA_ANY_CD_OR_DVD 0x00000004 -#define XBE_MEDIA_CD 0x00000008 -#define XBE_MEDIA_1LAYER_DVDROM 0x00000010 -#define XBE_MEDIA_2LAYER_DVDROM 0x00000020 -#define XBE_MEDIA_1LAYER_DVDR 0x00000040 -#define XBE_MEDIA_2LAYER_DVDR 0x00000080 -#define XBE_MEDIA_USB 0x00000100 -#define XBE_MEDIA_ALLOW_UNLOCKED_HDD 0x40000000 - -/* Section flags */ -#define XBE_SEC_WRITABLE 0x00000001 -#define XBE_SEC_PRELOAD 0x00000002 -#define XBE_SEC_EXECUTABLE 0x00000004 -#define XBE_SEC_INSERTED_FILE 0x00000008 -#define XBE_SEC_RO_HEAD_PAGE 0x00000010 -#define XBE_SEC_RO_TAIL_PAGE 0x00000020 - -/* x86 page size */ -#define PAGE_SIZE 0x1000 - -/* Native NT API calls on the XBOX */ - -/* PAGE_ALIGN: - * Returns an address rounded down to the nearest page boundary. - * - * Differences from NT: None. - */ -#define PAGE_ALIGN(Va) ((PVOID)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1))) - -// NtReadFile: -// Reads a file. -// -// Differences from NT: There is no Key parameter. -NTSYSAPI -EXPORTNUM(219) -NTSTATUS -NTAPI -NtReadFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG Length, - IN PLARGE_INTEGER ByteOffset - ); - -// NtWriteFile: -// Writes a file. -// -// Differences from NT: There is no Key parameter. -NTSYSAPI -EXPORTNUM(236) -NTSTATUS -NTAPI -NtWriteFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID Buffer, - IN ULONG Length, - IN PLARGE_INTEGER ByteOffset - ); - -// NtQueryVolumeInformation: -// Queries information about a file system. This is not documented by -// Microsoft even under NT. -// -// Differences from NT: None known. -NTSYSAPI -EXPORTNUM(218) -NTSTATUS -NTAPI -NtQueryVolumeInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID VolumeInformation, - IN ULONG VolumeInformationLength, - IN FS_INFORMATION_CLASS VolumeInformationClass - ); - -// NtClose: -// Closes a file or other handle. -// -// Differences from NT: None. -NTSYSAPI -EXPORTNUM(187) -NTSTATUS -NTAPI -NtClose( - IN HANDLE Handle - ); - -// NtAllocateVirtualMemory: -// Allocates virtual memory. -// -// Differences from NT: There is no ProcessHandle parameter. -NTSYSAPI -EXPORTNUM(184) -NTSTATUS -NTAPI -NtAllocateVirtualMemory( - IN OUT PVOID *BaseAddress, - IN ULONG ZeroBits, - IN OUT PULONG AllocationSize, - IN ULONG AllocationType, - IN ULONG Protect - ); - -// NtFreeVirtualMemory: -// Frees virtual memory. -// -// Differences from NT: There is no ProcessHandle parameter. -NTSYSAPI -EXPORTNUM(199) -NTSTATUS -NTAPI -NtFreeVirtualMemory( - IN OUT PVOID *BaseAddress, - IN OUT PULONG FreeSize, - IN ULONG FreeType - ); - - -// Kernel-level routines - -// MmMapIoSpace: -// Maps a physical address area into the virtual address space. -// DO NOT USE MEMORY MAPPED WITH THIS AS A BUFFER TO OTHER CALLS. For -// example, don't WriteFile or NtWriteFile these buffers. Copy them first. -// -// Differences from NT: PhysicalAddress is 32 bit, not 64. ProtectionType -// specifies the page protections, but it's a Win32 PAGE_ macro instead -// of the normal NT enumeration. PAGE_READWRITE is probably what you -// want... -NTSYSAPI -EXPORTNUM(177) -PVOID -NTAPI -MmMapIoSpace( - IN PHYSICAL_ADDRESS PhysicalAddress, - IN ULONG NumberOfBytes, - IN ULONG ProtectionType - ); - -// MmGetPhysicalAddress: -// Translates a virtual address into a physical address. -// -// Differences from NT: PhysicalAddress is 32 bit, not 64. -NTSYSAPI -EXPORTNUM(173) -PHYSICAL_ADDRESS -NTAPI -MmGetPhysicalAddress( - IN PVOID BaseAddress - ); - -// MmUnmapIoSpace: -// Unmaps a virtual address mapping made by MmMapIoSpace. -// -// Differences from NT: None. -NTSYSAPI -EXPORTNUM(183) -PVOID -NTAPI -MmUnmapIoSpace( - IN PVOID BaseAddress, - IN ULONG NumberOfBytes - ); - -// MmAllocateContiguousMemory: -// Allocates a range of physically contiguous, cache-aligned memory from the -// non-paged pool (= main pool on XBOX). -// -// Differences from NT: HighestAcceptableAddress was deleted, opting instead -// to not care about the highest address. -NTSYSAPI -EXPORTNUM(165) -PVOID -NTAPI -MmAllocateContiguousMemory( - IN ULONG NumberOfBytes - ); - -// MmFreeContiguousMemory: -// Frees memory allocated with MmAllocateContiguousMemory. -// -// Differences from NT: None. -NTSYSAPI -EXPORTNUM(171) -VOID -NTAPI -MmFreeContiguousMemory( - IN PVOID BaseAddress - ); - -// IoCreateSymbolicLink: -// Creates a symbolic link in the object namespace. -// NtCreateSymbolicLinkObject is much harder to use than this simple -// function, so just use this one. -// -// Differences from NT: Uses ANSI_STRING instead of UNICODE_STRING. -NTSYSAPI -EXPORTNUM(67) -NTSTATUS -NTAPI -IoCreateSymbolicLink( - IN PANSI_STRING SymbolicLinkName, - IN PANSI_STRING DeviceName - ); - -// IoDeleteSymbolicLink: -// Creates a symbolic link in the object namespace. Deleting symbolic links -// through the Nt* functions is a pain, so use this instead. -// -// Differences from NT: Uses ANSI_STRING instead of UNICODE_STRING. -NTSYSAPI -EXPORTNUM(69) -NTSTATUS -NTAPI -IoDeleteSymbolicLink( - IN PANSI_STRING SymbolicLinkName - ); - - -// ObReferenceObjectByHandle: -// Turns a handle into a kernel object pointer. The ObjectType parameter -// specifies what type of object it is. This function also increments the -// object's reference count. -// -// Differences from NT: There are no DesiredAccess, AccessMode, or -// HandleInformation parameters. -NTSYSAPI -EXPORTNUM(246) -NTSTATUS -NTAPI -ObReferenceObjectByHandle( - IN HANDLE Handle, - IN POBJECT_TYPE ObjectType OPTIONAL, - OUT PVOID *Object - ); - -// ObfReferenceObject/ObReferenceObject: -// Increments the object's reference count. -// -// Differences from NT: None. -#define ObReferenceObject(Object) ObfReferenceObject(Object) -NTSYSAPI -EXPORTNUM(251) -VOID -FASTCALL -ObfReferenceObject( - IN PVOID Object - ); - -// ObfDereferenceObject/ObDereferenceObject: -// Decrements the object's reference count, deleting it if it is now unused. -// -// Differences from NT: None. -#define ObDereferenceObject(a) ObfDereferenceObject(a) -NTSYSAPI -EXPORTNUM(250) -VOID -FASTCALL -ObfDereferenceObject( - IN PVOID Object - ); - -// Kernel routines only in the XBOX - -// HalEnableSecureTrayEject: -// Notifies the SMBUS that ejecting the DVD-ROM should not reset the system. -// Note that this function can't really be called directly... -// -// New to the XBOX. -NTSYSAPI -EXPORTNUM(365) -VOID -NTAPI -HalEnableSecureTrayEject( - VOID - ); - -// XeLoadSection: -// Adds one to the reference count of the specified section and loads if the -// count is now above zero. -// -// New to the XBOX. -NTSYSAPI -EXPORTNUM(327) -NTSTATUS -NTAPI -XeLoadSection( - IN OUT PXBE_SECTION section - ); - -/* Error codes */ -#define STATUS_SUCCESS 0x00000000 -#define STATUS_UNSUCCESSFUL 0xC0000001 -#define STATUS_UNRECOGNIZED_MEDIA 0xC0000014 - -/* The SCSI input buffer was too large (not necessarily an error!) */ -#define STATUS_DATA_OVERRUN 0xC000003C -#define STATUS_INVALID_IMAGE_FORMAT 0xC000007B -#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A -#define STATUS_TOO_MANY_SECRETS 0xC0000156 -#define STATUS_REGION_MISMATCH 0xC0050001 - -#include - - // Thanks and credit go to Woodoo - extern VOID WINAPI HalWriteSMBusValue(BYTE, BYTE, BOOL, BYTE); - extern VOID WINAPI HalReadSMCTrayState(DWORD* state, DWORD* count); - - // Thanks and credit go to Team Evox - extern VOID WINAPI HalReturnToFirmware(DWORD); - - extern INT WINAPI XNetLoadConfigParams(LPBYTE); - extern INT WINAPI XNetSaveConfigParams(LPBYTE); - - extern INT WINAPI XWriteTitleInfoNoReboot(LPVOID,LPVOID,DWORD,DWORD,LPVOID); - - extern DWORD* LaunchDataPage; - -static HRESULT xbox_io_mount(char *szDrive, char *szDevice) -{ - STRING DeviceName, LinkName; -#ifndef IS_SALAMANDER - bool original_verbose = verbosity_is_enabled(); -#endif - char szSourceDevice[48] = {0}; - char szDestinationDrive[16] = {0}; - - snprintf(szSourceDevice, sizeof(szSourceDevice), - "\\Device\\%s", szDevice); - snprintf(szDestinationDrive, sizeof(szDestinationDrive), - "\\??\\%s", szDrive); - - DeviceName.Length = strlen(szSourceDevice); - DeviceName.MaximumLength = strlen(szSourceDevice) + 1; - DeviceName.Buffer = szSourceDevice; - - LinkName.Length = strlen(szDestinationDrive); - LinkName.MaximumLength = strlen(szDestinationDrive) + 1; - LinkName.Buffer = szDestinationDrive; - - IoCreateSymbolicLink(&LinkName, &DeviceName); - -#ifndef IS_SALAMANDER - if (original_verbose) - verbosity_enable(); - else - verbosity_disable(); -#endif - return S_OK; -} - -static HRESULT xbox_io_unmount(char *szDrive) -{ - STRING LinkName; - char szDestinationDrive[16] = {0}; - - snprintf(szDestinationDrive, sizeof(szDestinationDrive), - "\\??\\%s", szDrive); - - LinkName.Length = strlen(szDestinationDrive); - LinkName.MaximumLength = strlen(szDestinationDrive) + 1; - LinkName.Buffer = szDestinationDrive; - - IoDeleteSymbolicLink(&LinkName); - - return S_OK; -} -#endif - -#ifdef _XBOX360 -typedef struct _STRING -{ - USHORT Length; - USHORT MaximumLength; - PCHAR Buffer; -} STRING, *PSTRING; - -VOID RtlInitAnsiString(PSTRING DestinationString, PCHAR SourceString); -HRESULT ObDeleteSymbolicLink(PSTRING SymbolicLinkName); -HRESULT ObCreateSymbolicLink(PSTRING SymbolicLinkName, PSTRING DeviceName); - -static HRESULT xbox_io_mount(const char* szDrive, char* szDevice) -{ - STRING DeviceName, LinkName; - char szDestinationDrive[PATH_MAX_LENGTH]; - - snprintf(szDestinationDrive, sizeof(szDestinationDrive), - "\\??\\%s", szDrive); - RtlInitAnsiString(&DeviceName, szDevice); - RtlInitAnsiString(&LinkName, (PCHAR)szDestinationDrive); - ObDeleteSymbolicLink(&LinkName); - return (HRESULT)ObCreateSymbolicLink(&LinkName, &DeviceName); -} -#endif +#ifdef _XBOX1 +#include + +// Don't do __declspec(dllimport) for things like emulators +#if defined(NTSYSAPI) && defined(DONT_IMPORT_INTERNAL) +#undef NTSYSAPI +#endif +#ifdef DONT_IMPORT_INTERNAL +#define NTSYSAPI +#endif + +// The normal headers don't have this...? +#define FASTCALL __fastcall + +// The usual NTSTATUS +typedef LONG NTSTATUS; + +// The usual NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) + +// Just for documentation +#define EXPORTNUM(x) + + +// Needed for object structures and related things +typedef CONST SHORT CSHORT; + + +// String types +typedef CHAR *PSZ; +typedef CONST CHAR *PCSZ; + +// ANSI_STRING +// Differences from NT: None. +typedef struct _STRING { + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; +} STRING; +typedef STRING *PSTRING; + +typedef STRING ANSI_STRING; +typedef PSTRING PANSI_STRING; + + +// IO Status Block type (UNVERIFIED) +// Differences from NT: None. +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +// APC routine +typedef +VOID +(NTAPI *PIO_APC_ROUTINE) ( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved + ); + + +// Header for dispatcher objects +// Differences from NT: None. +typedef struct _DISPATCHER_HEADER { + UCHAR Type; + UCHAR Absolute; + UCHAR Size; + UCHAR Inserted; + LONG SignalState; + LIST_ENTRY WaitListHead; +} DISPATCHER_HEADER; + + +// Object types +#define NotificationTimerObject 8 +#define SynchronizationTimerObject 9 +#define DpcObject 19 + + +// Object Attributes type +// Differences from NT: There are no Length, SecurityDescriptor, or +// SecurityQualityOfService fields. Also, ObjectName is ANSI, not +// Unicode. +typedef struct _OBJECT_ATTRIBUTES { + HANDLE RootDirectory; + PANSI_STRING ObjectName; + ULONG Attributes; +} OBJECT_ATTRIBUTES; +typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; + +// Flags for OBJECT_ATTRIBUTES::Attributes +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_VALID_ATTRIBUTES 0x000003F2L + +// CreateDisposition values for NtCreateFile() +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +// CreateOption values for NtCreateFile() +// FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT is what CreateFile +// uses for most things when translating to NtCreateFile. +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 +#define FILE_COPY_STRUCTURED_STORAGE 0x00000041 +#define FILE_STRUCTURED_STORAGE 0x00000441 +#define FILE_VALID_OPTION_FLAGS 0x00ffffff +#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 +#define FILE_VALID_SET_FLAGS 0x00000036 + + +// NtQueryVolumeInformation / NtSetVolumeInformation stuff +// Type of information to retrieve; FileFsSizeInformation and +// FileFsDeviceInformation are the only ones confirmed to work. +typedef enum _FSINFOCLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +// Structure of FileFsSizeInformation +typedef struct _FILE_FS_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +#define DEVICE_TYPE ULONG + +// Structure of FileFsDeviceInformation +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +// DEVICE_TYPEs (I took a guess as to which the XBOX might have.) +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 + +// Characteristics +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_READ_ONLY_DEVICE 0x00000002 +#define FILE_FLOPPY_DISKETTE 0x00000004 +#define FILE_WRITE_ONCE_MEDIA 0x00000008 +#define FILE_REMOTE_DEVICE 0x00000010 +#define FILE_DEVICE_IS_MOUNTED 0x00000020 +#define FILE_VIRTUAL_VOLUME 0x00000040 +#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 +#define FILE_DEVICE_SECURE_OPEN 0x00000100 + +/* Physical address + * Differences from NT: 32 bit address instead of 64. */ +typedef ULONG PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; + +/* NtCreateFile/NtOpenFile stuff */ +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +// NtReadFile/NtWriteFile stuff +#define FILE_WRITE_TO_END_OF_FILE 0xffffffff +#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe + +// Device types +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_SCSI FILE_DEVICE_CONTROLLER +#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_DVD 0x00000033 + +// Access types +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS 0x0001 /* file & pipe */ +#define FILE_WRITE_ACCESS 0x0002 /* file & pipe */ + +// Method types +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +// The all-important CTL_CODE +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +// IDE/SCSI codes +// IOCTL_SCSI_PASS_THROUGH_DIRECT is the only one known to be used. +// Differences from NT: None. +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_FREE_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IDE_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// Special XBOX code? +#define IOCTL_CDROM_AUTHENTICATE_DISK CTL_CODE(FILE_DEVICE_CD_ROM, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) + +/* Structure for IOCTL_SCSI_PASS_THROUGH_DIRECT + * Differences from NT: None, believe it or not. */ +typedef struct _SCSI_PASS_THROUGH_DIRECT { + /*000*/ USHORT Length; + /*002*/ UCHAR ScsiStatus; + /*003*/ UCHAR PathId; + /*004*/ UCHAR TargetId; + /*005*/ UCHAR Lun; + /*006*/ UCHAR CdbLength; + /*007*/ UCHAR SenseInfoLength; + /*008*/ UCHAR DataIn; + /*00C*/ ULONG DataTransferLength; + /*010*/ ULONG TimeOutValue; + /*014*/ PVOID DataBuffer; + /*018*/ ULONG SenseInfoOffset; + /*01C*/ UCHAR Cdb[16]; +}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + +/* DataIn fields for IOCTL_SCSI_PASS_THROUGH_DIRECT */ +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +/* Kernel object type (unsure about the structure...) */ +typedef struct _OBJECT_TYPE +{ + // Same prototype as ExAllocatePoolWithTag, because that's the usual one + PVOID + (NTAPI *AllocationFunction)( + SIZE_T NumberOfBytes, + ULONG Tag + ); + + // Same prototype as ExFreePool, because that's the usual one + VOID + (NTAPI *FreeFunction)( + IN PVOID P + ); + + // The prototypes of these are unknown + void *CloseFunction; + void *DeleteFunction; + void *ParseFunction; + + // Unknown DWORD... Size of this object type maybe? + void *DefaultObjectMaybe; + + // 4 letter tag for this object type + CHAR Tag[4]; +} OBJECT_TYPE; +typedef OBJECT_TYPE *POBJECT_TYPE; + +// Object types +extern POBJECT_TYPE IoFileObjectType; +extern POBJECT_TYPE ExEventObjectType; +extern POBJECT_TYPE ExSemaphoreObjectType; +extern POBJECT_TYPE IoCompletionObjectType; +extern POBJECT_TYPE IoDeviceObjectType; + + +// *_OBJECT and related structures (mostly opaque since I'm lazy) +typedef struct _DRIVER_OBJECT { + CSHORT Type; + CSHORT Size; + struct _DEVICE_OBJECT *DeviceObject; + // ... +} DRIVER_OBJECT; +typedef DRIVER_OBJECT *PDRIVER_OBJECT; + +typedef struct _DEVICE_OBJECT { + CSHORT Type; + USHORT Size; + LONG ReferenceCount; + PDRIVER_OBJECT DriverObject; + // ... +} DEVICE_OBJECT; +typedef DEVICE_OBJECT *PDEVICE_OBJECT; + +typedef struct _FILE_OBJECT { + CSHORT Type; + CSHORT Size; + PDEVICE_OBJECT DeviceObject; + // ... +} FILE_OBJECT; +typedef FILE_OBJECT *PFILE_OBJECT; + + +/* Thread information structures */ + +/* IRQL */ +typedef UCHAR KIRQL, *PKIRQL; +#define PASSIVE_LEVEL 0 // Passive release level +#define LOW_LEVEL 0 // Lowest interrupt level +#define APC_LEVEL 1 // APC interrupt level +#define DISPATCH_LEVEL 2 // Dispatcher level + +// Thread entry point +// NOTE: This is not a standard call! You can't call this function from C code! +// You push registers like stdcall, but ebp + 4 must point to the first argument before the call! +// +// Differences from NT: 2 parameters instead of 1; strange calling convention +typedef +VOID +(NTAPI *PKSTART_ROUTINE) ( + IN PVOID StartContext1, + IN PVOID StartContext2 + ); + +// Structure of a critical section +// Same as the XBOX's RTL_CRITICAL_SECTION, but with the more explicit header +typedef struct _KCRITICAL_SECTION +{ + // 000 Dispatcher header + DISPATCHER_HEADER Header; + // 010 Lock count of the critical section + LONG LockCount; + // 014 Recursion count of the critical section + LONG RecursionCount; + // 018 Thread ID of the thread that currently owns this critical section + ULONG OwningThread; +} KCRITICAL_SECTION, *PKCRITICAL_SECTION; + +// Structure of a thread object +typedef struct _KTHREAD +{ + // 000 Dispatcher header + DISPATCHER_HEADER Header; + // 010 Unknown + BYTE unknown[0x18]; + // 028 Pointer to TLS data + PVOID TlsData; + // ??? just padding - real size is unknown + BYTE unknown2[0x100]; +} KTHREAD, *PKTHREAD; + +// Structure of the data at FS +typedef struct _FS_STRUCTURE +{ + // 000 Current exception handler information + PVOID *ExceptionFrame; + // 004 Pointer to current TLS data top + PVOID TlsDataTop; + // 008 + BYTE unknown2[0x1C]; + // 024 Current IRQL of the OS + KIRQL CurrentIrql; + // 028 Thread structure of the current thread + PKTHREAD ThreadObject; + // ??? just padding - real size is unknown + BYTE unknown3[0x100]; +} FS_STRUCTURE, *PFS_STRUCTURE; + +// DPC routine +typedef +VOID +(*PKDEFERRED_ROUTINE) ( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + +// DPC information +// It's not known which of these fields are used on XBOX. +typedef struct _KDPC { + CSHORT Type; + UCHAR Number; + UCHAR Importance; + LIST_ENTRY DpcListEntry; + PKDEFERRED_ROUTINE DeferredRoutine; + PVOID DeferredContext; + PVOID SystemArgument1; + PVOID SystemArgument2; + PULONG_PTR Lock; +} KDPC, *PKDPC; + + +// Timers +typedef enum _TIMER_TYPE { + NotificationTimer, + SynchronizationTimer + } TIMER_TYPE; + +typedef struct _KTIMER { + DISPATCHER_HEADER Header; + ULARGE_INTEGER DueTime; + LIST_ENTRY TimerListEntry; + struct _KDPC *Dpc; + LONG Period; +} KTIMER, *PKTIMER; + +/* XBE stuff + * Not used in any exported kernel calls, but still useful. + */ + +/* XBE header information */ +typedef struct _XBE_HEADER +{ + // 000 "XBEH" + CHAR Magic[4]; + // 004 RSA digital signature of the entire header area + UCHAR HeaderSignature[256]; + // 104 Base address of XBE image (must be 0x00010000?) + PVOID BaseAddress; + // 108 Size of all headers combined - other headers must be within this + ULONG HeaderSize; + // 10C Size of entire image + ULONG ImageSize; + // 110 Size of this header (always 0x178?) + ULONG XbeHeaderSize; + // 114 Image timestamp - unknown format + ULONG Timestamp; + // 118 Pointer to certificate data (must be within HeaderSize) + struct _XBE_CERTIFICATE *Certificate; + // 11C Number of sections + DWORD NumSections; + // 120 Pointer to section headers (must be within HeaderSize) + struct _XBE_SECTION *Sections; + // 124 Initialization flags + ULONG InitFlags; + // 128 Entry point (XOR'd; see xboxhacker.net) + PVOID EntryPoint; + // 12C Pointer to TLS directory + struct _XBE_TLS_DIRECTORY *TlsDirectory; + // 130 Stack commit size + ULONG StackCommit; + // 134 Heap reserve size + ULONG HeapReserve; + // 138 Heap commit size + ULONG HeapCommit; + // 13C PE base address (?) + PVOID PeBaseAddress; + // 140 PE image size (?) + ULONG PeImageSize; + // 144 PE checksum (?) + ULONG PeChecksum; + // 148 PE timestamp (?) + ULONG PeTimestamp; + // 14C PC path and filename to EXE file from which XBE is derived + PCSZ PcExePath; + // 150 PC filename (last part of PcExePath) from which XBE is derived + PCSZ PcExeFilename; + // 154 PC filename (Unicode version of PcExeFilename) + PWSTR PcExeFilenameUnicode; + // 158 Pointer to kernel thunk table (XOR'd; EFB1F152 debug) + ULONG_PTR *KernelThunkTable; + // 15C Non-kernel import table (debug only) + PVOID DebugImportTable; + // 160 Number of library headers + ULONG NumLibraries; + // 164 Pointer to library headers + struct _XBE_LIBRARY *Libraries; + // 168 Pointer to kernel library header + struct _XBE_LIBRARY *KernelLibrary; + // 16C Pointer to XAPI library + struct _XBE_LIBRARY *XapiLibrary; + // 170 Pointer to logo bitmap (NULL = use default of Microsoft) + PVOID LogoBitmap; + // 174 Size of logo bitmap + ULONG LogoBitmapSize; + // 178 +} XBE_HEADER, *PXBE_HEADER; + +// Certificate structure +typedef struct _XBE_CERTIFICATE { + // 000 Size of certificate + ULONG Size; + // 004 Certificate timestamp (unknown format) + ULONG Timestamp; + // 008 Title ID + ULONG TitleId; + // 00C Name of the game (Unicode) + WCHAR TitleName[40]; + // 05C Alternate title ID's (0-terminated) + ULONG AlternateTitleIds[16]; + // 09C Allowed media types - 1 bit match between XBE and media = boots + ULONG MediaTypes; + // 0A0 Allowed game regions - 1 bit match between this and XBOX = boots + ULONG GameRegion; + // 0A4 Allowed game ratings - 1 bit match between this and XBOX = boots + ULONG GameRating; + // 0A8 Disk number (?) + ULONG DiskNumber; + // 0AC Version (?) + ULONG Version; + // 0B0 LAN key for this game + UCHAR LanKey[16]; + // 0C0 Signature key for this game + UCHAR SignatureKey[16]; + // 0D0 Signature keys for the alternate title ID's + UCHAR AlternateSignatureKeys[16][16]; + // 1D0 +} XBE_CERTIFICATE, *PXBE_CERTIFICATE; + +// Section headers +typedef struct _XBE_SECTION { + // 000 Flags + ULONG Flags; + // 004 Virtual address (where this section loads in RAM) + PVOID VirtualAddress; + // 008 Virtual size (size of section in RAM; after FileSize it's 00'd) + ULONG VirtualSize; + // 00C File address (where in the file from which this section comes) + ULONG FileAddress; + // 010 File size (size of the section in the XBE file) + ULONG FileSize; + // 014 Pointer to section name + PCSZ SectionName; + // 018 Section reference count - when >= 1, section is loaded + LONG SectionReferenceCount; + // 01C Pointer to head shared page reference count + WORD *HeadReferenceCount; + // 020 Pointer to tail shared page reference count + WORD *TailReferenceCount; + // 024 SHA hash. Hash DWORD containing FileSize, then hash section. + DWORD ShaHash[5]; + // 038 +} XBE_SECTION, *PXBE_SECTION; + +/* TLS directory information needed later + * Library version data needed later */ + +/* Initialization flags */ +#define XBE_INIT_MOUNT_UTILITY 0x00000001 +#define XBE_INIT_FORMAT_UTILITY 0x00000002 +#define XBE_INIT_64M_RAM_ONLY 0x00000004 +#define XBE_INIT_DONT_SETUP_HDD 0x00000008 + +/* Region codes */ +#define XBE_REGION_US_CANADA 0x00000001 +#define XBE_REGION_JAPAN 0x00000002 +#define XBE_REGION_ELSEWHERE 0x00000004 +#define XBE_REGION_DEBUG 0x80000000 + +/* Media types */ +#define XBE_MEDIA_HDD 0x00000001 +#define XBE_MEDIA_XBOX_DVD 0x00000002 +#define XBE_MEDIA_ANY_CD_OR_DVD 0x00000004 +#define XBE_MEDIA_CD 0x00000008 +#define XBE_MEDIA_1LAYER_DVDROM 0x00000010 +#define XBE_MEDIA_2LAYER_DVDROM 0x00000020 +#define XBE_MEDIA_1LAYER_DVDR 0x00000040 +#define XBE_MEDIA_2LAYER_DVDR 0x00000080 +#define XBE_MEDIA_USB 0x00000100 +#define XBE_MEDIA_ALLOW_UNLOCKED_HDD 0x40000000 + +/* Section flags */ +#define XBE_SEC_WRITABLE 0x00000001 +#define XBE_SEC_PRELOAD 0x00000002 +#define XBE_SEC_EXECUTABLE 0x00000004 +#define XBE_SEC_INSERTED_FILE 0x00000008 +#define XBE_SEC_RO_HEAD_PAGE 0x00000010 +#define XBE_SEC_RO_TAIL_PAGE 0x00000020 + +/* x86 page size */ +#define PAGE_SIZE 0x1000 + +/* Native NT API calls on the XBOX */ + +/* PAGE_ALIGN: + * Returns an address rounded down to the nearest page boundary. + * + * Differences from NT: None. + */ +#define PAGE_ALIGN(Va) ((PVOID)((ULONG_PTR)(Va) & ~(PAGE_SIZE - 1))) + +// NtReadFile: +// Reads a file. +// +// Differences from NT: There is no Key parameter. +NTSYSAPI +EXPORTNUM(219) +NTSTATUS +NTAPI +NtReadFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset + ); + +// NtWriteFile: +// Writes a file. +// +// Differences from NT: There is no Key parameter. +NTSYSAPI +EXPORTNUM(236) +NTSTATUS +NTAPI +NtWriteFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset + ); + +// NtQueryVolumeInformation: +// Queries information about a file system. This is not documented by +// Microsoft even under NT. +// +// Differences from NT: None known. +NTSYSAPI +EXPORTNUM(218) +NTSTATUS +NTAPI +NtQueryVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID VolumeInformation, + IN ULONG VolumeInformationLength, + IN FS_INFORMATION_CLASS VolumeInformationClass + ); + +// NtClose: +// Closes a file or other handle. +// +// Differences from NT: None. +NTSYSAPI +EXPORTNUM(187) +NTSTATUS +NTAPI +NtClose( + IN HANDLE Handle + ); + +// NtAllocateVirtualMemory: +// Allocates virtual memory. +// +// Differences from NT: There is no ProcessHandle parameter. +NTSYSAPI +EXPORTNUM(184) +NTSTATUS +NTAPI +NtAllocateVirtualMemory( + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG AllocationSize, + IN ULONG AllocationType, + IN ULONG Protect + ); + +// NtFreeVirtualMemory: +// Frees virtual memory. +// +// Differences from NT: There is no ProcessHandle parameter. +NTSYSAPI +EXPORTNUM(199) +NTSTATUS +NTAPI +NtFreeVirtualMemory( + IN OUT PVOID *BaseAddress, + IN OUT PULONG FreeSize, + IN ULONG FreeType + ); + + +// Kernel-level routines + +// MmMapIoSpace: +// Maps a physical address area into the virtual address space. +// DO NOT USE MEMORY MAPPED WITH THIS AS A BUFFER TO OTHER CALLS. For +// example, don't WriteFile or NtWriteFile these buffers. Copy them first. +// +// Differences from NT: PhysicalAddress is 32 bit, not 64. ProtectionType +// specifies the page protections, but it's a Win32 PAGE_ macro instead +// of the normal NT enumeration. PAGE_READWRITE is probably what you +// want... +NTSYSAPI +EXPORTNUM(177) +PVOID +NTAPI +MmMapIoSpace( + IN PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG NumberOfBytes, + IN ULONG ProtectionType + ); + +// MmGetPhysicalAddress: +// Translates a virtual address into a physical address. +// +// Differences from NT: PhysicalAddress is 32 bit, not 64. +NTSYSAPI +EXPORTNUM(173) +PHYSICAL_ADDRESS +NTAPI +MmGetPhysicalAddress( + IN PVOID BaseAddress + ); + +// MmUnmapIoSpace: +// Unmaps a virtual address mapping made by MmMapIoSpace. +// +// Differences from NT: None. +NTSYSAPI +EXPORTNUM(183) +PVOID +NTAPI +MmUnmapIoSpace( + IN PVOID BaseAddress, + IN ULONG NumberOfBytes + ); + +// MmAllocateContiguousMemory: +// Allocates a range of physically contiguous, cache-aligned memory from the +// non-paged pool (= main pool on XBOX). +// +// Differences from NT: HighestAcceptableAddress was deleted, opting instead +// to not care about the highest address. +NTSYSAPI +EXPORTNUM(165) +PVOID +NTAPI +MmAllocateContiguousMemory( + IN ULONG NumberOfBytes + ); + +// MmFreeContiguousMemory: +// Frees memory allocated with MmAllocateContiguousMemory. +// +// Differences from NT: None. +NTSYSAPI +EXPORTNUM(171) +VOID +NTAPI +MmFreeContiguousMemory( + IN PVOID BaseAddress + ); + +// IoCreateSymbolicLink: +// Creates a symbolic link in the object namespace. +// NtCreateSymbolicLinkObject is much harder to use than this simple +// function, so just use this one. +// +// Differences from NT: Uses ANSI_STRING instead of UNICODE_STRING. +NTSYSAPI +EXPORTNUM(67) +NTSTATUS +NTAPI +IoCreateSymbolicLink( + IN PANSI_STRING SymbolicLinkName, + IN PANSI_STRING DeviceName + ); + +// IoDeleteSymbolicLink: +// Creates a symbolic link in the object namespace. Deleting symbolic links +// through the Nt* functions is a pain, so use this instead. +// +// Differences from NT: Uses ANSI_STRING instead of UNICODE_STRING. +NTSYSAPI +EXPORTNUM(69) +NTSTATUS +NTAPI +IoDeleteSymbolicLink( + IN PANSI_STRING SymbolicLinkName + ); + + +// ObReferenceObjectByHandle: +// Turns a handle into a kernel object pointer. The ObjectType parameter +// specifies what type of object it is. This function also increments the +// object's reference count. +// +// Differences from NT: There are no DesiredAccess, AccessMode, or +// HandleInformation parameters. +NTSYSAPI +EXPORTNUM(246) +NTSTATUS +NTAPI +ObReferenceObjectByHandle( + IN HANDLE Handle, + IN POBJECT_TYPE ObjectType OPTIONAL, + OUT PVOID *Object + ); + +// ObfReferenceObject/ObReferenceObject: +// Increments the object's reference count. +// +// Differences from NT: None. +#define ObReferenceObject(Object) ObfReferenceObject(Object) +NTSYSAPI +EXPORTNUM(251) +VOID +FASTCALL +ObfReferenceObject( + IN PVOID Object + ); + +// ObfDereferenceObject/ObDereferenceObject: +// Decrements the object's reference count, deleting it if it is now unused. +// +// Differences from NT: None. +#define ObDereferenceObject(a) ObfDereferenceObject(a) +NTSYSAPI +EXPORTNUM(250) +VOID +FASTCALL +ObfDereferenceObject( + IN PVOID Object + ); + +// Kernel routines only in the XBOX + +// HalEnableSecureTrayEject: +// Notifies the SMBUS that ejecting the DVD-ROM should not reset the system. +// Note that this function can't really be called directly... +// +// New to the XBOX. +NTSYSAPI +EXPORTNUM(365) +VOID +NTAPI +HalEnableSecureTrayEject( + VOID + ); + +// XeLoadSection: +// Adds one to the reference count of the specified section and loads if the +// count is now above zero. +// +// New to the XBOX. +NTSYSAPI +EXPORTNUM(327) +NTSTATUS +NTAPI +XeLoadSection( + IN OUT PXBE_SECTION section + ); + +/* Error codes */ +#define STATUS_SUCCESS 0x00000000 +#define STATUS_UNSUCCESSFUL 0xC0000001 +#define STATUS_UNRECOGNIZED_MEDIA 0xC0000014 + +/* The SCSI input buffer was too large (not necessarily an error!) */ +#define STATUS_DATA_OVERRUN 0xC000003C +#define STATUS_INVALID_IMAGE_FORMAT 0xC000007B +#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A +#define STATUS_TOO_MANY_SECRETS 0xC0000156 +#define STATUS_REGION_MISMATCH 0xC0050001 + +#include + + // Thanks and credit go to Woodoo + extern VOID WINAPI HalWriteSMBusValue(BYTE, BYTE, BOOL, BYTE); + extern VOID WINAPI HalReadSMCTrayState(DWORD* state, DWORD* count); + + // Thanks and credit go to Team Evox + extern VOID WINAPI HalReturnToFirmware(DWORD); + + extern INT WINAPI XNetLoadConfigParams(LPBYTE); + extern INT WINAPI XNetSaveConfigParams(LPBYTE); + + extern INT WINAPI XWriteTitleInfoNoReboot(LPVOID,LPVOID,DWORD,DWORD,LPVOID); + + extern DWORD* LaunchDataPage; + +static HRESULT xbox_io_mount(char *szDrive, char *szDevice) +{ + STRING DeviceName, LinkName; +#ifndef IS_SALAMANDER + bool original_verbose = verbosity_is_enabled(); +#endif + char szSourceDevice[48] = {0}; + char szDestinationDrive[16] = {0}; + + snprintf(szSourceDevice, sizeof(szSourceDevice), + "\\Device\\%s", szDevice); + snprintf(szDestinationDrive, sizeof(szDestinationDrive), + "\\??\\%s", szDrive); + + DeviceName.Length = strlen(szSourceDevice); + DeviceName.MaximumLength = strlen(szSourceDevice) + 1; + DeviceName.Buffer = szSourceDevice; + + LinkName.Length = strlen(szDestinationDrive); + LinkName.MaximumLength = strlen(szDestinationDrive) + 1; + LinkName.Buffer = szDestinationDrive; + + IoCreateSymbolicLink(&LinkName, &DeviceName); + +#ifndef IS_SALAMANDER + if (original_verbose) + verbosity_enable(); + else + verbosity_disable(); +#endif + return S_OK; +} + +static HRESULT xbox_io_unmount(char *szDrive) +{ + STRING LinkName; + char szDestinationDrive[16] = {0}; + + snprintf(szDestinationDrive, sizeof(szDestinationDrive), + "\\??\\%s", szDrive); + + LinkName.Length = strlen(szDestinationDrive); + LinkName.MaximumLength = strlen(szDestinationDrive) + 1; + LinkName.Buffer = szDestinationDrive; + + IoDeleteSymbolicLink(&LinkName); + + return S_OK; +} +#endif + +#ifdef _XBOX360 +typedef struct _STRING +{ + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; +} STRING, *PSTRING; + +VOID RtlInitAnsiString(PSTRING DestinationString, PCHAR SourceString); +HRESULT ObDeleteSymbolicLink(PSTRING SymbolicLinkName); +HRESULT ObCreateSymbolicLink(PSTRING SymbolicLinkName, PSTRING DeviceName); + +static HRESULT xbox_io_mount(const char* szDrive, char* szDevice) +{ + STRING DeviceName, LinkName; + char szDestinationDrive[PATH_MAX_LENGTH]; + + snprintf(szDestinationDrive, sizeof(szDestinationDrive), + "\\??\\%s", szDrive); + RtlInitAnsiString(&DeviceName, szDevice); + RtlInitAnsiString(&LinkName, (PCHAR)szDestinationDrive); + ObDeleteSymbolicLink(&LinkName); + return (HRESULT)ObCreateSymbolicLink(&LinkName, &DeviceName); +} +#endif diff --git a/gfx/drivers_shader/slang_reflection.hpp b/gfx/drivers_shader/slang_reflection.hpp index c424899317..1ba1928dd9 100644 --- a/gfx/drivers_shader/slang_reflection.hpp +++ b/gfx/drivers_shader/slang_reflection.hpp @@ -1,86 +1,86 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2019 - Hans-Kristian Arntzen - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef SLANG_REFLECTION_HPP_ -#define SLANG_REFLECTION_HPP_ - -#include -#include -#include -#include - -struct slang_texture_semantic_meta -{ - size_t ubo_offset = 0; - size_t push_constant_offset = 0; - unsigned binding = 0; - uint32_t stage_mask = 0; - - bool texture = false; - bool uniform = false; - bool push_constant = false; -}; - -struct slang_semantic_meta -{ - size_t ubo_offset = 0; - size_t push_constant_offset = 0; - unsigned num_components = 0; - bool uniform = false; - bool push_constant = false; -}; - -struct slang_texture_semantic_map -{ - slang_texture_semantic semantic; - unsigned index; -}; - -struct slang_semantic_map -{ - slang_semantic semantic; - unsigned index; -}; - -struct slang_reflection -{ - slang_reflection(); - - size_t ubo_size = 0; - size_t push_constant_size = 0; - - unsigned ubo_binding = 0; - uint32_t ubo_stage_mask = 0; - uint32_t push_constant_stage_mask = 0; - - std::vector semantic_textures[SLANG_NUM_TEXTURE_SEMANTICS]; - slang_semantic_meta semantics[SLANG_NUM_SEMANTICS]; - std::vector semantic_float_parameters; - - const std::unordered_map *texture_semantic_map = nullptr; - const std::unordered_map *texture_semantic_uniform_map = nullptr; - const std::unordered_map *semantic_map = nullptr; - unsigned pass_number = 0; -}; - -bool slang_reflect_spirv(const std::vector &vertex, - const std::vector &fragment, - slang_reflection *reflection); - -bool slang_reflect(const spirv_cross::Compiler &vertex_compiler, const spirv_cross::Compiler &fragment_compiler, - const spirv_cross::ShaderResources &vertex, const spirv_cross::ShaderResources &fragment, - slang_reflection *reflection); - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2019 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef SLANG_REFLECTION_HPP_ +#define SLANG_REFLECTION_HPP_ + +#include +#include +#include +#include + +struct slang_texture_semantic_meta +{ + size_t ubo_offset = 0; + size_t push_constant_offset = 0; + unsigned binding = 0; + uint32_t stage_mask = 0; + + bool texture = false; + bool uniform = false; + bool push_constant = false; +}; + +struct slang_semantic_meta +{ + size_t ubo_offset = 0; + size_t push_constant_offset = 0; + unsigned num_components = 0; + bool uniform = false; + bool push_constant = false; +}; + +struct slang_texture_semantic_map +{ + slang_texture_semantic semantic; + unsigned index; +}; + +struct slang_semantic_map +{ + slang_semantic semantic; + unsigned index; +}; + +struct slang_reflection +{ + slang_reflection(); + + size_t ubo_size = 0; + size_t push_constant_size = 0; + + unsigned ubo_binding = 0; + uint32_t ubo_stage_mask = 0; + uint32_t push_constant_stage_mask = 0; + + std::vector semantic_textures[SLANG_NUM_TEXTURE_SEMANTICS]; + slang_semantic_meta semantics[SLANG_NUM_SEMANTICS]; + std::vector semantic_float_parameters; + + const std::unordered_map *texture_semantic_map = nullptr; + const std::unordered_map *texture_semantic_uniform_map = nullptr; + const std::unordered_map *semantic_map = nullptr; + unsigned pass_number = 0; +}; + +bool slang_reflect_spirv(const std::vector &vertex, + const std::vector &fragment, + slang_reflection *reflection); + +bool slang_reflect(const spirv_cross::Compiler &vertex_compiler, const spirv_cross::Compiler &fragment_compiler, + const spirv_cross::ShaderResources &vertex, const spirv_cross::ShaderResources &fragment, + slang_reflection *reflection); + +#endif diff --git a/gfx/include/d3d8/d3d8caps.h b/gfx/include/d3d8/d3d8caps.h index fe31c2d33b..c2f7edcd16 100644 --- a/gfx/include/d3d8/d3d8caps.h +++ b/gfx/include/d3d8/d3d8caps.h @@ -1,326 +1,326 @@ -/*==========================================================================; - * - * Copyright (C) Microsoft Corporation. All Rights Reserved. - * - * File: d3d8caps.h - * Content: Direct3D capabilities include file - * - ***************************************************************************/ - -#ifndef _D3D8CAPS_H -#define _D3D8CAPS_H - -#ifndef DIRECT3D_VERSION -#define DIRECT3D_VERSION 0x0800 -#endif /* DIRECT3D_VERSION */ - -/* include this file content only if compiling for DX8 interfaces */ -#if(DIRECT3D_VERSION >= 0x0800) - -#if defined(_X86_) || defined(_IA64_) -#pragma pack(4) -#endif - -typedef struct _D3DCAPS8 -{ - /* Device Info */ - D3DDEVTYPE DeviceType; - UINT AdapterOrdinal; - - /* Caps from DX7 Draw */ - DWORD Caps; - DWORD Caps2; - DWORD Caps3; - DWORD PresentationIntervals; - - /* Cursor Caps */ - DWORD CursorCaps; - - /* 3D Device Caps */ - DWORD DevCaps; - - DWORD PrimitiveMiscCaps; - DWORD RasterCaps; - DWORD ZCmpCaps; - DWORD SrcBlendCaps; - DWORD DestBlendCaps; - DWORD AlphaCmpCaps; - DWORD ShadeCaps; - DWORD TextureCaps; - DWORD TextureFilterCaps; /* D3DPTFILTERCAPS for IDirect3DTexture8's */ - DWORD CubeTextureFilterCaps; /* D3DPTFILTERCAPS for IDirect3DCubeTexture8's */ - DWORD VolumeTextureFilterCaps; /* D3DPTFILTERCAPS for IDirect3DVolumeTexture8's */ - DWORD TextureAddressCaps; /* D3DPTADDRESSCAPS for IDirect3DTexture8's */ - DWORD VolumeTextureAddressCaps; /* D3DPTADDRESSCAPS for IDirect3DVolumeTexture8's */ - - DWORD LineCaps; /* D3DLINECAPS */ - - DWORD MaxTextureWidth, MaxTextureHeight; - DWORD MaxVolumeExtent; - - DWORD MaxTextureRepeat; - DWORD MaxTextureAspectRatio; - DWORD MaxAnisotropy; - float MaxVertexW; - - float GuardBandLeft; - float GuardBandTop; - float GuardBandRight; - float GuardBandBottom; - - float ExtentsAdjust; - DWORD StencilCaps; - - DWORD FVFCaps; - DWORD TextureOpCaps; - DWORD MaxTextureBlendStages; - DWORD MaxSimultaneousTextures; - - DWORD VertexProcessingCaps; - DWORD MaxActiveLights; - DWORD MaxUserClipPlanes; - DWORD MaxVertexBlendMatrices; - DWORD MaxVertexBlendMatrixIndex; - - float MaxPointSize; - - DWORD MaxPrimitiveCount; /* max number of primitives per DrawPrimitive call */ - DWORD MaxVertexIndex; - DWORD MaxStreams; - DWORD MaxStreamStride; /* max stride for SetStreamSource */ - - DWORD VertexShaderVersion; - DWORD MaxVertexShaderConst; /* number of vertex shader constant registers */ - - DWORD PixelShaderVersion; - float MaxPixelShaderValue; /* max value of pixel shader arithmetic component */ - -} D3DCAPS8; - -/* BIT DEFINES FOR D3DCAPS8 DWORD MEMBERS */ - -/* Caps */ -#define D3DCAPS_READ_SCANLINE 0x00020000L - -/* Caps2 */ -#define D3DCAPS2_NO2DDURING3DSCENE 0x00000002L -#define D3DCAPS2_FULLSCREENGAMMA 0x00020000L -#define D3DCAPS2_CANRENDERWINDOWED 0x00080000L -#define D3DCAPS2_CANCALIBRATEGAMMA 0x00100000L -#define D3DCAPS2_RESERVED 0x02000000L -#define D3DCAPS2_CANMANAGERESOURCE 0x10000000L -#define D3DCAPS2_DYNAMICTEXTURES 0x20000000L - -/* Caps3 */ -#define D3DCAPS3_RESERVED 0x8000001fL - -/* Indicates that the device can respect the ALPHABLENDENABLE render state - * when fullscreen while using the FLIP or DISCARD swap effect. - * COPY and COPYVSYNC swap effects work whether or not this flag is set. - */ -#define D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD 0x00000020L - -/* PresentationIntervals */ -#define D3DPRESENT_INTERVAL_DEFAULT 0x00000000L -#define D3DPRESENT_INTERVAL_ONE 0x00000001L -#define D3DPRESENT_INTERVAL_TWO 0x00000002L -#define D3DPRESENT_INTERVAL_THREE 0x00000004L -#define D3DPRESENT_INTERVAL_FOUR 0x00000008L -#define D3DPRESENT_INTERVAL_IMMEDIATE 0x80000000L - -/* CursorCaps */ - -/* Driver supports HW color cursor in at least hi-res modes(height >=400) */ -#define D3DCURSORCAPS_COLOR 0x00000001L -/* Driver supports HW cursor also in low-res modes(height < 400) */ -#define D3DCURSORCAPS_LOWRES 0x00000002L - -/* DevCaps */ -#define D3DDEVCAPS_EXECUTESYSTEMMEMORY 0x00000010L /* Device can use execute buffers from system memory */ -#define D3DDEVCAPS_EXECUTEVIDEOMEMORY 0x00000020L /* Device can use execute buffers from video memory */ -#define D3DDEVCAPS_TLVERTEXSYSTEMMEMORY 0x00000040L /* Device can use TL buffers from system memory */ -#define D3DDEVCAPS_TLVERTEXVIDEOMEMORY 0x00000080L /* Device can use TL buffers from video memory */ -#define D3DDEVCAPS_TEXTURESYSTEMMEMORY 0x00000100L /* Device can texture from system memory */ -#define D3DDEVCAPS_TEXTUREVIDEOMEMORY 0x00000200L /* Device can texture from device memory */ -#define D3DDEVCAPS_DRAWPRIMTLVERTEX 0x00000400L /* Device can draw TLVERTEX primitives */ -#define D3DDEVCAPS_CANRENDERAFTERFLIP 0x00000800L /* Device can render without waiting for flip to complete */ -#define D3DDEVCAPS_TEXTURENONLOCALVIDMEM 0x00001000L /* Device can texture from nonlocal video memory */ -#define D3DDEVCAPS_DRAWPRIMITIVES2 0x00002000L /* Device can support DrawPrimitives2 */ -#define D3DDEVCAPS_SEPARATETEXTUREMEMORIES 0x00004000L /* Device is texturing from separate memory pools */ -#define D3DDEVCAPS_DRAWPRIMITIVES2EX 0x00008000L /* Device can support Extended DrawPrimitives2 i.e. DX7 compliant driver*/ -#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */ -#define D3DDEVCAPS_CANBLTSYSTONONLOCAL 0x00020000L /* Device supports a Tex Blt from system memory to non-local vidmem */ -#define D3DDEVCAPS_HWRASTERIZATION 0x00080000L /* Device has HW acceleration for rasterization */ -#define D3DDEVCAPS_PUREDEVICE 0x00100000L /* Device supports D3DCREATE_PUREDEVICE */ -#define D3DDEVCAPS_QUINTICRTPATCHES 0x00200000L /* Device supports quintic Beziers and BSplines */ -#define D3DDEVCAPS_RTPATCHES 0x00400000L /* Device supports Rect and Tri patches */ -#define D3DDEVCAPS_RTPATCHHANDLEZERO 0x00800000L /* Indicates that RT Patches may be drawn efficiently using handle 0 */ -#define D3DDEVCAPS_NPATCHES 0x01000000L /* Device supports N-Patches */ - -/* PrimitiveMiscCaps */ -#define D3DPMISCCAPS_MASKZ 0x00000002L -#define D3DPMISCCAPS_LINEPATTERNREP 0x00000004L -#define D3DPMISCCAPS_CULLNONE 0x00000010L -#define D3DPMISCCAPS_CULLCW 0x00000020L -#define D3DPMISCCAPS_CULLCCW 0x00000040L -#define D3DPMISCCAPS_COLORWRITEENABLE 0x00000080L -#define D3DPMISCCAPS_CLIPPLANESCALEDPOINTS 0x00000100L /* Device correctly clips scaled points to clip planes */ -#define D3DPMISCCAPS_CLIPTLVERTS 0x00000200L /* device will clip post-transformed vertex primitives */ -#define D3DPMISCCAPS_TSSARGTEMP 0x00000400L /* device supports D3DTA_TEMP for temporary register */ -#define D3DPMISCCAPS_BLENDOP 0x00000800L /* device supports D3DRS_BLENDOP */ -#define D3DPMISCCAPS_NULLREFERENCE 0x00001000L /* Reference Device that doesnt render */ - -/* LineCaps */ -#define D3DLINECAPS_TEXTURE 0x00000001L -#define D3DLINECAPS_ZTEST 0x00000002L -#define D3DLINECAPS_BLEND 0x00000004L -#define D3DLINECAPS_ALPHACMP 0x00000008L -#define D3DLINECAPS_FOG 0x00000010L - -/* RasterCaps */ -#define D3DPRASTERCAPS_DITHER 0x00000001L -#define D3DPRASTERCAPS_PAT 0x00000008L -#define D3DPRASTERCAPS_ZTEST 0x00000010L -#define D3DPRASTERCAPS_FOGVERTEX 0x00000080L -#define D3DPRASTERCAPS_FOGTABLE 0x00000100L -#define D3DPRASTERCAPS_ANTIALIASEDGES 0x00001000L -#define D3DPRASTERCAPS_MIPMAPLODBIAS 0x00002000L -#define D3DPRASTERCAPS_ZBIAS 0x00004000L -#define D3DPRASTERCAPS_ZBUFFERLESSHSR 0x00008000L -#define D3DPRASTERCAPS_FOGRANGE 0x00010000L -#define D3DPRASTERCAPS_ANISOTROPY 0x00020000L -#define D3DPRASTERCAPS_WBUFFER 0x00040000L -#define D3DPRASTERCAPS_WFOG 0x00100000L -#define D3DPRASTERCAPS_ZFOG 0x00200000L -#define D3DPRASTERCAPS_COLORPERSPECTIVE 0x00400000L /* Device iterates colors perspective correct */ -#define D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE 0x00800000L - -/* ZCmpCaps, AlphaCmpCaps */ -#define D3DPCMPCAPS_NEVER 0x00000001L -#define D3DPCMPCAPS_LESS 0x00000002L -#define D3DPCMPCAPS_EQUAL 0x00000004L -#define D3DPCMPCAPS_LESSEQUAL 0x00000008L -#define D3DPCMPCAPS_GREATER 0x00000010L -#define D3DPCMPCAPS_NOTEQUAL 0x00000020L -#define D3DPCMPCAPS_GREATEREQUAL 0x00000040L -#define D3DPCMPCAPS_ALWAYS 0x00000080L - -/* SourceBlendCaps, DestBlendCaps */ -#define D3DPBLENDCAPS_ZERO 0x00000001L -#define D3DPBLENDCAPS_ONE 0x00000002L -#define D3DPBLENDCAPS_SRCCOLOR 0x00000004L -#define D3DPBLENDCAPS_INVSRCCOLOR 0x00000008L -#define D3DPBLENDCAPS_SRCALPHA 0x00000010L -#define D3DPBLENDCAPS_INVSRCALPHA 0x00000020L -#define D3DPBLENDCAPS_DESTALPHA 0x00000040L -#define D3DPBLENDCAPS_INVDESTALPHA 0x00000080L -#define D3DPBLENDCAPS_DESTCOLOR 0x00000100L -#define D3DPBLENDCAPS_INVDESTCOLOR 0x00000200L -#define D3DPBLENDCAPS_SRCALPHASAT 0x00000400L -#define D3DPBLENDCAPS_BOTHSRCALPHA 0x00000800L -#define D3DPBLENDCAPS_BOTHINVSRCALPHA 0x00001000L - -/* ShadeCaps */ -#define D3DPSHADECAPS_COLORGOURAUDRGB 0x00000008L -#define D3DPSHADECAPS_SPECULARGOURAUDRGB 0x00000200L -#define D3DPSHADECAPS_ALPHAGOURAUDBLEND 0x00004000L -#define D3DPSHADECAPS_FOGGOURAUD 0x00080000L - -/* TextureCaps */ -#define D3DPTEXTURECAPS_PERSPECTIVE 0x00000001L /* Perspective-correct texturing is supported */ -#define D3DPTEXTURECAPS_POW2 0x00000002L /* Power-of-2 texture dimensions are required - applies to non-Cube/Volume textures only. */ -#define D3DPTEXTURECAPS_ALPHA 0x00000004L /* Alpha in texture pixels is supported */ -#define D3DPTEXTURECAPS_SQUAREONLY 0x00000020L /* Only square textures are supported */ -#define D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE 0x00000040L /* Texture indices are not scaled by the texture size prior to interpolation */ -#define D3DPTEXTURECAPS_ALPHAPALETTE 0x00000080L /* Device can draw alpha from texture palettes */ -/* Device can use non-POW2 textures if: - * 1) D3DTEXTURE_ADDRESS is set to CLAMP for this texture's stage - * 2) D3DRS_WRAP(N) is zero for this texture's coordinates - * 3) mip mapping is not enabled (use magnification filter only) - */ -#define D3DPTEXTURECAPS_NONPOW2CONDITIONAL 0x00000100L -#define D3DPTEXTURECAPS_PROJECTED 0x00000400L /* Device can do D3DTTFF_PROJECTED */ -#define D3DPTEXTURECAPS_CUBEMAP 0x00000800L /* Device can do cubemap textures */ -#define D3DPTEXTURECAPS_VOLUMEMAP 0x00002000L /* Device can do volume textures */ -#define D3DPTEXTURECAPS_MIPMAP 0x00004000L /* Device can do mipmapped textures */ -#define D3DPTEXTURECAPS_MIPVOLUMEMAP 0x00008000L /* Device can do mipmapped volume textures */ -#define D3DPTEXTURECAPS_MIPCUBEMAP 0x00010000L /* Device can do mipmapped cube maps */ -#define D3DPTEXTURECAPS_CUBEMAP_POW2 0x00020000L /* Device requires that cubemaps be power-of-2 dimension */ -#define D3DPTEXTURECAPS_VOLUMEMAP_POW2 0x00040000L /* Device requires that volume maps be power-of-2 dimension */ - -/* TextureFilterCaps */ -#define D3DPTFILTERCAPS_MINFPOINT 0x00000100L /* Min Filter */ -#define D3DPTFILTERCAPS_MINFLINEAR 0x00000200L -#define D3DPTFILTERCAPS_MINFANISOTROPIC 0x00000400L -#define D3DPTFILTERCAPS_MIPFPOINT 0x00010000L /* Mip Filter */ -#define D3DPTFILTERCAPS_MIPFLINEAR 0x00020000L -#define D3DPTFILTERCAPS_MAGFPOINT 0x01000000L /* Mag Filter */ -#define D3DPTFILTERCAPS_MAGFLINEAR 0x02000000L -#define D3DPTFILTERCAPS_MAGFANISOTROPIC 0x04000000L -#define D3DPTFILTERCAPS_MAGFAFLATCUBIC 0x08000000L -#define D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC 0x10000000L - -/* TextureAddressCaps */ -#define D3DPTADDRESSCAPS_WRAP 0x00000001L -#define D3DPTADDRESSCAPS_MIRROR 0x00000002L -#define D3DPTADDRESSCAPS_CLAMP 0x00000004L -#define D3DPTADDRESSCAPS_BORDER 0x00000008L -#define D3DPTADDRESSCAPS_INDEPENDENTUV 0x00000010L -#define D3DPTADDRESSCAPS_MIRRORONCE 0x00000020L - -/* StencilCaps */ -#define D3DSTENCILCAPS_KEEP 0x00000001L -#define D3DSTENCILCAPS_ZERO 0x00000002L -#define D3DSTENCILCAPS_REPLACE 0x00000004L -#define D3DSTENCILCAPS_INCRSAT 0x00000008L -#define D3DSTENCILCAPS_DECRSAT 0x00000010L -#define D3DSTENCILCAPS_INVERT 0x00000020L -#define D3DSTENCILCAPS_INCR 0x00000040L -#define D3DSTENCILCAPS_DECR 0x00000080L - -/* TextureOpCaps */ -#define D3DTEXOPCAPS_DISABLE 0x00000001L -#define D3DTEXOPCAPS_SELECTARG1 0x00000002L -#define D3DTEXOPCAPS_SELECTARG2 0x00000004L -#define D3DTEXOPCAPS_MODULATE 0x00000008L -#define D3DTEXOPCAPS_MODULATE2X 0x00000010L -#define D3DTEXOPCAPS_MODULATE4X 0x00000020L -#define D3DTEXOPCAPS_ADD 0x00000040L -#define D3DTEXOPCAPS_ADDSIGNED 0x00000080L -#define D3DTEXOPCAPS_ADDSIGNED2X 0x00000100L -#define D3DTEXOPCAPS_SUBTRACT 0x00000200L -#define D3DTEXOPCAPS_ADDSMOOTH 0x00000400L -#define D3DTEXOPCAPS_BLENDDIFFUSEALPHA 0x00000800L -#define D3DTEXOPCAPS_BLENDTEXTUREALPHA 0x00001000L -#define D3DTEXOPCAPS_BLENDFACTORALPHA 0x00002000L -#define D3DTEXOPCAPS_BLENDTEXTUREALPHAPM 0x00004000L -#define D3DTEXOPCAPS_BLENDCURRENTALPHA 0x00008000L -#define D3DTEXOPCAPS_PREMODULATE 0x00010000L -#define D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR 0x00020000L -#define D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA 0x00040000L -#define D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR 0x00080000L -#define D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA 0x00100000L -#define D3DTEXOPCAPS_BUMPENVMAP 0x00200000L -#define D3DTEXOPCAPS_BUMPENVMAPLUMINANCE 0x00400000L -#define D3DTEXOPCAPS_DOTPRODUCT3 0x00800000L -#define D3DTEXOPCAPS_MULTIPLYADD 0x01000000L -#define D3DTEXOPCAPS_LERP 0x02000000L - -/* FVFCaps */ -#define D3DFVFCAPS_TEXCOORDCOUNTMASK 0x0000ffffL /* mask for texture coordinate count field */ -#define D3DFVFCAPS_DONOTSTRIPELEMENTS 0x00080000L /* Device prefers that vertex elements not be stripped */ -#define D3DFVFCAPS_PSIZE 0x00100000L /* Device can receive point size */ - -/* VertexProcessingCaps */ -#define D3DVTXPCAPS_TEXGEN 0x00000001L /* device can do texgen */ -#define D3DVTXPCAPS_MATERIALSOURCE7 0x00000002L /* device can do DX7-level colormaterialsource ops */ -#define D3DVTXPCAPS_DIRECTIONALLIGHTS 0x00000008L /* device can do directional lights */ -#define D3DVTXPCAPS_POSITIONALLIGHTS 0x00000010L /* device can do positional lights (includes point and spot) */ -#define D3DVTXPCAPS_LOCALVIEWER 0x00000020L /* device can do local viewer */ -#define D3DVTXPCAPS_TWEENING 0x00000040L /* device can do vertex tweening */ -#define D3DVTXPCAPS_NO_VSDT_UBYTE4 0x00000080L /* device does not support D3DVSDT_UBYTE4 */ - -#pragma pack() - -#endif /* (DIRECT3D_VERSION >= 0x0800) */ -#endif /* _D3D8CAPS_H_ */ +/*==========================================================================; + * + * Copyright (C) Microsoft Corporation. All Rights Reserved. + * + * File: d3d8caps.h + * Content: Direct3D capabilities include file + * + ***************************************************************************/ + +#ifndef _D3D8CAPS_H +#define _D3D8CAPS_H + +#ifndef DIRECT3D_VERSION +#define DIRECT3D_VERSION 0x0800 +#endif /* DIRECT3D_VERSION */ + +/* include this file content only if compiling for DX8 interfaces */ +#if(DIRECT3D_VERSION >= 0x0800) + +#if defined(_X86_) || defined(_IA64_) +#pragma pack(4) +#endif + +typedef struct _D3DCAPS8 +{ + /* Device Info */ + D3DDEVTYPE DeviceType; + UINT AdapterOrdinal; + + /* Caps from DX7 Draw */ + DWORD Caps; + DWORD Caps2; + DWORD Caps3; + DWORD PresentationIntervals; + + /* Cursor Caps */ + DWORD CursorCaps; + + /* 3D Device Caps */ + DWORD DevCaps; + + DWORD PrimitiveMiscCaps; + DWORD RasterCaps; + DWORD ZCmpCaps; + DWORD SrcBlendCaps; + DWORD DestBlendCaps; + DWORD AlphaCmpCaps; + DWORD ShadeCaps; + DWORD TextureCaps; + DWORD TextureFilterCaps; /* D3DPTFILTERCAPS for IDirect3DTexture8's */ + DWORD CubeTextureFilterCaps; /* D3DPTFILTERCAPS for IDirect3DCubeTexture8's */ + DWORD VolumeTextureFilterCaps; /* D3DPTFILTERCAPS for IDirect3DVolumeTexture8's */ + DWORD TextureAddressCaps; /* D3DPTADDRESSCAPS for IDirect3DTexture8's */ + DWORD VolumeTextureAddressCaps; /* D3DPTADDRESSCAPS for IDirect3DVolumeTexture8's */ + + DWORD LineCaps; /* D3DLINECAPS */ + + DWORD MaxTextureWidth, MaxTextureHeight; + DWORD MaxVolumeExtent; + + DWORD MaxTextureRepeat; + DWORD MaxTextureAspectRatio; + DWORD MaxAnisotropy; + float MaxVertexW; + + float GuardBandLeft; + float GuardBandTop; + float GuardBandRight; + float GuardBandBottom; + + float ExtentsAdjust; + DWORD StencilCaps; + + DWORD FVFCaps; + DWORD TextureOpCaps; + DWORD MaxTextureBlendStages; + DWORD MaxSimultaneousTextures; + + DWORD VertexProcessingCaps; + DWORD MaxActiveLights; + DWORD MaxUserClipPlanes; + DWORD MaxVertexBlendMatrices; + DWORD MaxVertexBlendMatrixIndex; + + float MaxPointSize; + + DWORD MaxPrimitiveCount; /* max number of primitives per DrawPrimitive call */ + DWORD MaxVertexIndex; + DWORD MaxStreams; + DWORD MaxStreamStride; /* max stride for SetStreamSource */ + + DWORD VertexShaderVersion; + DWORD MaxVertexShaderConst; /* number of vertex shader constant registers */ + + DWORD PixelShaderVersion; + float MaxPixelShaderValue; /* max value of pixel shader arithmetic component */ + +} D3DCAPS8; + +/* BIT DEFINES FOR D3DCAPS8 DWORD MEMBERS */ + +/* Caps */ +#define D3DCAPS_READ_SCANLINE 0x00020000L + +/* Caps2 */ +#define D3DCAPS2_NO2DDURING3DSCENE 0x00000002L +#define D3DCAPS2_FULLSCREENGAMMA 0x00020000L +#define D3DCAPS2_CANRENDERWINDOWED 0x00080000L +#define D3DCAPS2_CANCALIBRATEGAMMA 0x00100000L +#define D3DCAPS2_RESERVED 0x02000000L +#define D3DCAPS2_CANMANAGERESOURCE 0x10000000L +#define D3DCAPS2_DYNAMICTEXTURES 0x20000000L + +/* Caps3 */ +#define D3DCAPS3_RESERVED 0x8000001fL + +/* Indicates that the device can respect the ALPHABLENDENABLE render state + * when fullscreen while using the FLIP or DISCARD swap effect. + * COPY and COPYVSYNC swap effects work whether or not this flag is set. + */ +#define D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD 0x00000020L + +/* PresentationIntervals */ +#define D3DPRESENT_INTERVAL_DEFAULT 0x00000000L +#define D3DPRESENT_INTERVAL_ONE 0x00000001L +#define D3DPRESENT_INTERVAL_TWO 0x00000002L +#define D3DPRESENT_INTERVAL_THREE 0x00000004L +#define D3DPRESENT_INTERVAL_FOUR 0x00000008L +#define D3DPRESENT_INTERVAL_IMMEDIATE 0x80000000L + +/* CursorCaps */ + +/* Driver supports HW color cursor in at least hi-res modes(height >=400) */ +#define D3DCURSORCAPS_COLOR 0x00000001L +/* Driver supports HW cursor also in low-res modes(height < 400) */ +#define D3DCURSORCAPS_LOWRES 0x00000002L + +/* DevCaps */ +#define D3DDEVCAPS_EXECUTESYSTEMMEMORY 0x00000010L /* Device can use execute buffers from system memory */ +#define D3DDEVCAPS_EXECUTEVIDEOMEMORY 0x00000020L /* Device can use execute buffers from video memory */ +#define D3DDEVCAPS_TLVERTEXSYSTEMMEMORY 0x00000040L /* Device can use TL buffers from system memory */ +#define D3DDEVCAPS_TLVERTEXVIDEOMEMORY 0x00000080L /* Device can use TL buffers from video memory */ +#define D3DDEVCAPS_TEXTURESYSTEMMEMORY 0x00000100L /* Device can texture from system memory */ +#define D3DDEVCAPS_TEXTUREVIDEOMEMORY 0x00000200L /* Device can texture from device memory */ +#define D3DDEVCAPS_DRAWPRIMTLVERTEX 0x00000400L /* Device can draw TLVERTEX primitives */ +#define D3DDEVCAPS_CANRENDERAFTERFLIP 0x00000800L /* Device can render without waiting for flip to complete */ +#define D3DDEVCAPS_TEXTURENONLOCALVIDMEM 0x00001000L /* Device can texture from nonlocal video memory */ +#define D3DDEVCAPS_DRAWPRIMITIVES2 0x00002000L /* Device can support DrawPrimitives2 */ +#define D3DDEVCAPS_SEPARATETEXTUREMEMORIES 0x00004000L /* Device is texturing from separate memory pools */ +#define D3DDEVCAPS_DRAWPRIMITIVES2EX 0x00008000L /* Device can support Extended DrawPrimitives2 i.e. DX7 compliant driver*/ +#define D3DDEVCAPS_HWTRANSFORMANDLIGHT 0x00010000L /* Device can support transformation and lighting in hardware and DRAWPRIMITIVES2EX must be also */ +#define D3DDEVCAPS_CANBLTSYSTONONLOCAL 0x00020000L /* Device supports a Tex Blt from system memory to non-local vidmem */ +#define D3DDEVCAPS_HWRASTERIZATION 0x00080000L /* Device has HW acceleration for rasterization */ +#define D3DDEVCAPS_PUREDEVICE 0x00100000L /* Device supports D3DCREATE_PUREDEVICE */ +#define D3DDEVCAPS_QUINTICRTPATCHES 0x00200000L /* Device supports quintic Beziers and BSplines */ +#define D3DDEVCAPS_RTPATCHES 0x00400000L /* Device supports Rect and Tri patches */ +#define D3DDEVCAPS_RTPATCHHANDLEZERO 0x00800000L /* Indicates that RT Patches may be drawn efficiently using handle 0 */ +#define D3DDEVCAPS_NPATCHES 0x01000000L /* Device supports N-Patches */ + +/* PrimitiveMiscCaps */ +#define D3DPMISCCAPS_MASKZ 0x00000002L +#define D3DPMISCCAPS_LINEPATTERNREP 0x00000004L +#define D3DPMISCCAPS_CULLNONE 0x00000010L +#define D3DPMISCCAPS_CULLCW 0x00000020L +#define D3DPMISCCAPS_CULLCCW 0x00000040L +#define D3DPMISCCAPS_COLORWRITEENABLE 0x00000080L +#define D3DPMISCCAPS_CLIPPLANESCALEDPOINTS 0x00000100L /* Device correctly clips scaled points to clip planes */ +#define D3DPMISCCAPS_CLIPTLVERTS 0x00000200L /* device will clip post-transformed vertex primitives */ +#define D3DPMISCCAPS_TSSARGTEMP 0x00000400L /* device supports D3DTA_TEMP for temporary register */ +#define D3DPMISCCAPS_BLENDOP 0x00000800L /* device supports D3DRS_BLENDOP */ +#define D3DPMISCCAPS_NULLREFERENCE 0x00001000L /* Reference Device that doesnt render */ + +/* LineCaps */ +#define D3DLINECAPS_TEXTURE 0x00000001L +#define D3DLINECAPS_ZTEST 0x00000002L +#define D3DLINECAPS_BLEND 0x00000004L +#define D3DLINECAPS_ALPHACMP 0x00000008L +#define D3DLINECAPS_FOG 0x00000010L + +/* RasterCaps */ +#define D3DPRASTERCAPS_DITHER 0x00000001L +#define D3DPRASTERCAPS_PAT 0x00000008L +#define D3DPRASTERCAPS_ZTEST 0x00000010L +#define D3DPRASTERCAPS_FOGVERTEX 0x00000080L +#define D3DPRASTERCAPS_FOGTABLE 0x00000100L +#define D3DPRASTERCAPS_ANTIALIASEDGES 0x00001000L +#define D3DPRASTERCAPS_MIPMAPLODBIAS 0x00002000L +#define D3DPRASTERCAPS_ZBIAS 0x00004000L +#define D3DPRASTERCAPS_ZBUFFERLESSHSR 0x00008000L +#define D3DPRASTERCAPS_FOGRANGE 0x00010000L +#define D3DPRASTERCAPS_ANISOTROPY 0x00020000L +#define D3DPRASTERCAPS_WBUFFER 0x00040000L +#define D3DPRASTERCAPS_WFOG 0x00100000L +#define D3DPRASTERCAPS_ZFOG 0x00200000L +#define D3DPRASTERCAPS_COLORPERSPECTIVE 0x00400000L /* Device iterates colors perspective correct */ +#define D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE 0x00800000L + +/* ZCmpCaps, AlphaCmpCaps */ +#define D3DPCMPCAPS_NEVER 0x00000001L +#define D3DPCMPCAPS_LESS 0x00000002L +#define D3DPCMPCAPS_EQUAL 0x00000004L +#define D3DPCMPCAPS_LESSEQUAL 0x00000008L +#define D3DPCMPCAPS_GREATER 0x00000010L +#define D3DPCMPCAPS_NOTEQUAL 0x00000020L +#define D3DPCMPCAPS_GREATEREQUAL 0x00000040L +#define D3DPCMPCAPS_ALWAYS 0x00000080L + +/* SourceBlendCaps, DestBlendCaps */ +#define D3DPBLENDCAPS_ZERO 0x00000001L +#define D3DPBLENDCAPS_ONE 0x00000002L +#define D3DPBLENDCAPS_SRCCOLOR 0x00000004L +#define D3DPBLENDCAPS_INVSRCCOLOR 0x00000008L +#define D3DPBLENDCAPS_SRCALPHA 0x00000010L +#define D3DPBLENDCAPS_INVSRCALPHA 0x00000020L +#define D3DPBLENDCAPS_DESTALPHA 0x00000040L +#define D3DPBLENDCAPS_INVDESTALPHA 0x00000080L +#define D3DPBLENDCAPS_DESTCOLOR 0x00000100L +#define D3DPBLENDCAPS_INVDESTCOLOR 0x00000200L +#define D3DPBLENDCAPS_SRCALPHASAT 0x00000400L +#define D3DPBLENDCAPS_BOTHSRCALPHA 0x00000800L +#define D3DPBLENDCAPS_BOTHINVSRCALPHA 0x00001000L + +/* ShadeCaps */ +#define D3DPSHADECAPS_COLORGOURAUDRGB 0x00000008L +#define D3DPSHADECAPS_SPECULARGOURAUDRGB 0x00000200L +#define D3DPSHADECAPS_ALPHAGOURAUDBLEND 0x00004000L +#define D3DPSHADECAPS_FOGGOURAUD 0x00080000L + +/* TextureCaps */ +#define D3DPTEXTURECAPS_PERSPECTIVE 0x00000001L /* Perspective-correct texturing is supported */ +#define D3DPTEXTURECAPS_POW2 0x00000002L /* Power-of-2 texture dimensions are required - applies to non-Cube/Volume textures only. */ +#define D3DPTEXTURECAPS_ALPHA 0x00000004L /* Alpha in texture pixels is supported */ +#define D3DPTEXTURECAPS_SQUAREONLY 0x00000020L /* Only square textures are supported */ +#define D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE 0x00000040L /* Texture indices are not scaled by the texture size prior to interpolation */ +#define D3DPTEXTURECAPS_ALPHAPALETTE 0x00000080L /* Device can draw alpha from texture palettes */ +/* Device can use non-POW2 textures if: + * 1) D3DTEXTURE_ADDRESS is set to CLAMP for this texture's stage + * 2) D3DRS_WRAP(N) is zero for this texture's coordinates + * 3) mip mapping is not enabled (use magnification filter only) + */ +#define D3DPTEXTURECAPS_NONPOW2CONDITIONAL 0x00000100L +#define D3DPTEXTURECAPS_PROJECTED 0x00000400L /* Device can do D3DTTFF_PROJECTED */ +#define D3DPTEXTURECAPS_CUBEMAP 0x00000800L /* Device can do cubemap textures */ +#define D3DPTEXTURECAPS_VOLUMEMAP 0x00002000L /* Device can do volume textures */ +#define D3DPTEXTURECAPS_MIPMAP 0x00004000L /* Device can do mipmapped textures */ +#define D3DPTEXTURECAPS_MIPVOLUMEMAP 0x00008000L /* Device can do mipmapped volume textures */ +#define D3DPTEXTURECAPS_MIPCUBEMAP 0x00010000L /* Device can do mipmapped cube maps */ +#define D3DPTEXTURECAPS_CUBEMAP_POW2 0x00020000L /* Device requires that cubemaps be power-of-2 dimension */ +#define D3DPTEXTURECAPS_VOLUMEMAP_POW2 0x00040000L /* Device requires that volume maps be power-of-2 dimension */ + +/* TextureFilterCaps */ +#define D3DPTFILTERCAPS_MINFPOINT 0x00000100L /* Min Filter */ +#define D3DPTFILTERCAPS_MINFLINEAR 0x00000200L +#define D3DPTFILTERCAPS_MINFANISOTROPIC 0x00000400L +#define D3DPTFILTERCAPS_MIPFPOINT 0x00010000L /* Mip Filter */ +#define D3DPTFILTERCAPS_MIPFLINEAR 0x00020000L +#define D3DPTFILTERCAPS_MAGFPOINT 0x01000000L /* Mag Filter */ +#define D3DPTFILTERCAPS_MAGFLINEAR 0x02000000L +#define D3DPTFILTERCAPS_MAGFANISOTROPIC 0x04000000L +#define D3DPTFILTERCAPS_MAGFAFLATCUBIC 0x08000000L +#define D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC 0x10000000L + +/* TextureAddressCaps */ +#define D3DPTADDRESSCAPS_WRAP 0x00000001L +#define D3DPTADDRESSCAPS_MIRROR 0x00000002L +#define D3DPTADDRESSCAPS_CLAMP 0x00000004L +#define D3DPTADDRESSCAPS_BORDER 0x00000008L +#define D3DPTADDRESSCAPS_INDEPENDENTUV 0x00000010L +#define D3DPTADDRESSCAPS_MIRRORONCE 0x00000020L + +/* StencilCaps */ +#define D3DSTENCILCAPS_KEEP 0x00000001L +#define D3DSTENCILCAPS_ZERO 0x00000002L +#define D3DSTENCILCAPS_REPLACE 0x00000004L +#define D3DSTENCILCAPS_INCRSAT 0x00000008L +#define D3DSTENCILCAPS_DECRSAT 0x00000010L +#define D3DSTENCILCAPS_INVERT 0x00000020L +#define D3DSTENCILCAPS_INCR 0x00000040L +#define D3DSTENCILCAPS_DECR 0x00000080L + +/* TextureOpCaps */ +#define D3DTEXOPCAPS_DISABLE 0x00000001L +#define D3DTEXOPCAPS_SELECTARG1 0x00000002L +#define D3DTEXOPCAPS_SELECTARG2 0x00000004L +#define D3DTEXOPCAPS_MODULATE 0x00000008L +#define D3DTEXOPCAPS_MODULATE2X 0x00000010L +#define D3DTEXOPCAPS_MODULATE4X 0x00000020L +#define D3DTEXOPCAPS_ADD 0x00000040L +#define D3DTEXOPCAPS_ADDSIGNED 0x00000080L +#define D3DTEXOPCAPS_ADDSIGNED2X 0x00000100L +#define D3DTEXOPCAPS_SUBTRACT 0x00000200L +#define D3DTEXOPCAPS_ADDSMOOTH 0x00000400L +#define D3DTEXOPCAPS_BLENDDIFFUSEALPHA 0x00000800L +#define D3DTEXOPCAPS_BLENDTEXTUREALPHA 0x00001000L +#define D3DTEXOPCAPS_BLENDFACTORALPHA 0x00002000L +#define D3DTEXOPCAPS_BLENDTEXTUREALPHAPM 0x00004000L +#define D3DTEXOPCAPS_BLENDCURRENTALPHA 0x00008000L +#define D3DTEXOPCAPS_PREMODULATE 0x00010000L +#define D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR 0x00020000L +#define D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA 0x00040000L +#define D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR 0x00080000L +#define D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA 0x00100000L +#define D3DTEXOPCAPS_BUMPENVMAP 0x00200000L +#define D3DTEXOPCAPS_BUMPENVMAPLUMINANCE 0x00400000L +#define D3DTEXOPCAPS_DOTPRODUCT3 0x00800000L +#define D3DTEXOPCAPS_MULTIPLYADD 0x01000000L +#define D3DTEXOPCAPS_LERP 0x02000000L + +/* FVFCaps */ +#define D3DFVFCAPS_TEXCOORDCOUNTMASK 0x0000ffffL /* mask for texture coordinate count field */ +#define D3DFVFCAPS_DONOTSTRIPELEMENTS 0x00080000L /* Device prefers that vertex elements not be stripped */ +#define D3DFVFCAPS_PSIZE 0x00100000L /* Device can receive point size */ + +/* VertexProcessingCaps */ +#define D3DVTXPCAPS_TEXGEN 0x00000001L /* device can do texgen */ +#define D3DVTXPCAPS_MATERIALSOURCE7 0x00000002L /* device can do DX7-level colormaterialsource ops */ +#define D3DVTXPCAPS_DIRECTIONALLIGHTS 0x00000008L /* device can do directional lights */ +#define D3DVTXPCAPS_POSITIONALLIGHTS 0x00000010L /* device can do positional lights (includes point and spot) */ +#define D3DVTXPCAPS_LOCALVIEWER 0x00000020L /* device can do local viewer */ +#define D3DVTXPCAPS_TWEENING 0x00000040L /* device can do vertex tweening */ +#define D3DVTXPCAPS_NO_VSDT_UBYTE4 0x00000080L /* device does not support D3DVSDT_UBYTE4 */ + +#pragma pack() + +#endif /* (DIRECT3D_VERSION >= 0x0800) */ +#endif /* _D3D8CAPS_H_ */ diff --git a/gfx/include/d3d8/d3d8types.h b/gfx/include/d3d8/d3d8types.h index 9ed1221341..26e6b1bf5e 100644 --- a/gfx/include/d3d8/d3d8types.h +++ b/gfx/include/d3d8/d3d8types.h @@ -1,1654 +1,1654 @@ -/*==========================================================================; - * - * Copyright (C) Microsoft Corporation. All Rights Reserved. - * - * File: d3d8types.h - * Content: Direct3D capabilities include file - * - ***************************************************************************/ - -#ifndef _D3D8TYPES_H_ -#define _D3D8TYPES_H_ - -#ifndef DIRECT3D_VERSION -#define DIRECT3D_VERSION 0x0800 -#endif /* DIRECT3D_VERSION */ - -/* include this file content only if compiling for DX8 interfaces */ -#if(DIRECT3D_VERSION >= 0x0800) - -#include - -#if _MSC_VER >= 1200 -#pragma warning(push) -#endif -#pragma warning(disable:4201) /* anonymous unions warning */ -#if defined(_X86_) || defined(_IA64_) -#pragma pack(4) -#endif - -/* D3DCOLOR is equivalent to D3DFMT_A8R8G8B8 */ -#ifndef D3DCOLOR_DEFINED -typedef DWORD D3DCOLOR; -#define D3DCOLOR_DEFINED -#endif - -/* maps unsigned 8 bits/channel to D3DCOLOR */ -#define D3DCOLOR_ARGB(a,r,g,b) \ - ((D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) -#define D3DCOLOR_RGBA(r,g,b,a) D3DCOLOR_ARGB(a,r,g,b) -#define D3DCOLOR_XRGB(r,g,b) D3DCOLOR_ARGB(0xff,r,g,b) - -/* maps floating point channels (0.f to 1.f range) to D3DCOLOR */ -#define D3DCOLOR_COLORVALUE(r,g,b,a) \ - D3DCOLOR_RGBA((DWORD)((r)*255.f),(DWORD)((g)*255.f),(DWORD)((b)*255.f),(DWORD)((a)*255.f)) - - -#ifndef D3DVECTOR_DEFINED -typedef struct _D3DVECTOR { - float x; - float y; - float z; -} D3DVECTOR; -#define D3DVECTOR_DEFINED -#endif - -#ifndef D3DCOLORVALUE_DEFINED -typedef struct _D3DCOLORVALUE { - float r; - float g; - float b; - float a; -} D3DCOLORVALUE; -#define D3DCOLORVALUE_DEFINED -#endif - -#ifndef D3DRECT_DEFINED -typedef struct _D3DRECT { - LONG x1; - LONG y1; - LONG x2; - LONG y2; -} D3DRECT; -#define D3DRECT_DEFINED -#endif - -#ifndef D3DMATRIX_DEFINED -typedef struct _D3DMATRIX { - union { - struct { - float _11, _12, _13, _14; - float _21, _22, _23, _24; - float _31, _32, _33, _34; - float _41, _42, _43, _44; - - }; - float m[4][4]; - }; -} D3DMATRIX; -#define D3DMATRIX_DEFINED -#endif - -typedef struct _D3DVIEWPORT8 { - DWORD X; - DWORD Y; /* Viewport Top left */ - DWORD Width; - DWORD Height; /* Viewport Dimensions */ - float MinZ; /* Min/max of clip Volume */ - float MaxZ; -} D3DVIEWPORT8; - -/* - * Values for clip fields. - */ - -/* Max number of user clipping planes, supported in D3D. */ -#define D3DMAXUSERCLIPPLANES 32 - -/* These bits could be ORed together to use with D3DRS_CLIPPLANEENABLE */ -#define D3DCLIPPLANE0 (1 << 0) -#define D3DCLIPPLANE1 (1 << 1) -#define D3DCLIPPLANE2 (1 << 2) -#define D3DCLIPPLANE3 (1 << 3) -#define D3DCLIPPLANE4 (1 << 4) -#define D3DCLIPPLANE5 (1 << 5) - -/* The following bits are used in the ClipUnion and ClipIntersection - * members of the D3DCLIPSTATUS8 - */ - -#define D3DCS_LEFT 0x00000001L -#define D3DCS_RIGHT 0x00000002L -#define D3DCS_TOP 0x00000004L -#define D3DCS_BOTTOM 0x00000008L -#define D3DCS_FRONT 0x00000010L -#define D3DCS_BACK 0x00000020L -#define D3DCS_PLANE0 0x00000040L -#define D3DCS_PLANE1 0x00000080L -#define D3DCS_PLANE2 0x00000100L -#define D3DCS_PLANE3 0x00000200L -#define D3DCS_PLANE4 0x00000400L -#define D3DCS_PLANE5 0x00000800L - -#define D3DCS_ALL (D3DCS_LEFT | \ - D3DCS_RIGHT | \ - D3DCS_TOP | \ - D3DCS_BOTTOM | \ - D3DCS_FRONT | \ - D3DCS_BACK | \ - D3DCS_PLANE0 | \ - D3DCS_PLANE1 | \ - D3DCS_PLANE2 | \ - D3DCS_PLANE3 | \ - D3DCS_PLANE4 | \ - D3DCS_PLANE5) - -typedef struct _D3DCLIPSTATUS8 { - DWORD ClipUnion; - DWORD ClipIntersection; -} D3DCLIPSTATUS8; - -typedef struct _D3DMATERIAL8 { - D3DCOLORVALUE Diffuse; /* Diffuse color RGBA */ - D3DCOLORVALUE Ambient; /* Ambient color RGB */ - D3DCOLORVALUE Specular; /* Specular 'shininess' */ - D3DCOLORVALUE Emissive; /* Emissive color RGB */ - float Power; /* Sharpness if specular highlight */ -} D3DMATERIAL8; - -typedef enum _D3DLIGHTTYPE { - D3DLIGHT_POINT = 1, - D3DLIGHT_SPOT = 2, - D3DLIGHT_DIRECTIONAL = 3, - D3DLIGHT_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DLIGHTTYPE; - -typedef struct _D3DLIGHT8 { - D3DLIGHTTYPE Type; /* Type of light source */ - D3DCOLORVALUE Diffuse; /* Diffuse color of light */ - D3DCOLORVALUE Specular; /* Specular color of light */ - D3DCOLORVALUE Ambient; /* Ambient color of light */ - D3DVECTOR Position; /* Position in world space */ - D3DVECTOR Direction; /* Direction in world space */ - float Range; /* Cutoff range */ - float Falloff; /* Falloff */ - float Attenuation0; /* Constant attenuation */ - float Attenuation1; /* Linear attenuation */ - float Attenuation2; /* Quadratic attenuation */ - float Theta; /* Inner angle of spotlight cone */ - float Phi; /* Outer angle of spotlight cone */ -} D3DLIGHT8; - -/* - * Options for clearing - */ -#define D3DCLEAR_TARGET 0x00000001l /* Clear target surface */ -#define D3DCLEAR_ZBUFFER 0x00000002l /* Clear target z buffer */ -#define D3DCLEAR_STENCIL 0x00000004l /* Clear stencil planes */ - -/* - * The following defines the rendering states - */ - -typedef enum _D3DSHADEMODE { - D3DSHADE_FLAT = 1, - D3DSHADE_GOURAUD = 2, - D3DSHADE_PHONG = 3, - D3DSHADE_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DSHADEMODE; - -typedef enum _D3DFILLMODE { - D3DFILL_POINT = 1, - D3DFILL_WIREFRAME = 2, - D3DFILL_SOLID = 3, - D3DFILL_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DFILLMODE; - -typedef struct _D3DLINEPATTERN { - WORD wRepeatFactor; - WORD wLinePattern; -} D3DLINEPATTERN; - -typedef enum _D3DBLEND { - D3DBLEND_ZERO = 1, - D3DBLEND_ONE = 2, - D3DBLEND_SRCCOLOR = 3, - D3DBLEND_INVSRCCOLOR = 4, - D3DBLEND_SRCALPHA = 5, - D3DBLEND_INVSRCALPHA = 6, - D3DBLEND_DESTALPHA = 7, - D3DBLEND_INVDESTALPHA = 8, - D3DBLEND_DESTCOLOR = 9, - D3DBLEND_INVDESTCOLOR = 10, - D3DBLEND_SRCALPHASAT = 11, - D3DBLEND_BOTHSRCALPHA = 12, - D3DBLEND_BOTHINVSRCALPHA = 13, - D3DBLEND_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DBLEND; - -typedef enum _D3DBLENDOP { - D3DBLENDOP_ADD = 1, - D3DBLENDOP_SUBTRACT = 2, - D3DBLENDOP_REVSUBTRACT = 3, - D3DBLENDOP_MIN = 4, - D3DBLENDOP_MAX = 5, - D3DBLENDOP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DBLENDOP; - -typedef enum _D3DTEXTUREADDRESS { - D3DTADDRESS_WRAP = 1, - D3DTADDRESS_MIRROR = 2, - D3DTADDRESS_CLAMP = 3, - D3DTADDRESS_BORDER = 4, - D3DTADDRESS_MIRRORONCE = 5, - D3DTADDRESS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DTEXTUREADDRESS; - -typedef enum _D3DCULL { - D3DCULL_NONE = 1, - D3DCULL_CW = 2, - D3DCULL_CCW = 3, - D3DCULL_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DCULL; - -typedef enum _D3DCMPFUNC { - D3DCMP_NEVER = 1, - D3DCMP_LESS = 2, - D3DCMP_EQUAL = 3, - D3DCMP_LESSEQUAL = 4, - D3DCMP_GREATER = 5, - D3DCMP_NOTEQUAL = 6, - D3DCMP_GREATEREQUAL = 7, - D3DCMP_ALWAYS = 8, - D3DCMP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DCMPFUNC; - -typedef enum _D3DSTENCILOP { - D3DSTENCILOP_KEEP = 1, - D3DSTENCILOP_ZERO = 2, - D3DSTENCILOP_REPLACE = 3, - D3DSTENCILOP_INCRSAT = 4, - D3DSTENCILOP_DECRSAT = 5, - D3DSTENCILOP_INVERT = 6, - D3DSTENCILOP_INCR = 7, - D3DSTENCILOP_DECR = 8, - D3DSTENCILOP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DSTENCILOP; - -typedef enum _D3DFOGMODE { - D3DFOG_NONE = 0, - D3DFOG_EXP = 1, - D3DFOG_EXP2 = 2, - D3DFOG_LINEAR = 3, - D3DFOG_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DFOGMODE; - -typedef enum _D3DZBUFFERTYPE { - D3DZB_FALSE = 0, - D3DZB_TRUE = 1, /* Z buffering */ - D3DZB_USEW = 2, /* W buffering */ - D3DZB_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DZBUFFERTYPE; - -/* Primitives supported by draw-primitive API */ -typedef enum _D3DPRIMITIVETYPE { - D3DPT_POINTLIST = 1, - D3DPT_LINELIST = 2, - D3DPT_LINESTRIP = 3, - D3DPT_TRIANGLELIST = 4, - D3DPT_TRIANGLESTRIP = 5, - D3DPT_TRIANGLEFAN = 6, - D3DPT_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DPRIMITIVETYPE; - -typedef enum _D3DTRANSFORMSTATETYPE { - D3DTS_VIEW = 2, - D3DTS_PROJECTION = 3, - D3DTS_TEXTURE0 = 16, - D3DTS_TEXTURE1 = 17, - D3DTS_TEXTURE2 = 18, - D3DTS_TEXTURE3 = 19, - D3DTS_TEXTURE4 = 20, - D3DTS_TEXTURE5 = 21, - D3DTS_TEXTURE6 = 22, - D3DTS_TEXTURE7 = 23, - D3DTS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DTRANSFORMSTATETYPE; - -#define D3DTS_WORLDMATRIX(index) (D3DTRANSFORMSTATETYPE)(index + 256) -#define D3DTS_WORLD D3DTS_WORLDMATRIX(0) -#define D3DTS_WORLD1 D3DTS_WORLDMATRIX(1) -#define D3DTS_WORLD2 D3DTS_WORLDMATRIX(2) -#define D3DTS_WORLD3 D3DTS_WORLDMATRIX(3) - -typedef enum _D3DRENDERSTATETYPE { - D3DRS_ZENABLE = 7, /* D3DZBUFFERTYPE (or TRUE/FALSE for legacy) */ - D3DRS_FILLMODE = 8, /* D3DFILLMODE */ - D3DRS_SHADEMODE = 9, /* D3DSHADEMODE */ - D3DRS_LINEPATTERN = 10, /* D3DLINEPATTERN */ - D3DRS_ZWRITEENABLE = 14, /* TRUE to enable z writes */ - D3DRS_ALPHATESTENABLE = 15, /* TRUE to enable alpha tests */ - D3DRS_LASTPIXEL = 16, /* TRUE for last-pixel on lines */ - D3DRS_SRCBLEND = 19, /* D3DBLEND */ - D3DRS_DESTBLEND = 20, /* D3DBLEND */ - D3DRS_CULLMODE = 22, /* D3DCULL */ - D3DRS_ZFUNC = 23, /* D3DCMPFUNC */ - D3DRS_ALPHAREF = 24, /* D3DFIXED */ - D3DRS_ALPHAFUNC = 25, /* D3DCMPFUNC */ - D3DRS_DITHERENABLE = 26, /* TRUE to enable dithering */ - D3DRS_ALPHABLENDENABLE = 27, /* TRUE to enable alpha blending */ - D3DRS_FOGENABLE = 28, /* TRUE to enable fog blending */ - D3DRS_SPECULARENABLE = 29, /* TRUE to enable specular */ - D3DRS_ZVISIBLE = 30, /* TRUE to enable z checking */ - D3DRS_FOGCOLOR = 34, /* D3DCOLOR */ - D3DRS_FOGTABLEMODE = 35, /* D3DFOGMODE */ - D3DRS_FOGSTART = 36, /* Fog start (for both vertex and pixel fog) */ - D3DRS_FOGEND = 37, /* Fog end */ - D3DRS_FOGDENSITY = 38, /* Fog density */ - D3DRS_EDGEANTIALIAS = 40, /* TRUE to enable edge antialiasing */ - D3DRS_ZBIAS = 47, /* LONG Z bias */ - D3DRS_RANGEFOGENABLE = 48, /* Enables range-based fog */ - D3DRS_STENCILENABLE = 52, /* BOOL enable/disable stenciling */ - D3DRS_STENCILFAIL = 53, /* D3DSTENCILOP to do if stencil test fails */ - D3DRS_STENCILZFAIL = 54, /* D3DSTENCILOP to do if stencil test passes and Z test fails */ - D3DRS_STENCILPASS = 55, /* D3DSTENCILOP to do if both stencil and Z tests pass */ - D3DRS_STENCILFUNC = 56, /* D3DCMPFUNC fn. Stencil Test passes if ((ref & mask) stencilfn (stencil & mask)) is true */ - D3DRS_STENCILREF = 57, /* Reference value used in stencil test */ - D3DRS_STENCILMASK = 58, /* Mask value used in stencil test */ - D3DRS_STENCILWRITEMASK = 59, /* Write mask applied to values written to stencil buffer */ - D3DRS_TEXTUREFACTOR = 60, /* D3DCOLOR used for multi-texture blend */ - D3DRS_WRAP0 = 128, /* wrap for 1st texture coord. set */ - D3DRS_WRAP1 = 129, /* wrap for 2nd texture coord. set */ - D3DRS_WRAP2 = 130, /* wrap for 3rd texture coord. set */ - D3DRS_WRAP3 = 131, /* wrap for 4th texture coord. set */ - D3DRS_WRAP4 = 132, /* wrap for 5th texture coord. set */ - D3DRS_WRAP5 = 133, /* wrap for 6th texture coord. set */ - D3DRS_WRAP6 = 134, /* wrap for 7th texture coord. set */ - D3DRS_WRAP7 = 135, /* wrap for 8th texture coord. set */ - D3DRS_CLIPPING = 136, - D3DRS_LIGHTING = 137, - D3DRS_AMBIENT = 139, - D3DRS_FOGVERTEXMODE = 140, - D3DRS_COLORVERTEX = 141, - D3DRS_LOCALVIEWER = 142, - D3DRS_NORMALIZENORMALS = 143, - D3DRS_DIFFUSEMATERIALSOURCE = 145, - D3DRS_SPECULARMATERIALSOURCE = 146, - D3DRS_AMBIENTMATERIALSOURCE = 147, - D3DRS_EMISSIVEMATERIALSOURCE = 148, - D3DRS_VERTEXBLEND = 151, - D3DRS_CLIPPLANEENABLE = 152, - D3DRS_SOFTWAREVERTEXPROCESSING = 153, - D3DRS_POINTSIZE = 154, /* float point size */ - D3DRS_POINTSIZE_MIN = 155, /* float point size min threshold */ - D3DRS_POINTSPRITEENABLE = 156, /* BOOL point texture coord control */ - D3DRS_POINTSCALEENABLE = 157, /* BOOL point size scale enable */ - D3DRS_POINTSCALE_A = 158, /* float point attenuation A value */ - D3DRS_POINTSCALE_B = 159, /* float point attenuation B value */ - D3DRS_POINTSCALE_C = 160, /* float point attenuation C value */ - D3DRS_MULTISAMPLEANTIALIAS = 161, /* BOOL - set to do FSAA with multisample buffer */ - D3DRS_MULTISAMPLEMASK = 162, /* DWORD - per-sample enable/disable */ - D3DRS_PATCHEDGESTYLE = 163, /* Sets whether patch edges will use float style tessellation */ - D3DRS_PATCHSEGMENTS = 164, /* Number of segments per edge when drawing patches */ - D3DRS_DEBUGMONITORTOKEN = 165, /* DEBUG ONLY - token to debug monitor */ - D3DRS_POINTSIZE_MAX = 166, /* float point size max threshold */ - D3DRS_INDEXEDVERTEXBLENDENABLE = 167, - D3DRS_COLORWRITEENABLE = 168, /* per-channel write enable */ - D3DRS_TWEENFACTOR = 170, /* float tween factor */ - D3DRS_BLENDOP = 171, /* D3DBLENDOP setting */ - D3DRS_POSITIONORDER = 172, /* NPatch position interpolation order. D3DORDER_LINEAR or D3DORDER_CUBIC (default) */ - D3DRS_NORMALORDER = 173, /* NPatch normal interpolation order. D3DORDER_LINEAR (default) or D3DORDER_QUADRATIC */ - - D3DRS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DRENDERSTATETYPE; - -/* Values for material source */ -typedef enum _D3DMATERIALCOLORSOURCE -{ - D3DMCS_MATERIAL = 0, /* Color from material is used */ - D3DMCS_COLOR1 = 1, /* Diffuse vertex color is used */ - D3DMCS_COLOR2 = 2, /* Specular vertex color is used */ - D3DMCS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DMATERIALCOLORSOURCE; - -/* Bias to apply to the texture coordinate set to apply a wrap to. */ -#define D3DRENDERSTATE_WRAPBIAS 128UL - -/* Flags to construct the WRAP render states */ -#define D3DWRAP_U 0x00000001L -#define D3DWRAP_V 0x00000002L -#define D3DWRAP_W 0x00000004L - -/* Flags to construct the WRAP render states for 1D thru 4D texture coordinates */ -#define D3DWRAPCOORD_0 0x00000001L /* same as D3DWRAP_U */ -#define D3DWRAPCOORD_1 0x00000002L /* same as D3DWRAP_V */ -#define D3DWRAPCOORD_2 0x00000004L /* same as D3DWRAP_W */ -#define D3DWRAPCOORD_3 0x00000008L - -/* Flags to construct D3DRS_COLORWRITEENABLE */ -#define D3DCOLORWRITEENABLE_RED (1L<<0) -#define D3DCOLORWRITEENABLE_GREEN (1L<<1) -#define D3DCOLORWRITEENABLE_BLUE (1L<<2) -#define D3DCOLORWRITEENABLE_ALPHA (1L<<3) - -/* - * State enumerants for per-stage texture processing. - */ -typedef enum _D3DTEXTURESTAGESTATETYPE -{ - D3DTSS_COLOROP = 1, /* D3DTEXTUREOP - per-stage blending controls for color channels */ - D3DTSS_COLORARG1 = 2, /* D3DTA_* (texture arg) */ - D3DTSS_COLORARG2 = 3, /* D3DTA_* (texture arg) */ - D3DTSS_ALPHAOP = 4, /* D3DTEXTUREOP - per-stage blending controls for alpha channel */ - D3DTSS_ALPHAARG1 = 5, /* D3DTA_* (texture arg) */ - D3DTSS_ALPHAARG2 = 6, /* D3DTA_* (texture arg) */ - D3DTSS_BUMPENVMAT00 = 7, /* float (bump mapping matrix) */ - D3DTSS_BUMPENVMAT01 = 8, /* float (bump mapping matrix) */ - D3DTSS_BUMPENVMAT10 = 9, /* float (bump mapping matrix) */ - D3DTSS_BUMPENVMAT11 = 10, /* float (bump mapping matrix) */ - D3DTSS_TEXCOORDINDEX = 11, /* identifies which set of texture coordinates index this texture */ - D3DTSS_ADDRESSU = 13, /* D3DTEXTUREADDRESS for U coordinate */ - D3DTSS_ADDRESSV = 14, /* D3DTEXTUREADDRESS for V coordinate */ - D3DTSS_BORDERCOLOR = 15, /* D3DCOLOR */ - D3DTSS_MAGFILTER = 16, /* D3DTEXTUREFILTER filter to use for magnification */ - D3DTSS_MINFILTER = 17, /* D3DTEXTUREFILTER filter to use for minification */ - D3DTSS_MIPFILTER = 18, /* D3DTEXTUREFILTER filter to use between mipmaps during minification */ - D3DTSS_MIPMAPLODBIAS = 19, /* float Mipmap LOD bias */ - D3DTSS_MAXMIPLEVEL = 20, /* DWORD 0..(n-1) LOD index of largest map to use (0 == largest) */ - D3DTSS_MAXANISOTROPY = 21, /* DWORD maximum anisotropy */ - D3DTSS_BUMPENVLSCALE = 22, /* float scale for bump map luminance */ - D3DTSS_BUMPENVLOFFSET = 23, /* float offset for bump map luminance */ - D3DTSS_TEXTURETRANSFORMFLAGS = 24, /* D3DTEXTURETRANSFORMFLAGS controls texture transform */ - D3DTSS_ADDRESSW = 25, /* D3DTEXTUREADDRESS for W coordinate */ - D3DTSS_COLORARG0 = 26, /* D3DTA_* third arg for triadic ops */ - D3DTSS_ALPHAARG0 = 27, /* D3DTA_* third arg for triadic ops */ - D3DTSS_RESULTARG = 28, /* D3DTA_* arg for result (CURRENT or TEMP) */ - D3DTSS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ -} D3DTEXTURESTAGESTATETYPE; - -/* Values, used with D3DTSS_TEXCOORDINDEX, to specify that the vertex data(position - * and normal in the camera space) should be taken as texture coordinates - * Low 16 bits are used to specify texture coordinate index, to take the WRAP mode from - */ -#define D3DTSS_TCI_PASSTHRU 0x00000000 -#define D3DTSS_TCI_CAMERASPACENORMAL 0x00010000 -#define D3DTSS_TCI_CAMERASPACEPOSITION 0x00020000 -#define D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 0x00030000 - -/* - * Enumerations for COLOROP and ALPHAOP texture blending operations set in - * texture processing stage controls in D3DTSS. - */ -typedef enum _D3DTEXTUREOP -{ - /* Control */ - D3DTOP_DISABLE = 1, /* disables stage */ - D3DTOP_SELECTARG1 = 2, /* the default */ - D3DTOP_SELECTARG2 = 3, - - /* Modulate */ - D3DTOP_MODULATE = 4, /* multiply args together */ - D3DTOP_MODULATE2X = 5, /* multiply and 1 bit */ - D3DTOP_MODULATE4X = 6, /* multiply and 2 bits */ - - /* Add */ - D3DTOP_ADD = 7, /* add arguments together */ - D3DTOP_ADDSIGNED = 8, /* add with -0.5 bias */ - D3DTOP_ADDSIGNED2X = 9, /* as above but left 1 bit */ - D3DTOP_SUBTRACT = 10, /* Arg1 - Arg2, with no saturation */ - D3DTOP_ADDSMOOTH = 11, /* add 2 args, subtract product */ - /* Arg1 + Arg2 - Arg1*Arg2 */ - /* = Arg1 + (1-Arg1)*Arg2 */ - - /* Linear alpha blend: Arg1*(Alpha) + Arg2*(1-Alpha) */ - D3DTOP_BLENDDIFFUSEALPHA = 12, /* iterated alpha */ - D3DTOP_BLENDTEXTUREALPHA = 13, /* texture alpha */ - D3DTOP_BLENDFACTORALPHA = 14, /* alpha from D3DRS_TEXTUREFACTOR */ - - /* Linear alpha blend with pre-multiplied arg1 input: Arg1 + Arg2*(1-Alpha) */ - D3DTOP_BLENDTEXTUREALPHAPM = 15, /* texture alpha */ - D3DTOP_BLENDCURRENTALPHA = 16, /* by alpha of current color */ - - /* Specular mapping */ - D3DTOP_PREMODULATE = 17, /* modulate with next texture before use */ - D3DTOP_MODULATEALPHA_ADDCOLOR = 18, /* Arg1.RGB + Arg1.A*Arg2.RGB */ - /* COLOROP only */ - D3DTOP_MODULATECOLOR_ADDALPHA = 19, /* Arg1.RGB*Arg2.RGB + Arg1.A */ - /* COLOROP only */ - D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20, /* (1-Arg1.A)*Arg2.RGB + Arg1.RGB */ - /* COLOROP only */ - D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21, /* (1-Arg1.RGB)*Arg2.RGB + Arg1.A */ - /* COLOROP only */ - - /* Bump mapping */ - D3DTOP_BUMPENVMAP = 22, /* per pixel env map perturbation */ - D3DTOP_BUMPENVMAPLUMINANCE = 23, /* with luminance channel */ - - /* This can do either diffuse or specular bump mapping with correct input. - * Performs the function (Arg1.R*Arg2.R + Arg1.G*Arg2.G + Arg1.B*Arg2.B) - * where each component has been scaled and offset to make it signed. - * The result is replicated into all four (including alpha) channels. - * This is a valid COLOROP only. - */ - D3DTOP_DOTPRODUCT3 = 24, - - /* Triadic ops */ - D3DTOP_MULTIPLYADD = 25, /* Arg0 + Arg1*Arg2 */ - D3DTOP_LERP = 26, /* (Arg0)*Arg1 + (1-Arg0)*Arg2 */ - - D3DTOP_FORCE_DWORD = 0x7fffffff -} D3DTEXTUREOP; - -/* - * Values for COLORARG0,1,2, ALPHAARG0,1,2, and RESULTARG texture blending - * operations set in texture processing stage controls in D3DRENDERSTATE. - */ -#define D3DTA_SELECTMASK 0x0000000f /* mask for arg selector */ -#define D3DTA_DIFFUSE 0x00000000 /* select diffuse color (read only) */ -#define D3DTA_CURRENT 0x00000001 /* select stage destination register (read/write) */ -#define D3DTA_TEXTURE 0x00000002 /* select texture color (read only) */ -#define D3DTA_TFACTOR 0x00000003 /* select D3DRS_TEXTUREFACTOR (read only) */ -#define D3DTA_SPECULAR 0x00000004 /* select specular color (read only) */ -#define D3DTA_TEMP 0x00000005 /* select temporary register color (read/write) */ -#define D3DTA_COMPLEMENT 0x00000010 /* take 1.0 - x (read modifier) */ -#define D3DTA_ALPHAREPLICATE 0x00000020 /* replicate alpha to color components (read modifier) */ - -/* Values for D3DTSS_***FILTER texture stage states */ -typedef enum _D3DTEXTUREFILTERTYPE -{ - D3DTEXF_NONE = 0, /* filtering disabled (valid for mip filter only) */ - D3DTEXF_POINT = 1, /* nearest */ - D3DTEXF_LINEAR = 2, /* linear interpolation */ - D3DTEXF_ANISOTROPIC = 3, /* anisotropic */ - D3DTEXF_FLATCUBIC = 4, /* cubic */ - D3DTEXF_GAUSSIANCUBIC = 5, /* different cubic kernel */ - D3DTEXF_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DTEXTUREFILTERTYPE; - -/* Bits for Flags in ProcessVertices call */ - -#define D3DPV_DONOTCOPYDATA (1 << 0) - -/*------------------------------------------------------------------- */ - -/* Flexible vertex format bits */ -#define D3DFVF_RESERVED0 0x001 -#define D3DFVF_POSITION_MASK 0x00E -#define D3DFVF_XYZ 0x002 -#define D3DFVF_XYZRHW 0x004 -#define D3DFVF_XYZB1 0x006 -#define D3DFVF_XYZB2 0x008 -#define D3DFVF_XYZB3 0x00a -#define D3DFVF_XYZB4 0x00c -#define D3DFVF_XYZB5 0x00e - -#define D3DFVF_NORMAL 0x010 -#define D3DFVF_PSIZE 0x020 -#define D3DFVF_DIFFUSE 0x040 -#define D3DFVF_SPECULAR 0x080 - -#define D3DFVF_TEXCOUNT_MASK 0xf00 -#define D3DFVF_TEXCOUNT_SHIFT 8 -#define D3DFVF_TEX0 0x000 -#define D3DFVF_TEX1 0x100 -#define D3DFVF_TEX2 0x200 -#define D3DFVF_TEX3 0x300 -#define D3DFVF_TEX4 0x400 -#define D3DFVF_TEX5 0x500 -#define D3DFVF_TEX6 0x600 -#define D3DFVF_TEX7 0x700 -#define D3DFVF_TEX8 0x800 - -#define D3DFVF_LASTBETA_UBYTE4 0x1000 - -#define D3DFVF_RESERVED2 0xE000 /* 4 reserved bits */ - -/*--------------------------------------------------------------------- - * Vertex Shaders - */ - -/* - -Vertex Shader Declaration - -The declaration portion of a vertex shader defines the static external -interface of the shader. The information in the declaration includes: - -- Assignments of vertex shader input registers to data streams. These -assignments bind a specific vertex register to a single component within a -vertex stream. A vertex stream element is identified by a byte offset -within the stream and a type. The type specifies the arithmetic data type -plus the dimensionality (1, 2, 3, or 4 values). Stream data which is -less than 4 values are always expanded out to 4 values with zero or more -0.F values and one 1.F value. - -- Assignment of vertex shader input registers to implicit data from the -primitive tessellator. This controls the loading of vertex data which is -not loaded from a stream, but rather is generated during primitive -tessellation prior to the vertex shader. - -- Loading data into the constant memory at the time a shader is set as the -current shader. Each token specifies values for one or more contiguous 4 -DWORD constant registers. This allows the shader to update an arbitrary -subset of the constant memory, overwriting the device state (which -contains the current values of the constant memory). Note that these -values can be subsequently overwritten (between DrawPrimitive calls) -during the time a shader is bound to a device via the -SetVertexShaderConstant method. - - -Declaration arrays are single-dimensional arrays of DWORDs composed of -multiple tokens each of which is one or more DWORDs. The single-DWORD -token value 0xFFFFFFFF is a special token used to indicate the end of the -declaration array. The single DWORD token value 0x00000000 is a NOP token -with is ignored during the declaration parsing. Note that 0x00000000 is a -valid value for DWORDs following the first DWORD for multiple word tokens. - -[31:29] TokenType - 0x0 - NOP (requires all DWORD bits to be zero) - 0x1 - stream selector - 0x2 - stream data definition (map to vertex input memory) - 0x3 - vertex input memory from tessellator - 0x4 - constant memory from shader - 0x5 - extension - 0x6 - reserved - 0x7 - end-of-array (requires all DWORD bits to be 1) - -NOP Token (single DWORD token) - [31:29] 0x0 - [28:00] 0x0 - -Stream Selector (single DWORD token) - [31:29] 0x1 - [28] indicates whether this is a tessellator stream - [27:04] 0x0 - [03:00] stream selector (0..15) - -Stream Data Definition (single DWORD token) - Vertex Input Register Load - [31:29] 0x2 - [28] 0x0 - [27:20] 0x0 - [19:16] type (dimensionality and data type) - [15:04] 0x0 - [03:00] vertex register address (0..15) - Data Skip (no register load) - [31:29] 0x2 - [28] 0x1 - [27:20] 0x0 - [19:16] count of DWORDS to skip over (0..15) - [15:00] 0x0 - Vertex Input Memory from Tessellator Data (single DWORD token) - [31:29] 0x3 - [28] indicates whether data is normals or u/v - [27:24] 0x0 - [23:20] vertex register address (0..15) - [19:16] type (dimensionality) - [15:04] 0x0 - [03:00] vertex register address (0..15) - -Constant Memory from Shader (multiple DWORD token) - [31:29] 0x4 - [28:25] count of 4*DWORD constants to load (0..15) - [24:07] 0x0 - [06:00] constant memory address (0..95) - -Extension Token (single or multiple DWORD token) - [31:29] 0x5 - [28:24] count of additional DWORDs in token (0..31) - [23:00] extension-specific information - -End-of-array token (single DWORD token) - [31:29] 0x7 - [28:00] 0x1fffffff - -The stream selector token must be immediately followed by a contiguous set of stream data definition tokens. This token sequence fully defines that stream, including the set of elements within the stream, the order in which the elements appear, the type of each element, and the vertex register into which to load an element. -Streams are allowed to include data which is not loaded into a vertex register, thus allowing data which is not used for this shader to exist in the vertex stream. This skipped data is defined only by a count of DWORDs to skip over, since the type information is irrelevant. -The token sequence: -Stream Select: stream=0 -Stream Data Definition (Load): type=FLOAT3; register=3 -Stream Data Definition (Load): type=FLOAT3; register=4 -Stream Data Definition (Skip): count=2 -Stream Data Definition (Load): type=FLOAT2; register=7 - -defines stream zero to consist of 4 elements, 3 of which are loaded into registers and the fourth skipped over. Register 3 is loaded with the first three DWORDs in each vertex interpreted as FLOAT data. Register 4 is loaded with the 4th, 5th, and 6th DWORDs interpreted as FLOAT data. The next two DWORDs (7th and 8th) are skipped over and not loaded into any vertex input register. Register 7 is loaded with the 9th and 10th DWORDS interpreted as FLOAT data. -Placing of tokens other than NOPs between the Stream Selector and Stream Data Definition tokens is disallowed. - -*/ - -typedef enum _D3DVSD_TOKENTYPE -{ - D3DVSD_TOKEN_NOP = 0, /* NOP or extension */ - D3DVSD_TOKEN_STREAM, /* stream selector */ - D3DVSD_TOKEN_STREAMDATA, /* stream data definition (map to vertex input memory) */ - D3DVSD_TOKEN_TESSELLATOR, /* vertex input memory from tessellator */ - D3DVSD_TOKEN_CONSTMEM, /* constant memory from shader */ - D3DVSD_TOKEN_EXT, /* extension */ - D3DVSD_TOKEN_END = 7, /* end-of-array (requires all DWORD bits to be 1) */ - D3DVSD_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DVSD_TOKENTYPE; - -#define D3DVSD_TOKENTYPESHIFT 29 -#define D3DVSD_TOKENTYPEMASK (7 << D3DVSD_TOKENTYPESHIFT) - -#define D3DVSD_STREAMNUMBERSHIFT 0 -#define D3DVSD_STREAMNUMBERMASK (0xF << D3DVSD_STREAMNUMBERSHIFT) - -#define D3DVSD_DATALOADTYPESHIFT 28 -#define D3DVSD_DATALOADTYPEMASK (0x1 << D3DVSD_DATALOADTYPESHIFT) - -#define D3DVSD_DATATYPESHIFT 16 -#define D3DVSD_DATATYPEMASK (0xF << D3DVSD_DATATYPESHIFT) - -#define D3DVSD_SKIPCOUNTSHIFT 16 -#define D3DVSD_SKIPCOUNTMASK (0xF << D3DVSD_SKIPCOUNTSHIFT) - -#define D3DVSD_VERTEXREGSHIFT 0 -#define D3DVSD_VERTEXREGMASK (0x1F << D3DVSD_VERTEXREGSHIFT) - -#define D3DVSD_VERTEXREGINSHIFT 20 -#define D3DVSD_VERTEXREGINMASK (0xF << D3DVSD_VERTEXREGINSHIFT) - -#define D3DVSD_CONSTCOUNTSHIFT 25 -#define D3DVSD_CONSTCOUNTMASK (0xF << D3DVSD_CONSTCOUNTSHIFT) - -#define D3DVSD_CONSTADDRESSSHIFT 0 -#define D3DVSD_CONSTADDRESSMASK (0x7F << D3DVSD_CONSTADDRESSSHIFT) - -#define D3DVSD_CONSTRSSHIFT 16 -#define D3DVSD_CONSTRSMASK (0x1FFF << D3DVSD_CONSTRSSHIFT) - -#define D3DVSD_EXTCOUNTSHIFT 24 -#define D3DVSD_EXTCOUNTMASK (0x1F << D3DVSD_EXTCOUNTSHIFT) - -#define D3DVSD_EXTINFOSHIFT 0 -#define D3DVSD_EXTINFOMASK (0xFFFFFF << D3DVSD_EXTINFOSHIFT) - -#define D3DVSD_MAKETOKENTYPE(tokenType) ((tokenType << D3DVSD_TOKENTYPESHIFT) & D3DVSD_TOKENTYPEMASK) - -/* macros for generation of CreateVertexShader Declaration token array */ - -/* Set current stream - * _StreamNumber [0..(MaxStreams-1)] stream to get data from - */ -#define D3DVSD_STREAM( _StreamNumber ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAM) | (_StreamNumber)) - -/* Set tessellator stream - */ -#define D3DVSD_STREAMTESSSHIFT 28 -#define D3DVSD_STREAMTESSMASK (1 << D3DVSD_STREAMTESSSHIFT) -#define D3DVSD_STREAM_TESS( ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAM) | (D3DVSD_STREAMTESSMASK)) - -/* bind single vertex register to vertex element from vertex stream - * - * _VertexRegister [0..15] address of the vertex register - * _Type [D3DVSDT_*] dimensionality and arithmetic data type - */ - -#define D3DVSD_REG( _VertexRegister, _Type ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAMDATA) | \ - ((_Type) << D3DVSD_DATATYPESHIFT) | (_VertexRegister)) - -/* Skip _DWORDCount DWORDs in vertex - */ -#define D3DVSD_SKIP( _DWORDCount ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAMDATA) | 0x10000000 | \ - ((_DWORDCount) << D3DVSD_SKIPCOUNTSHIFT)) - -/* load data into vertex shader constant memory - * - * _ConstantAddress [0..95] - address of constant array to begin filling data - * _Count [0..15] - number of constant vectors to load (4 DWORDs each) - * followed by 4*_Count DWORDS of data - */ -#define D3DVSD_CONST( _ConstantAddress, _Count ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_CONSTMEM) | \ - ((_Count) << D3DVSD_CONSTCOUNTSHIFT) | (_ConstantAddress)) - -/* enable tessellator generated normals - * - * _VertexRegisterIn [0..15] address of vertex register whose input stream - * will be used in normal computation - * _VertexRegisterOut [0..15] address of vertex register to output the normal to - */ -#define D3DVSD_TESSNORMAL( _VertexRegisterIn, _VertexRegisterOut ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_TESSELLATOR) | \ - ((_VertexRegisterIn) << D3DVSD_VERTEXREGINSHIFT) | \ - ((0x02) << D3DVSD_DATATYPESHIFT) | (_VertexRegisterOut)) - -/* enable tessellator generated surface parameters - * - * _VertexRegister [0..15] address of vertex register to output parameters - */ -#define D3DVSD_TESSUV( _VertexRegister ) \ - (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_TESSELLATOR) | 0x10000000 | \ - ((0x01) << D3DVSD_DATATYPESHIFT) | (_VertexRegister)) - -/* Generates END token - */ -#define D3DVSD_END() 0xFFFFFFFF - -/* Generates NOP token */ -#define D3DVSD_NOP() 0x00000000 - -/* bit declarations for _Type fields */ -#define D3DVSDT_FLOAT1 0x00 /* 1D float expanded to (value, 0., 0., 1.) */ -#define D3DVSDT_FLOAT2 0x01 /* 2D float expanded to (value, value, 0., 1.) */ -#define D3DVSDT_FLOAT3 0x02 /* 3D float expanded to (value, value, value, 1.) */ -#define D3DVSDT_FLOAT4 0x03 /* 4D float */ -#define D3DVSDT_D3DCOLOR 0x04 /* 4D packed unsigned bytes mapped to 0. to 1. range - * Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A) */ -#define D3DVSDT_UBYTE4 0x05 /* 4D unsigned byte */ -#define D3DVSDT_SHORT2 0x06 /* 2D signed short expanded to (value, value, 0., 1.) */ -#define D3DVSDT_SHORT4 0x07 /* 4D signed short */ - -/* assignments of vertex input registers for fixed function vertex shader */ -#define D3DVSDE_POSITION 0 -#define D3DVSDE_BLENDWEIGHT 1 -#define D3DVSDE_BLENDINDICES 2 -#define D3DVSDE_NORMAL 3 -#define D3DVSDE_PSIZE 4 -#define D3DVSDE_DIFFUSE 5 -#define D3DVSDE_SPECULAR 6 -#define D3DVSDE_TEXCOORD0 7 -#define D3DVSDE_TEXCOORD1 8 -#define D3DVSDE_TEXCOORD2 9 -#define D3DVSDE_TEXCOORD3 10 -#define D3DVSDE_TEXCOORD4 11 -#define D3DVSDE_TEXCOORD5 12 -#define D3DVSDE_TEXCOORD6 13 -#define D3DVSDE_TEXCOORD7 14 -#define D3DVSDE_POSITION2 15 -#define D3DVSDE_NORMAL2 16 - -/* Maximum supported number of texture coordinate sets */ -#define D3DDP_MAXTEXCOORD 8 - - -/* Instruction Token Bit Definitions */ -#define D3DSI_OPCODE_MASK 0x0000FFFF - -typedef enum _D3DSHADER_INSTRUCTION_OPCODE_TYPE -{ - D3DSIO_NOP = 0, /* PS/VS */ - D3DSIO_MOV , /* PS/VS */ - D3DSIO_ADD , /* PS/VS */ - D3DSIO_SUB , /* PS */ - D3DSIO_MAD , /* PS/VS */ - D3DSIO_MUL , /* PS/VS */ - D3DSIO_RCP , /* VS */ - D3DSIO_RSQ , /* VS */ - D3DSIO_DP3 , /* PS/VS */ - D3DSIO_DP4 , /* PS/VS */ - D3DSIO_MIN , /* VS */ - D3DSIO_MAX , /* VS */ - D3DSIO_SLT , /* VS */ - D3DSIO_SGE , /* VS */ - D3DSIO_EXP , /* VS */ - D3DSIO_LOG , /* VS */ - D3DSIO_LIT , /* VS */ - D3DSIO_DST , /* VS */ - D3DSIO_LRP , /* PS */ - D3DSIO_FRC , /* VS */ - D3DSIO_M4x4 , /* VS */ - D3DSIO_M4x3 , /* VS */ - D3DSIO_M3x4 , /* VS */ - D3DSIO_M3x3 , /* VS */ - D3DSIO_M3x2 , /* VS */ - - D3DSIO_TEXCOORD = 64, /* PS */ - D3DSIO_TEXKILL , /* PS */ - D3DSIO_TEX , /* PS */ - D3DSIO_TEXBEM , /* PS */ - D3DSIO_TEXBEML , /* PS */ - D3DSIO_TEXREG2AR , /* PS */ - D3DSIO_TEXREG2GB , /* PS */ - D3DSIO_TEXM3x2PAD , /* PS */ - D3DSIO_TEXM3x2TEX , /* PS */ - D3DSIO_TEXM3x3PAD , /* PS */ - D3DSIO_TEXM3x3TEX , /* PS */ - D3DSIO_TEXM3x3DIFF , /* PS */ - D3DSIO_TEXM3x3SPEC , /* PS */ - D3DSIO_TEXM3x3VSPEC , /* PS */ - D3DSIO_EXPP , /* VS */ - D3DSIO_LOGP , /* VS */ - D3DSIO_CND , /* PS */ - D3DSIO_DEF , /* PS */ - D3DSIO_TEXREG2RGB , /* PS */ - D3DSIO_TEXDP3TEX , /* PS */ - D3DSIO_TEXM3x2DEPTH , /* PS */ - D3DSIO_TEXDP3 , /* PS */ - D3DSIO_TEXM3x3 , /* PS */ - D3DSIO_TEXDEPTH , /* PS */ - D3DSIO_CMP , /* PS */ - D3DSIO_BEM , /* PS */ - - D3DSIO_PHASE = 0xFFFD, - D3DSIO_COMMENT = 0xFFFE, - D3DSIO_END = 0xFFFF, - - D3DSIO_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ -} D3DSHADER_INSTRUCTION_OPCODE_TYPE; - -/* Co-Issue Instruction Modifier - if set then this instruction is to be - * issued in parallel with the previous instruction(s) for which this bit - * is not set. */ -#define D3DSI_COISSUE 0x40000000 - -/* Parameter Token Bit Definitions */ -#define D3DSP_REGNUM_MASK 0x00001FFF - -/* destination parameter write mask */ -#define D3DSP_WRITEMASK_0 0x00010000 /* Component 0 (X;Red) */ -#define D3DSP_WRITEMASK_1 0x00020000 /* Component 1 (Y;Green) */ -#define D3DSP_WRITEMASK_2 0x00040000 /* Component 2 (Z;Blue) */ -#define D3DSP_WRITEMASK_3 0x00080000 /* Component 3 (W;Alpha) */ -#define D3DSP_WRITEMASK_ALL 0x000F0000 /* All Components */ - -/* destination parameter modifiers */ -#define D3DSP_DSTMOD_SHIFT 20 -#define D3DSP_DSTMOD_MASK 0x00F00000 - -typedef enum _D3DSHADER_PARAM_DSTMOD_TYPE -{ - D3DSPDM_NONE = 0<>8)&0xFF) -#define D3DSHADER_VERSION_MINOR(_Version) (((_Version)>>0)&0xFF) - -/* destination/source parameter register type */ -#define D3DSI_COMMENTSIZE_SHIFT 16 -#define D3DSI_COMMENTSIZE_MASK 0x7FFF0000 -#define D3DSHADER_COMMENT(_DWordSize) \ - ((((_DWordSize)<= 1200 -#pragma warning(pop) -#else -#pragma warning(default:4201) -#endif - -#endif /* (DIRECT3D_VERSION >= 0x0800) */ -#endif /* _D3D8TYPES(P)_H_ */ +/*==========================================================================; + * + * Copyright (C) Microsoft Corporation. All Rights Reserved. + * + * File: d3d8types.h + * Content: Direct3D capabilities include file + * + ***************************************************************************/ + +#ifndef _D3D8TYPES_H_ +#define _D3D8TYPES_H_ + +#ifndef DIRECT3D_VERSION +#define DIRECT3D_VERSION 0x0800 +#endif /* DIRECT3D_VERSION */ + +/* include this file content only if compiling for DX8 interfaces */ +#if(DIRECT3D_VERSION >= 0x0800) + +#include + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4201) /* anonymous unions warning */ +#if defined(_X86_) || defined(_IA64_) +#pragma pack(4) +#endif + +/* D3DCOLOR is equivalent to D3DFMT_A8R8G8B8 */ +#ifndef D3DCOLOR_DEFINED +typedef DWORD D3DCOLOR; +#define D3DCOLOR_DEFINED +#endif + +/* maps unsigned 8 bits/channel to D3DCOLOR */ +#define D3DCOLOR_ARGB(a,r,g,b) \ + ((D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#define D3DCOLOR_RGBA(r,g,b,a) D3DCOLOR_ARGB(a,r,g,b) +#define D3DCOLOR_XRGB(r,g,b) D3DCOLOR_ARGB(0xff,r,g,b) + +/* maps floating point channels (0.f to 1.f range) to D3DCOLOR */ +#define D3DCOLOR_COLORVALUE(r,g,b,a) \ + D3DCOLOR_RGBA((DWORD)((r)*255.f),(DWORD)((g)*255.f),(DWORD)((b)*255.f),(DWORD)((a)*255.f)) + + +#ifndef D3DVECTOR_DEFINED +typedef struct _D3DVECTOR { + float x; + float y; + float z; +} D3DVECTOR; +#define D3DVECTOR_DEFINED +#endif + +#ifndef D3DCOLORVALUE_DEFINED +typedef struct _D3DCOLORVALUE { + float r; + float g; + float b; + float a; +} D3DCOLORVALUE; +#define D3DCOLORVALUE_DEFINED +#endif + +#ifndef D3DRECT_DEFINED +typedef struct _D3DRECT { + LONG x1; + LONG y1; + LONG x2; + LONG y2; +} D3DRECT; +#define D3DRECT_DEFINED +#endif + +#ifndef D3DMATRIX_DEFINED +typedef struct _D3DMATRIX { + union { + struct { + float _11, _12, _13, _14; + float _21, _22, _23, _24; + float _31, _32, _33, _34; + float _41, _42, _43, _44; + + }; + float m[4][4]; + }; +} D3DMATRIX; +#define D3DMATRIX_DEFINED +#endif + +typedef struct _D3DVIEWPORT8 { + DWORD X; + DWORD Y; /* Viewport Top left */ + DWORD Width; + DWORD Height; /* Viewport Dimensions */ + float MinZ; /* Min/max of clip Volume */ + float MaxZ; +} D3DVIEWPORT8; + +/* + * Values for clip fields. + */ + +/* Max number of user clipping planes, supported in D3D. */ +#define D3DMAXUSERCLIPPLANES 32 + +/* These bits could be ORed together to use with D3DRS_CLIPPLANEENABLE */ +#define D3DCLIPPLANE0 (1 << 0) +#define D3DCLIPPLANE1 (1 << 1) +#define D3DCLIPPLANE2 (1 << 2) +#define D3DCLIPPLANE3 (1 << 3) +#define D3DCLIPPLANE4 (1 << 4) +#define D3DCLIPPLANE5 (1 << 5) + +/* The following bits are used in the ClipUnion and ClipIntersection + * members of the D3DCLIPSTATUS8 + */ + +#define D3DCS_LEFT 0x00000001L +#define D3DCS_RIGHT 0x00000002L +#define D3DCS_TOP 0x00000004L +#define D3DCS_BOTTOM 0x00000008L +#define D3DCS_FRONT 0x00000010L +#define D3DCS_BACK 0x00000020L +#define D3DCS_PLANE0 0x00000040L +#define D3DCS_PLANE1 0x00000080L +#define D3DCS_PLANE2 0x00000100L +#define D3DCS_PLANE3 0x00000200L +#define D3DCS_PLANE4 0x00000400L +#define D3DCS_PLANE5 0x00000800L + +#define D3DCS_ALL (D3DCS_LEFT | \ + D3DCS_RIGHT | \ + D3DCS_TOP | \ + D3DCS_BOTTOM | \ + D3DCS_FRONT | \ + D3DCS_BACK | \ + D3DCS_PLANE0 | \ + D3DCS_PLANE1 | \ + D3DCS_PLANE2 | \ + D3DCS_PLANE3 | \ + D3DCS_PLANE4 | \ + D3DCS_PLANE5) + +typedef struct _D3DCLIPSTATUS8 { + DWORD ClipUnion; + DWORD ClipIntersection; +} D3DCLIPSTATUS8; + +typedef struct _D3DMATERIAL8 { + D3DCOLORVALUE Diffuse; /* Diffuse color RGBA */ + D3DCOLORVALUE Ambient; /* Ambient color RGB */ + D3DCOLORVALUE Specular; /* Specular 'shininess' */ + D3DCOLORVALUE Emissive; /* Emissive color RGB */ + float Power; /* Sharpness if specular highlight */ +} D3DMATERIAL8; + +typedef enum _D3DLIGHTTYPE { + D3DLIGHT_POINT = 1, + D3DLIGHT_SPOT = 2, + D3DLIGHT_DIRECTIONAL = 3, + D3DLIGHT_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DLIGHTTYPE; + +typedef struct _D3DLIGHT8 { + D3DLIGHTTYPE Type; /* Type of light source */ + D3DCOLORVALUE Diffuse; /* Diffuse color of light */ + D3DCOLORVALUE Specular; /* Specular color of light */ + D3DCOLORVALUE Ambient; /* Ambient color of light */ + D3DVECTOR Position; /* Position in world space */ + D3DVECTOR Direction; /* Direction in world space */ + float Range; /* Cutoff range */ + float Falloff; /* Falloff */ + float Attenuation0; /* Constant attenuation */ + float Attenuation1; /* Linear attenuation */ + float Attenuation2; /* Quadratic attenuation */ + float Theta; /* Inner angle of spotlight cone */ + float Phi; /* Outer angle of spotlight cone */ +} D3DLIGHT8; + +/* + * Options for clearing + */ +#define D3DCLEAR_TARGET 0x00000001l /* Clear target surface */ +#define D3DCLEAR_ZBUFFER 0x00000002l /* Clear target z buffer */ +#define D3DCLEAR_STENCIL 0x00000004l /* Clear stencil planes */ + +/* + * The following defines the rendering states + */ + +typedef enum _D3DSHADEMODE { + D3DSHADE_FLAT = 1, + D3DSHADE_GOURAUD = 2, + D3DSHADE_PHONG = 3, + D3DSHADE_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DSHADEMODE; + +typedef enum _D3DFILLMODE { + D3DFILL_POINT = 1, + D3DFILL_WIREFRAME = 2, + D3DFILL_SOLID = 3, + D3DFILL_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DFILLMODE; + +typedef struct _D3DLINEPATTERN { + WORD wRepeatFactor; + WORD wLinePattern; +} D3DLINEPATTERN; + +typedef enum _D3DBLEND { + D3DBLEND_ZERO = 1, + D3DBLEND_ONE = 2, + D3DBLEND_SRCCOLOR = 3, + D3DBLEND_INVSRCCOLOR = 4, + D3DBLEND_SRCALPHA = 5, + D3DBLEND_INVSRCALPHA = 6, + D3DBLEND_DESTALPHA = 7, + D3DBLEND_INVDESTALPHA = 8, + D3DBLEND_DESTCOLOR = 9, + D3DBLEND_INVDESTCOLOR = 10, + D3DBLEND_SRCALPHASAT = 11, + D3DBLEND_BOTHSRCALPHA = 12, + D3DBLEND_BOTHINVSRCALPHA = 13, + D3DBLEND_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DBLEND; + +typedef enum _D3DBLENDOP { + D3DBLENDOP_ADD = 1, + D3DBLENDOP_SUBTRACT = 2, + D3DBLENDOP_REVSUBTRACT = 3, + D3DBLENDOP_MIN = 4, + D3DBLENDOP_MAX = 5, + D3DBLENDOP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DBLENDOP; + +typedef enum _D3DTEXTUREADDRESS { + D3DTADDRESS_WRAP = 1, + D3DTADDRESS_MIRROR = 2, + D3DTADDRESS_CLAMP = 3, + D3DTADDRESS_BORDER = 4, + D3DTADDRESS_MIRRORONCE = 5, + D3DTADDRESS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DTEXTUREADDRESS; + +typedef enum _D3DCULL { + D3DCULL_NONE = 1, + D3DCULL_CW = 2, + D3DCULL_CCW = 3, + D3DCULL_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DCULL; + +typedef enum _D3DCMPFUNC { + D3DCMP_NEVER = 1, + D3DCMP_LESS = 2, + D3DCMP_EQUAL = 3, + D3DCMP_LESSEQUAL = 4, + D3DCMP_GREATER = 5, + D3DCMP_NOTEQUAL = 6, + D3DCMP_GREATEREQUAL = 7, + D3DCMP_ALWAYS = 8, + D3DCMP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DCMPFUNC; + +typedef enum _D3DSTENCILOP { + D3DSTENCILOP_KEEP = 1, + D3DSTENCILOP_ZERO = 2, + D3DSTENCILOP_REPLACE = 3, + D3DSTENCILOP_INCRSAT = 4, + D3DSTENCILOP_DECRSAT = 5, + D3DSTENCILOP_INVERT = 6, + D3DSTENCILOP_INCR = 7, + D3DSTENCILOP_DECR = 8, + D3DSTENCILOP_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DSTENCILOP; + +typedef enum _D3DFOGMODE { + D3DFOG_NONE = 0, + D3DFOG_EXP = 1, + D3DFOG_EXP2 = 2, + D3DFOG_LINEAR = 3, + D3DFOG_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DFOGMODE; + +typedef enum _D3DZBUFFERTYPE { + D3DZB_FALSE = 0, + D3DZB_TRUE = 1, /* Z buffering */ + D3DZB_USEW = 2, /* W buffering */ + D3DZB_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DZBUFFERTYPE; + +/* Primitives supported by draw-primitive API */ +typedef enum _D3DPRIMITIVETYPE { + D3DPT_POINTLIST = 1, + D3DPT_LINELIST = 2, + D3DPT_LINESTRIP = 3, + D3DPT_TRIANGLELIST = 4, + D3DPT_TRIANGLESTRIP = 5, + D3DPT_TRIANGLEFAN = 6, + D3DPT_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DPRIMITIVETYPE; + +typedef enum _D3DTRANSFORMSTATETYPE { + D3DTS_VIEW = 2, + D3DTS_PROJECTION = 3, + D3DTS_TEXTURE0 = 16, + D3DTS_TEXTURE1 = 17, + D3DTS_TEXTURE2 = 18, + D3DTS_TEXTURE3 = 19, + D3DTS_TEXTURE4 = 20, + D3DTS_TEXTURE5 = 21, + D3DTS_TEXTURE6 = 22, + D3DTS_TEXTURE7 = 23, + D3DTS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DTRANSFORMSTATETYPE; + +#define D3DTS_WORLDMATRIX(index) (D3DTRANSFORMSTATETYPE)(index + 256) +#define D3DTS_WORLD D3DTS_WORLDMATRIX(0) +#define D3DTS_WORLD1 D3DTS_WORLDMATRIX(1) +#define D3DTS_WORLD2 D3DTS_WORLDMATRIX(2) +#define D3DTS_WORLD3 D3DTS_WORLDMATRIX(3) + +typedef enum _D3DRENDERSTATETYPE { + D3DRS_ZENABLE = 7, /* D3DZBUFFERTYPE (or TRUE/FALSE for legacy) */ + D3DRS_FILLMODE = 8, /* D3DFILLMODE */ + D3DRS_SHADEMODE = 9, /* D3DSHADEMODE */ + D3DRS_LINEPATTERN = 10, /* D3DLINEPATTERN */ + D3DRS_ZWRITEENABLE = 14, /* TRUE to enable z writes */ + D3DRS_ALPHATESTENABLE = 15, /* TRUE to enable alpha tests */ + D3DRS_LASTPIXEL = 16, /* TRUE for last-pixel on lines */ + D3DRS_SRCBLEND = 19, /* D3DBLEND */ + D3DRS_DESTBLEND = 20, /* D3DBLEND */ + D3DRS_CULLMODE = 22, /* D3DCULL */ + D3DRS_ZFUNC = 23, /* D3DCMPFUNC */ + D3DRS_ALPHAREF = 24, /* D3DFIXED */ + D3DRS_ALPHAFUNC = 25, /* D3DCMPFUNC */ + D3DRS_DITHERENABLE = 26, /* TRUE to enable dithering */ + D3DRS_ALPHABLENDENABLE = 27, /* TRUE to enable alpha blending */ + D3DRS_FOGENABLE = 28, /* TRUE to enable fog blending */ + D3DRS_SPECULARENABLE = 29, /* TRUE to enable specular */ + D3DRS_ZVISIBLE = 30, /* TRUE to enable z checking */ + D3DRS_FOGCOLOR = 34, /* D3DCOLOR */ + D3DRS_FOGTABLEMODE = 35, /* D3DFOGMODE */ + D3DRS_FOGSTART = 36, /* Fog start (for both vertex and pixel fog) */ + D3DRS_FOGEND = 37, /* Fog end */ + D3DRS_FOGDENSITY = 38, /* Fog density */ + D3DRS_EDGEANTIALIAS = 40, /* TRUE to enable edge antialiasing */ + D3DRS_ZBIAS = 47, /* LONG Z bias */ + D3DRS_RANGEFOGENABLE = 48, /* Enables range-based fog */ + D3DRS_STENCILENABLE = 52, /* BOOL enable/disable stenciling */ + D3DRS_STENCILFAIL = 53, /* D3DSTENCILOP to do if stencil test fails */ + D3DRS_STENCILZFAIL = 54, /* D3DSTENCILOP to do if stencil test passes and Z test fails */ + D3DRS_STENCILPASS = 55, /* D3DSTENCILOP to do if both stencil and Z tests pass */ + D3DRS_STENCILFUNC = 56, /* D3DCMPFUNC fn. Stencil Test passes if ((ref & mask) stencilfn (stencil & mask)) is true */ + D3DRS_STENCILREF = 57, /* Reference value used in stencil test */ + D3DRS_STENCILMASK = 58, /* Mask value used in stencil test */ + D3DRS_STENCILWRITEMASK = 59, /* Write mask applied to values written to stencil buffer */ + D3DRS_TEXTUREFACTOR = 60, /* D3DCOLOR used for multi-texture blend */ + D3DRS_WRAP0 = 128, /* wrap for 1st texture coord. set */ + D3DRS_WRAP1 = 129, /* wrap for 2nd texture coord. set */ + D3DRS_WRAP2 = 130, /* wrap for 3rd texture coord. set */ + D3DRS_WRAP3 = 131, /* wrap for 4th texture coord. set */ + D3DRS_WRAP4 = 132, /* wrap for 5th texture coord. set */ + D3DRS_WRAP5 = 133, /* wrap for 6th texture coord. set */ + D3DRS_WRAP6 = 134, /* wrap for 7th texture coord. set */ + D3DRS_WRAP7 = 135, /* wrap for 8th texture coord. set */ + D3DRS_CLIPPING = 136, + D3DRS_LIGHTING = 137, + D3DRS_AMBIENT = 139, + D3DRS_FOGVERTEXMODE = 140, + D3DRS_COLORVERTEX = 141, + D3DRS_LOCALVIEWER = 142, + D3DRS_NORMALIZENORMALS = 143, + D3DRS_DIFFUSEMATERIALSOURCE = 145, + D3DRS_SPECULARMATERIALSOURCE = 146, + D3DRS_AMBIENTMATERIALSOURCE = 147, + D3DRS_EMISSIVEMATERIALSOURCE = 148, + D3DRS_VERTEXBLEND = 151, + D3DRS_CLIPPLANEENABLE = 152, + D3DRS_SOFTWAREVERTEXPROCESSING = 153, + D3DRS_POINTSIZE = 154, /* float point size */ + D3DRS_POINTSIZE_MIN = 155, /* float point size min threshold */ + D3DRS_POINTSPRITEENABLE = 156, /* BOOL point texture coord control */ + D3DRS_POINTSCALEENABLE = 157, /* BOOL point size scale enable */ + D3DRS_POINTSCALE_A = 158, /* float point attenuation A value */ + D3DRS_POINTSCALE_B = 159, /* float point attenuation B value */ + D3DRS_POINTSCALE_C = 160, /* float point attenuation C value */ + D3DRS_MULTISAMPLEANTIALIAS = 161, /* BOOL - set to do FSAA with multisample buffer */ + D3DRS_MULTISAMPLEMASK = 162, /* DWORD - per-sample enable/disable */ + D3DRS_PATCHEDGESTYLE = 163, /* Sets whether patch edges will use float style tessellation */ + D3DRS_PATCHSEGMENTS = 164, /* Number of segments per edge when drawing patches */ + D3DRS_DEBUGMONITORTOKEN = 165, /* DEBUG ONLY - token to debug monitor */ + D3DRS_POINTSIZE_MAX = 166, /* float point size max threshold */ + D3DRS_INDEXEDVERTEXBLENDENABLE = 167, + D3DRS_COLORWRITEENABLE = 168, /* per-channel write enable */ + D3DRS_TWEENFACTOR = 170, /* float tween factor */ + D3DRS_BLENDOP = 171, /* D3DBLENDOP setting */ + D3DRS_POSITIONORDER = 172, /* NPatch position interpolation order. D3DORDER_LINEAR or D3DORDER_CUBIC (default) */ + D3DRS_NORMALORDER = 173, /* NPatch normal interpolation order. D3DORDER_LINEAR (default) or D3DORDER_QUADRATIC */ + + D3DRS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DRENDERSTATETYPE; + +/* Values for material source */ +typedef enum _D3DMATERIALCOLORSOURCE +{ + D3DMCS_MATERIAL = 0, /* Color from material is used */ + D3DMCS_COLOR1 = 1, /* Diffuse vertex color is used */ + D3DMCS_COLOR2 = 2, /* Specular vertex color is used */ + D3DMCS_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DMATERIALCOLORSOURCE; + +/* Bias to apply to the texture coordinate set to apply a wrap to. */ +#define D3DRENDERSTATE_WRAPBIAS 128UL + +/* Flags to construct the WRAP render states */ +#define D3DWRAP_U 0x00000001L +#define D3DWRAP_V 0x00000002L +#define D3DWRAP_W 0x00000004L + +/* Flags to construct the WRAP render states for 1D thru 4D texture coordinates */ +#define D3DWRAPCOORD_0 0x00000001L /* same as D3DWRAP_U */ +#define D3DWRAPCOORD_1 0x00000002L /* same as D3DWRAP_V */ +#define D3DWRAPCOORD_2 0x00000004L /* same as D3DWRAP_W */ +#define D3DWRAPCOORD_3 0x00000008L + +/* Flags to construct D3DRS_COLORWRITEENABLE */ +#define D3DCOLORWRITEENABLE_RED (1L<<0) +#define D3DCOLORWRITEENABLE_GREEN (1L<<1) +#define D3DCOLORWRITEENABLE_BLUE (1L<<2) +#define D3DCOLORWRITEENABLE_ALPHA (1L<<3) + +/* + * State enumerants for per-stage texture processing. + */ +typedef enum _D3DTEXTURESTAGESTATETYPE +{ + D3DTSS_COLOROP = 1, /* D3DTEXTUREOP - per-stage blending controls for color channels */ + D3DTSS_COLORARG1 = 2, /* D3DTA_* (texture arg) */ + D3DTSS_COLORARG2 = 3, /* D3DTA_* (texture arg) */ + D3DTSS_ALPHAOP = 4, /* D3DTEXTUREOP - per-stage blending controls for alpha channel */ + D3DTSS_ALPHAARG1 = 5, /* D3DTA_* (texture arg) */ + D3DTSS_ALPHAARG2 = 6, /* D3DTA_* (texture arg) */ + D3DTSS_BUMPENVMAT00 = 7, /* float (bump mapping matrix) */ + D3DTSS_BUMPENVMAT01 = 8, /* float (bump mapping matrix) */ + D3DTSS_BUMPENVMAT10 = 9, /* float (bump mapping matrix) */ + D3DTSS_BUMPENVMAT11 = 10, /* float (bump mapping matrix) */ + D3DTSS_TEXCOORDINDEX = 11, /* identifies which set of texture coordinates index this texture */ + D3DTSS_ADDRESSU = 13, /* D3DTEXTUREADDRESS for U coordinate */ + D3DTSS_ADDRESSV = 14, /* D3DTEXTUREADDRESS for V coordinate */ + D3DTSS_BORDERCOLOR = 15, /* D3DCOLOR */ + D3DTSS_MAGFILTER = 16, /* D3DTEXTUREFILTER filter to use for magnification */ + D3DTSS_MINFILTER = 17, /* D3DTEXTUREFILTER filter to use for minification */ + D3DTSS_MIPFILTER = 18, /* D3DTEXTUREFILTER filter to use between mipmaps during minification */ + D3DTSS_MIPMAPLODBIAS = 19, /* float Mipmap LOD bias */ + D3DTSS_MAXMIPLEVEL = 20, /* DWORD 0..(n-1) LOD index of largest map to use (0 == largest) */ + D3DTSS_MAXANISOTROPY = 21, /* DWORD maximum anisotropy */ + D3DTSS_BUMPENVLSCALE = 22, /* float scale for bump map luminance */ + D3DTSS_BUMPENVLOFFSET = 23, /* float offset for bump map luminance */ + D3DTSS_TEXTURETRANSFORMFLAGS = 24, /* D3DTEXTURETRANSFORMFLAGS controls texture transform */ + D3DTSS_ADDRESSW = 25, /* D3DTEXTUREADDRESS for W coordinate */ + D3DTSS_COLORARG0 = 26, /* D3DTA_* third arg for triadic ops */ + D3DTSS_ALPHAARG0 = 27, /* D3DTA_* third arg for triadic ops */ + D3DTSS_RESULTARG = 28, /* D3DTA_* arg for result (CURRENT or TEMP) */ + D3DTSS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTEXTURESTAGESTATETYPE; + +/* Values, used with D3DTSS_TEXCOORDINDEX, to specify that the vertex data(position + * and normal in the camera space) should be taken as texture coordinates + * Low 16 bits are used to specify texture coordinate index, to take the WRAP mode from + */ +#define D3DTSS_TCI_PASSTHRU 0x00000000 +#define D3DTSS_TCI_CAMERASPACENORMAL 0x00010000 +#define D3DTSS_TCI_CAMERASPACEPOSITION 0x00020000 +#define D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 0x00030000 + +/* + * Enumerations for COLOROP and ALPHAOP texture blending operations set in + * texture processing stage controls in D3DTSS. + */ +typedef enum _D3DTEXTUREOP +{ + /* Control */ + D3DTOP_DISABLE = 1, /* disables stage */ + D3DTOP_SELECTARG1 = 2, /* the default */ + D3DTOP_SELECTARG2 = 3, + + /* Modulate */ + D3DTOP_MODULATE = 4, /* multiply args together */ + D3DTOP_MODULATE2X = 5, /* multiply and 1 bit */ + D3DTOP_MODULATE4X = 6, /* multiply and 2 bits */ + + /* Add */ + D3DTOP_ADD = 7, /* add arguments together */ + D3DTOP_ADDSIGNED = 8, /* add with -0.5 bias */ + D3DTOP_ADDSIGNED2X = 9, /* as above but left 1 bit */ + D3DTOP_SUBTRACT = 10, /* Arg1 - Arg2, with no saturation */ + D3DTOP_ADDSMOOTH = 11, /* add 2 args, subtract product */ + /* Arg1 + Arg2 - Arg1*Arg2 */ + /* = Arg1 + (1-Arg1)*Arg2 */ + + /* Linear alpha blend: Arg1*(Alpha) + Arg2*(1-Alpha) */ + D3DTOP_BLENDDIFFUSEALPHA = 12, /* iterated alpha */ + D3DTOP_BLENDTEXTUREALPHA = 13, /* texture alpha */ + D3DTOP_BLENDFACTORALPHA = 14, /* alpha from D3DRS_TEXTUREFACTOR */ + + /* Linear alpha blend with pre-multiplied arg1 input: Arg1 + Arg2*(1-Alpha) */ + D3DTOP_BLENDTEXTUREALPHAPM = 15, /* texture alpha */ + D3DTOP_BLENDCURRENTALPHA = 16, /* by alpha of current color */ + + /* Specular mapping */ + D3DTOP_PREMODULATE = 17, /* modulate with next texture before use */ + D3DTOP_MODULATEALPHA_ADDCOLOR = 18, /* Arg1.RGB + Arg1.A*Arg2.RGB */ + /* COLOROP only */ + D3DTOP_MODULATECOLOR_ADDALPHA = 19, /* Arg1.RGB*Arg2.RGB + Arg1.A */ + /* COLOROP only */ + D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20, /* (1-Arg1.A)*Arg2.RGB + Arg1.RGB */ + /* COLOROP only */ + D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21, /* (1-Arg1.RGB)*Arg2.RGB + Arg1.A */ + /* COLOROP only */ + + /* Bump mapping */ + D3DTOP_BUMPENVMAP = 22, /* per pixel env map perturbation */ + D3DTOP_BUMPENVMAPLUMINANCE = 23, /* with luminance channel */ + + /* This can do either diffuse or specular bump mapping with correct input. + * Performs the function (Arg1.R*Arg2.R + Arg1.G*Arg2.G + Arg1.B*Arg2.B) + * where each component has been scaled and offset to make it signed. + * The result is replicated into all four (including alpha) channels. + * This is a valid COLOROP only. + */ + D3DTOP_DOTPRODUCT3 = 24, + + /* Triadic ops */ + D3DTOP_MULTIPLYADD = 25, /* Arg0 + Arg1*Arg2 */ + D3DTOP_LERP = 26, /* (Arg0)*Arg1 + (1-Arg0)*Arg2 */ + + D3DTOP_FORCE_DWORD = 0x7fffffff +} D3DTEXTUREOP; + +/* + * Values for COLORARG0,1,2, ALPHAARG0,1,2, and RESULTARG texture blending + * operations set in texture processing stage controls in D3DRENDERSTATE. + */ +#define D3DTA_SELECTMASK 0x0000000f /* mask for arg selector */ +#define D3DTA_DIFFUSE 0x00000000 /* select diffuse color (read only) */ +#define D3DTA_CURRENT 0x00000001 /* select stage destination register (read/write) */ +#define D3DTA_TEXTURE 0x00000002 /* select texture color (read only) */ +#define D3DTA_TFACTOR 0x00000003 /* select D3DRS_TEXTUREFACTOR (read only) */ +#define D3DTA_SPECULAR 0x00000004 /* select specular color (read only) */ +#define D3DTA_TEMP 0x00000005 /* select temporary register color (read/write) */ +#define D3DTA_COMPLEMENT 0x00000010 /* take 1.0 - x (read modifier) */ +#define D3DTA_ALPHAREPLICATE 0x00000020 /* replicate alpha to color components (read modifier) */ + +/* Values for D3DTSS_***FILTER texture stage states */ +typedef enum _D3DTEXTUREFILTERTYPE +{ + D3DTEXF_NONE = 0, /* filtering disabled (valid for mip filter only) */ + D3DTEXF_POINT = 1, /* nearest */ + D3DTEXF_LINEAR = 2, /* linear interpolation */ + D3DTEXF_ANISOTROPIC = 3, /* anisotropic */ + D3DTEXF_FLATCUBIC = 4, /* cubic */ + D3DTEXF_GAUSSIANCUBIC = 5, /* different cubic kernel */ + D3DTEXF_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DTEXTUREFILTERTYPE; + +/* Bits for Flags in ProcessVertices call */ + +#define D3DPV_DONOTCOPYDATA (1 << 0) + +/*------------------------------------------------------------------- */ + +/* Flexible vertex format bits */ +#define D3DFVF_RESERVED0 0x001 +#define D3DFVF_POSITION_MASK 0x00E +#define D3DFVF_XYZ 0x002 +#define D3DFVF_XYZRHW 0x004 +#define D3DFVF_XYZB1 0x006 +#define D3DFVF_XYZB2 0x008 +#define D3DFVF_XYZB3 0x00a +#define D3DFVF_XYZB4 0x00c +#define D3DFVF_XYZB5 0x00e + +#define D3DFVF_NORMAL 0x010 +#define D3DFVF_PSIZE 0x020 +#define D3DFVF_DIFFUSE 0x040 +#define D3DFVF_SPECULAR 0x080 + +#define D3DFVF_TEXCOUNT_MASK 0xf00 +#define D3DFVF_TEXCOUNT_SHIFT 8 +#define D3DFVF_TEX0 0x000 +#define D3DFVF_TEX1 0x100 +#define D3DFVF_TEX2 0x200 +#define D3DFVF_TEX3 0x300 +#define D3DFVF_TEX4 0x400 +#define D3DFVF_TEX5 0x500 +#define D3DFVF_TEX6 0x600 +#define D3DFVF_TEX7 0x700 +#define D3DFVF_TEX8 0x800 + +#define D3DFVF_LASTBETA_UBYTE4 0x1000 + +#define D3DFVF_RESERVED2 0xE000 /* 4 reserved bits */ + +/*--------------------------------------------------------------------- + * Vertex Shaders + */ + +/* + +Vertex Shader Declaration + +The declaration portion of a vertex shader defines the static external +interface of the shader. The information in the declaration includes: + +- Assignments of vertex shader input registers to data streams. These +assignments bind a specific vertex register to a single component within a +vertex stream. A vertex stream element is identified by a byte offset +within the stream and a type. The type specifies the arithmetic data type +plus the dimensionality (1, 2, 3, or 4 values). Stream data which is +less than 4 values are always expanded out to 4 values with zero or more +0.F values and one 1.F value. + +- Assignment of vertex shader input registers to implicit data from the +primitive tessellator. This controls the loading of vertex data which is +not loaded from a stream, but rather is generated during primitive +tessellation prior to the vertex shader. + +- Loading data into the constant memory at the time a shader is set as the +current shader. Each token specifies values for one or more contiguous 4 +DWORD constant registers. This allows the shader to update an arbitrary +subset of the constant memory, overwriting the device state (which +contains the current values of the constant memory). Note that these +values can be subsequently overwritten (between DrawPrimitive calls) +during the time a shader is bound to a device via the +SetVertexShaderConstant method. + + +Declaration arrays are single-dimensional arrays of DWORDs composed of +multiple tokens each of which is one or more DWORDs. The single-DWORD +token value 0xFFFFFFFF is a special token used to indicate the end of the +declaration array. The single DWORD token value 0x00000000 is a NOP token +with is ignored during the declaration parsing. Note that 0x00000000 is a +valid value for DWORDs following the first DWORD for multiple word tokens. + +[31:29] TokenType + 0x0 - NOP (requires all DWORD bits to be zero) + 0x1 - stream selector + 0x2 - stream data definition (map to vertex input memory) + 0x3 - vertex input memory from tessellator + 0x4 - constant memory from shader + 0x5 - extension + 0x6 - reserved + 0x7 - end-of-array (requires all DWORD bits to be 1) + +NOP Token (single DWORD token) + [31:29] 0x0 + [28:00] 0x0 + +Stream Selector (single DWORD token) + [31:29] 0x1 + [28] indicates whether this is a tessellator stream + [27:04] 0x0 + [03:00] stream selector (0..15) + +Stream Data Definition (single DWORD token) + Vertex Input Register Load + [31:29] 0x2 + [28] 0x0 + [27:20] 0x0 + [19:16] type (dimensionality and data type) + [15:04] 0x0 + [03:00] vertex register address (0..15) + Data Skip (no register load) + [31:29] 0x2 + [28] 0x1 + [27:20] 0x0 + [19:16] count of DWORDS to skip over (0..15) + [15:00] 0x0 + Vertex Input Memory from Tessellator Data (single DWORD token) + [31:29] 0x3 + [28] indicates whether data is normals or u/v + [27:24] 0x0 + [23:20] vertex register address (0..15) + [19:16] type (dimensionality) + [15:04] 0x0 + [03:00] vertex register address (0..15) + +Constant Memory from Shader (multiple DWORD token) + [31:29] 0x4 + [28:25] count of 4*DWORD constants to load (0..15) + [24:07] 0x0 + [06:00] constant memory address (0..95) + +Extension Token (single or multiple DWORD token) + [31:29] 0x5 + [28:24] count of additional DWORDs in token (0..31) + [23:00] extension-specific information + +End-of-array token (single DWORD token) + [31:29] 0x7 + [28:00] 0x1fffffff + +The stream selector token must be immediately followed by a contiguous set of stream data definition tokens. This token sequence fully defines that stream, including the set of elements within the stream, the order in which the elements appear, the type of each element, and the vertex register into which to load an element. +Streams are allowed to include data which is not loaded into a vertex register, thus allowing data which is not used for this shader to exist in the vertex stream. This skipped data is defined only by a count of DWORDs to skip over, since the type information is irrelevant. +The token sequence: +Stream Select: stream=0 +Stream Data Definition (Load): type=FLOAT3; register=3 +Stream Data Definition (Load): type=FLOAT3; register=4 +Stream Data Definition (Skip): count=2 +Stream Data Definition (Load): type=FLOAT2; register=7 + +defines stream zero to consist of 4 elements, 3 of which are loaded into registers and the fourth skipped over. Register 3 is loaded with the first three DWORDs in each vertex interpreted as FLOAT data. Register 4 is loaded with the 4th, 5th, and 6th DWORDs interpreted as FLOAT data. The next two DWORDs (7th and 8th) are skipped over and not loaded into any vertex input register. Register 7 is loaded with the 9th and 10th DWORDS interpreted as FLOAT data. +Placing of tokens other than NOPs between the Stream Selector and Stream Data Definition tokens is disallowed. + +*/ + +typedef enum _D3DVSD_TOKENTYPE +{ + D3DVSD_TOKEN_NOP = 0, /* NOP or extension */ + D3DVSD_TOKEN_STREAM, /* stream selector */ + D3DVSD_TOKEN_STREAMDATA, /* stream data definition (map to vertex input memory) */ + D3DVSD_TOKEN_TESSELLATOR, /* vertex input memory from tessellator */ + D3DVSD_TOKEN_CONSTMEM, /* constant memory from shader */ + D3DVSD_TOKEN_EXT, /* extension */ + D3DVSD_TOKEN_END = 7, /* end-of-array (requires all DWORD bits to be 1) */ + D3DVSD_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DVSD_TOKENTYPE; + +#define D3DVSD_TOKENTYPESHIFT 29 +#define D3DVSD_TOKENTYPEMASK (7 << D3DVSD_TOKENTYPESHIFT) + +#define D3DVSD_STREAMNUMBERSHIFT 0 +#define D3DVSD_STREAMNUMBERMASK (0xF << D3DVSD_STREAMNUMBERSHIFT) + +#define D3DVSD_DATALOADTYPESHIFT 28 +#define D3DVSD_DATALOADTYPEMASK (0x1 << D3DVSD_DATALOADTYPESHIFT) + +#define D3DVSD_DATATYPESHIFT 16 +#define D3DVSD_DATATYPEMASK (0xF << D3DVSD_DATATYPESHIFT) + +#define D3DVSD_SKIPCOUNTSHIFT 16 +#define D3DVSD_SKIPCOUNTMASK (0xF << D3DVSD_SKIPCOUNTSHIFT) + +#define D3DVSD_VERTEXREGSHIFT 0 +#define D3DVSD_VERTEXREGMASK (0x1F << D3DVSD_VERTEXREGSHIFT) + +#define D3DVSD_VERTEXREGINSHIFT 20 +#define D3DVSD_VERTEXREGINMASK (0xF << D3DVSD_VERTEXREGINSHIFT) + +#define D3DVSD_CONSTCOUNTSHIFT 25 +#define D3DVSD_CONSTCOUNTMASK (0xF << D3DVSD_CONSTCOUNTSHIFT) + +#define D3DVSD_CONSTADDRESSSHIFT 0 +#define D3DVSD_CONSTADDRESSMASK (0x7F << D3DVSD_CONSTADDRESSSHIFT) + +#define D3DVSD_CONSTRSSHIFT 16 +#define D3DVSD_CONSTRSMASK (0x1FFF << D3DVSD_CONSTRSSHIFT) + +#define D3DVSD_EXTCOUNTSHIFT 24 +#define D3DVSD_EXTCOUNTMASK (0x1F << D3DVSD_EXTCOUNTSHIFT) + +#define D3DVSD_EXTINFOSHIFT 0 +#define D3DVSD_EXTINFOMASK (0xFFFFFF << D3DVSD_EXTINFOSHIFT) + +#define D3DVSD_MAKETOKENTYPE(tokenType) ((tokenType << D3DVSD_TOKENTYPESHIFT) & D3DVSD_TOKENTYPEMASK) + +/* macros for generation of CreateVertexShader Declaration token array */ + +/* Set current stream + * _StreamNumber [0..(MaxStreams-1)] stream to get data from + */ +#define D3DVSD_STREAM( _StreamNumber ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAM) | (_StreamNumber)) + +/* Set tessellator stream + */ +#define D3DVSD_STREAMTESSSHIFT 28 +#define D3DVSD_STREAMTESSMASK (1 << D3DVSD_STREAMTESSSHIFT) +#define D3DVSD_STREAM_TESS( ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAM) | (D3DVSD_STREAMTESSMASK)) + +/* bind single vertex register to vertex element from vertex stream + * + * _VertexRegister [0..15] address of the vertex register + * _Type [D3DVSDT_*] dimensionality and arithmetic data type + */ + +#define D3DVSD_REG( _VertexRegister, _Type ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAMDATA) | \ + ((_Type) << D3DVSD_DATATYPESHIFT) | (_VertexRegister)) + +/* Skip _DWORDCount DWORDs in vertex + */ +#define D3DVSD_SKIP( _DWORDCount ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_STREAMDATA) | 0x10000000 | \ + ((_DWORDCount) << D3DVSD_SKIPCOUNTSHIFT)) + +/* load data into vertex shader constant memory + * + * _ConstantAddress [0..95] - address of constant array to begin filling data + * _Count [0..15] - number of constant vectors to load (4 DWORDs each) + * followed by 4*_Count DWORDS of data + */ +#define D3DVSD_CONST( _ConstantAddress, _Count ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_CONSTMEM) | \ + ((_Count) << D3DVSD_CONSTCOUNTSHIFT) | (_ConstantAddress)) + +/* enable tessellator generated normals + * + * _VertexRegisterIn [0..15] address of vertex register whose input stream + * will be used in normal computation + * _VertexRegisterOut [0..15] address of vertex register to output the normal to + */ +#define D3DVSD_TESSNORMAL( _VertexRegisterIn, _VertexRegisterOut ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_TESSELLATOR) | \ + ((_VertexRegisterIn) << D3DVSD_VERTEXREGINSHIFT) | \ + ((0x02) << D3DVSD_DATATYPESHIFT) | (_VertexRegisterOut)) + +/* enable tessellator generated surface parameters + * + * _VertexRegister [0..15] address of vertex register to output parameters + */ +#define D3DVSD_TESSUV( _VertexRegister ) \ + (D3DVSD_MAKETOKENTYPE(D3DVSD_TOKEN_TESSELLATOR) | 0x10000000 | \ + ((0x01) << D3DVSD_DATATYPESHIFT) | (_VertexRegister)) + +/* Generates END token + */ +#define D3DVSD_END() 0xFFFFFFFF + +/* Generates NOP token */ +#define D3DVSD_NOP() 0x00000000 + +/* bit declarations for _Type fields */ +#define D3DVSDT_FLOAT1 0x00 /* 1D float expanded to (value, 0., 0., 1.) */ +#define D3DVSDT_FLOAT2 0x01 /* 2D float expanded to (value, value, 0., 1.) */ +#define D3DVSDT_FLOAT3 0x02 /* 3D float expanded to (value, value, value, 1.) */ +#define D3DVSDT_FLOAT4 0x03 /* 4D float */ +#define D3DVSDT_D3DCOLOR 0x04 /* 4D packed unsigned bytes mapped to 0. to 1. range + * Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A) */ +#define D3DVSDT_UBYTE4 0x05 /* 4D unsigned byte */ +#define D3DVSDT_SHORT2 0x06 /* 2D signed short expanded to (value, value, 0., 1.) */ +#define D3DVSDT_SHORT4 0x07 /* 4D signed short */ + +/* assignments of vertex input registers for fixed function vertex shader */ +#define D3DVSDE_POSITION 0 +#define D3DVSDE_BLENDWEIGHT 1 +#define D3DVSDE_BLENDINDICES 2 +#define D3DVSDE_NORMAL 3 +#define D3DVSDE_PSIZE 4 +#define D3DVSDE_DIFFUSE 5 +#define D3DVSDE_SPECULAR 6 +#define D3DVSDE_TEXCOORD0 7 +#define D3DVSDE_TEXCOORD1 8 +#define D3DVSDE_TEXCOORD2 9 +#define D3DVSDE_TEXCOORD3 10 +#define D3DVSDE_TEXCOORD4 11 +#define D3DVSDE_TEXCOORD5 12 +#define D3DVSDE_TEXCOORD6 13 +#define D3DVSDE_TEXCOORD7 14 +#define D3DVSDE_POSITION2 15 +#define D3DVSDE_NORMAL2 16 + +/* Maximum supported number of texture coordinate sets */ +#define D3DDP_MAXTEXCOORD 8 + + +/* Instruction Token Bit Definitions */ +#define D3DSI_OPCODE_MASK 0x0000FFFF + +typedef enum _D3DSHADER_INSTRUCTION_OPCODE_TYPE +{ + D3DSIO_NOP = 0, /* PS/VS */ + D3DSIO_MOV , /* PS/VS */ + D3DSIO_ADD , /* PS/VS */ + D3DSIO_SUB , /* PS */ + D3DSIO_MAD , /* PS/VS */ + D3DSIO_MUL , /* PS/VS */ + D3DSIO_RCP , /* VS */ + D3DSIO_RSQ , /* VS */ + D3DSIO_DP3 , /* PS/VS */ + D3DSIO_DP4 , /* PS/VS */ + D3DSIO_MIN , /* VS */ + D3DSIO_MAX , /* VS */ + D3DSIO_SLT , /* VS */ + D3DSIO_SGE , /* VS */ + D3DSIO_EXP , /* VS */ + D3DSIO_LOG , /* VS */ + D3DSIO_LIT , /* VS */ + D3DSIO_DST , /* VS */ + D3DSIO_LRP , /* PS */ + D3DSIO_FRC , /* VS */ + D3DSIO_M4x4 , /* VS */ + D3DSIO_M4x3 , /* VS */ + D3DSIO_M3x4 , /* VS */ + D3DSIO_M3x3 , /* VS */ + D3DSIO_M3x2 , /* VS */ + + D3DSIO_TEXCOORD = 64, /* PS */ + D3DSIO_TEXKILL , /* PS */ + D3DSIO_TEX , /* PS */ + D3DSIO_TEXBEM , /* PS */ + D3DSIO_TEXBEML , /* PS */ + D3DSIO_TEXREG2AR , /* PS */ + D3DSIO_TEXREG2GB , /* PS */ + D3DSIO_TEXM3x2PAD , /* PS */ + D3DSIO_TEXM3x2TEX , /* PS */ + D3DSIO_TEXM3x3PAD , /* PS */ + D3DSIO_TEXM3x3TEX , /* PS */ + D3DSIO_TEXM3x3DIFF , /* PS */ + D3DSIO_TEXM3x3SPEC , /* PS */ + D3DSIO_TEXM3x3VSPEC , /* PS */ + D3DSIO_EXPP , /* VS */ + D3DSIO_LOGP , /* VS */ + D3DSIO_CND , /* PS */ + D3DSIO_DEF , /* PS */ + D3DSIO_TEXREG2RGB , /* PS */ + D3DSIO_TEXDP3TEX , /* PS */ + D3DSIO_TEXM3x2DEPTH , /* PS */ + D3DSIO_TEXDP3 , /* PS */ + D3DSIO_TEXM3x3 , /* PS */ + D3DSIO_TEXDEPTH , /* PS */ + D3DSIO_CMP , /* PS */ + D3DSIO_BEM , /* PS */ + + D3DSIO_PHASE = 0xFFFD, + D3DSIO_COMMENT = 0xFFFE, + D3DSIO_END = 0xFFFF, + + D3DSIO_FORCE_DWORD = 0x7fffffff /* force 32-bit size enum */ +} D3DSHADER_INSTRUCTION_OPCODE_TYPE; + +/* Co-Issue Instruction Modifier - if set then this instruction is to be + * issued in parallel with the previous instruction(s) for which this bit + * is not set. */ +#define D3DSI_COISSUE 0x40000000 + +/* Parameter Token Bit Definitions */ +#define D3DSP_REGNUM_MASK 0x00001FFF + +/* destination parameter write mask */ +#define D3DSP_WRITEMASK_0 0x00010000 /* Component 0 (X;Red) */ +#define D3DSP_WRITEMASK_1 0x00020000 /* Component 1 (Y;Green) */ +#define D3DSP_WRITEMASK_2 0x00040000 /* Component 2 (Z;Blue) */ +#define D3DSP_WRITEMASK_3 0x00080000 /* Component 3 (W;Alpha) */ +#define D3DSP_WRITEMASK_ALL 0x000F0000 /* All Components */ + +/* destination parameter modifiers */ +#define D3DSP_DSTMOD_SHIFT 20 +#define D3DSP_DSTMOD_MASK 0x00F00000 + +typedef enum _D3DSHADER_PARAM_DSTMOD_TYPE +{ + D3DSPDM_NONE = 0<>8)&0xFF) +#define D3DSHADER_VERSION_MINOR(_Version) (((_Version)>>0)&0xFF) + +/* destination/source parameter register type */ +#define D3DSI_COMMENTSIZE_SHIFT 16 +#define D3DSI_COMMENTSIZE_MASK 0x7FFF0000 +#define D3DSHADER_COMMENT(_DWordSize) \ + ((((_DWordSize)<= 1200 +#pragma warning(pop) +#else +#pragma warning(default:4201) +#endif + +#endif /* (DIRECT3D_VERSION >= 0x0800) */ +#endif /* _D3D8TYPES(P)_H_ */ diff --git a/gfx/include/d3d8/d3dx8math.inl b/gfx/include/d3d8/d3dx8math.inl index ca94a797ba..0ecee3f9fa 100644 --- a/gfx/include/d3d8/d3dx8math.inl +++ b/gfx/include/d3d8/d3dx8math.inl @@ -1,1736 +1,1736 @@ -/* - * - * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved. - * - * File: d3dx8math.inl - * Content: D3DX math inline functions - * - */ - -#ifndef __D3DX8MATH_INL__ -#define __D3DX8MATH_INL__ - -/* - * - * Inline Class Methods - * - */ - -#ifdef __cplusplus - -/* - * 2D Vector - */ - -D3DXINLINE -D3DXVECTOR2::D3DXVECTOR2( CONST FLOAT *pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - x = pf[0]; - y = pf[1]; -} - -D3DXINLINE -D3DXVECTOR2::D3DXVECTOR2( FLOAT fx, FLOAT fy ) -{ - x = fx; - y = fy; -} - -/* casting */ -D3DXINLINE -D3DXVECTOR2::operator FLOAT* () -{ - return (FLOAT *) &x; -} - -D3DXINLINE -D3DXVECTOR2::operator CONST FLOAT* () const -{ - return (CONST FLOAT *) &x; -} - -/* assignment operators */ -D3DXINLINE D3DXVECTOR2& -D3DXVECTOR2::operator += ( CONST D3DXVECTOR2& v ) -{ - x += v.x; - y += v.y; - return *this; -} - -D3DXINLINE D3DXVECTOR2& -D3DXVECTOR2::operator -= ( CONST D3DXVECTOR2& v ) -{ - x -= v.x; - y -= v.y; - return *this; -} - -D3DXINLINE D3DXVECTOR2& -D3DXVECTOR2::operator *= ( FLOAT f ) -{ - x *= f; - y *= f; - return *this; -} - -D3DXINLINE D3DXVECTOR2& -D3DXVECTOR2::operator /= ( FLOAT f ) -{ - FLOAT fInv = 1.0f / f; - x *= fInv; - y *= fInv; - return *this; -} - -/* unary operators */ -D3DXINLINE D3DXVECTOR2 -D3DXVECTOR2::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXVECTOR2 -D3DXVECTOR2::operator - () const -{ - return D3DXVECTOR2(-x, -y); -} - -/* binary operators */ -D3DXINLINE D3DXVECTOR2 -D3DXVECTOR2::operator + ( CONST D3DXVECTOR2& v ) const -{ - return D3DXVECTOR2(x + v.x, y + v.y); -} - -D3DXINLINE D3DXVECTOR2 -D3DXVECTOR2::operator - ( CONST D3DXVECTOR2& v ) const -{ - return D3DXVECTOR2(x - v.x, y - v.y); -} - -D3DXINLINE D3DXVECTOR2 -D3DXVECTOR2::operator * ( FLOAT f ) const -{ - return D3DXVECTOR2(x * f, y * f); -} - -D3DXINLINE D3DXVECTOR2 -D3DXVECTOR2::operator / ( FLOAT f ) const -{ - FLOAT fInv = 1.0f / f; - return D3DXVECTOR2(x * fInv, y * fInv); -} - - -D3DXINLINE D3DXVECTOR2 -operator * ( FLOAT f, CONST D3DXVECTOR2& v ) -{ - return D3DXVECTOR2(f * v.x, f * v.y); -} - -D3DXINLINE BOOL -D3DXVECTOR2::operator == ( CONST D3DXVECTOR2& v ) const -{ - return x == v.x && y == v.y; -} - -D3DXINLINE BOOL -D3DXVECTOR2::operator != ( CONST D3DXVECTOR2& v ) const -{ - return x != v.x || y != v.y; -} - - - - -/* - * 3D Vector - */ -D3DXINLINE -D3DXVECTOR3::D3DXVECTOR3( CONST FLOAT *pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - x = pf[0]; - y = pf[1]; - z = pf[2]; -} - -D3DXINLINE -D3DXVECTOR3::D3DXVECTOR3( CONST D3DVECTOR& v ) -{ - x = v.x; - y = v.y; - z = v.z; -} - -D3DXINLINE -D3DXVECTOR3::D3DXVECTOR3( FLOAT fx, FLOAT fy, FLOAT fz ) -{ - x = fx; - y = fy; - z = fz; -} - - -/* casting */ -D3DXINLINE -D3DXVECTOR3::operator FLOAT* () -{ - return (FLOAT *) &x; -} - -D3DXINLINE -D3DXVECTOR3::operator CONST FLOAT* () const -{ - return (CONST FLOAT *) &x; -} - - -/* assignment operators */ -D3DXINLINE D3DXVECTOR3& -D3DXVECTOR3::operator += ( CONST D3DXVECTOR3& v ) -{ - x += v.x; - y += v.y; - z += v.z; - return *this; -} - -D3DXINLINE D3DXVECTOR3& -D3DXVECTOR3::operator -= ( CONST D3DXVECTOR3& v ) -{ - x -= v.x; - y -= v.y; - z -= v.z; - return *this; -} - -D3DXINLINE D3DXVECTOR3& -D3DXVECTOR3::operator *= ( FLOAT f ) -{ - x *= f; - y *= f; - z *= f; - return *this; -} - -D3DXINLINE D3DXVECTOR3& -D3DXVECTOR3::operator /= ( FLOAT f ) -{ - FLOAT fInv = 1.0f / f; - x *= fInv; - y *= fInv; - z *= fInv; - return *this; -} - -/* unary operators */ -D3DXINLINE D3DXVECTOR3 -D3DXVECTOR3::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXVECTOR3 -D3DXVECTOR3::operator - () const -{ - return D3DXVECTOR3(-x, -y, -z); -} - -/* binary operators */ -D3DXINLINE D3DXVECTOR3 -D3DXVECTOR3::operator + ( CONST D3DXVECTOR3& v ) const -{ - return D3DXVECTOR3(x + v.x, y + v.y, z + v.z); -} - -D3DXINLINE D3DXVECTOR3 -D3DXVECTOR3::operator - ( CONST D3DXVECTOR3& v ) const -{ - return D3DXVECTOR3(x - v.x, y - v.y, z - v.z); -} - -D3DXINLINE D3DXVECTOR3 -D3DXVECTOR3::operator * ( FLOAT f ) const -{ - return D3DXVECTOR3(x * f, y * f, z * f); -} - -D3DXINLINE D3DXVECTOR3 -D3DXVECTOR3::operator / ( FLOAT f ) const -{ - FLOAT fInv = 1.0f / f; - return D3DXVECTOR3(x * fInv, y * fInv, z * fInv); -} - - -D3DXINLINE D3DXVECTOR3 -operator * ( FLOAT f, CONST struct D3DXVECTOR3& v ) -{ - return D3DXVECTOR3(f * v.x, f * v.y, f * v.z); -} - - -D3DXINLINE BOOL -D3DXVECTOR3::operator == ( CONST D3DXVECTOR3& v ) const -{ - return x == v.x && y == v.y && z == v.z; -} - -D3DXINLINE BOOL -D3DXVECTOR3::operator != ( CONST D3DXVECTOR3& v ) const -{ - return x != v.x || y != v.y || z != v.z; -} - -/* - * 4D Vector - */ -D3DXINLINE -D3DXVECTOR4::D3DXVECTOR4( CONST FLOAT *pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - x = pf[0]; - y = pf[1]; - z = pf[2]; - w = pf[3]; -} - -D3DXINLINE -D3DXVECTOR4::D3DXVECTOR4( FLOAT fx, FLOAT fy, FLOAT fz, FLOAT fw ) -{ - x = fx; - y = fy; - z = fz; - w = fw; -} - -/* casting */ -D3DXINLINE -D3DXVECTOR4::operator FLOAT* () -{ - return (FLOAT *) &x; -} - -D3DXINLINE -D3DXVECTOR4::operator CONST FLOAT* () const -{ - return (CONST FLOAT *) &x; -} - - -/* assignment operators */ -D3DXINLINE D3DXVECTOR4& -D3DXVECTOR4::operator += ( CONST D3DXVECTOR4& v ) -{ - x += v.x; - y += v.y; - z += v.z; - w += v.w; - return *this; -} - -D3DXINLINE D3DXVECTOR4& -D3DXVECTOR4::operator -= ( CONST D3DXVECTOR4& v ) -{ - x -= v.x; - y -= v.y; - z -= v.z; - w -= v.w; - return *this; -} - -D3DXINLINE D3DXVECTOR4& -D3DXVECTOR4::operator *= ( FLOAT f ) -{ - x *= f; - y *= f; - z *= f; - w *= f; - return *this; -} - -D3DXINLINE D3DXVECTOR4& -D3DXVECTOR4::operator /= ( FLOAT f ) -{ - FLOAT fInv = 1.0f / f; - x *= fInv; - y *= fInv; - z *= fInv; - w *= fInv; - return *this; -} - -/* unary operators */ -D3DXINLINE D3DXVECTOR4 -D3DXVECTOR4::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXVECTOR4 -D3DXVECTOR4::operator - () const -{ - return D3DXVECTOR4(-x, -y, -z, -w); -} - - -/* binary operators */ -D3DXINLINE D3DXVECTOR4 -D3DXVECTOR4::operator + ( CONST D3DXVECTOR4& v ) const -{ - return D3DXVECTOR4(x + v.x, y + v.y, z + v.z, w + v.w); -} - -D3DXINLINE D3DXVECTOR4 -D3DXVECTOR4::operator - ( CONST D3DXVECTOR4& v ) const -{ - return D3DXVECTOR4(x - v.x, y - v.y, z - v.z, w - v.w); -} - -D3DXINLINE D3DXVECTOR4 -D3DXVECTOR4::operator * ( FLOAT f ) const -{ - return D3DXVECTOR4(x * f, y * f, z * f, w * f); -} - -D3DXINLINE D3DXVECTOR4 -D3DXVECTOR4::operator / ( FLOAT f ) const -{ - FLOAT fInv = 1.0f / f; - return D3DXVECTOR4(x * fInv, y * fInv, z * fInv, w * fInv); -} - - -D3DXINLINE D3DXVECTOR4 -operator * ( FLOAT f, CONST D3DXVECTOR4& v ) -{ - return D3DXVECTOR4(f * v.x, f * v.y, f * v.z, f * v.w); -} - - -D3DXINLINE BOOL -D3DXVECTOR4::operator == ( CONST D3DXVECTOR4& v ) const -{ - return x == v.x && y == v.y && z == v.z && w == v.w; -} - -D3DXINLINE BOOL -D3DXVECTOR4::operator != ( CONST D3DXVECTOR4& v ) const -{ - return x != v.x || y != v.y || z != v.z || w != v.w; -} - - -/* - * Matrix - */ -D3DXINLINE -D3DXMATRIX::D3DXMATRIX( CONST FLOAT* pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - memcpy(&_11, pf, sizeof(D3DXMATRIX)); -} - -D3DXINLINE -D3DXMATRIX::D3DXMATRIX( CONST D3DMATRIX& mat ) -{ - memcpy(&_11, &mat, sizeof(D3DXMATRIX)); -} - -D3DXINLINE -D3DXMATRIX::D3DXMATRIX( FLOAT f11, FLOAT f12, FLOAT f13, FLOAT f14, - FLOAT f21, FLOAT f22, FLOAT f23, FLOAT f24, - FLOAT f31, FLOAT f32, FLOAT f33, FLOAT f34, - FLOAT f41, FLOAT f42, FLOAT f43, FLOAT f44 ) -{ - _11 = f11; _12 = f12; _13 = f13; _14 = f14; - _21 = f21; _22 = f22; _23 = f23; _24 = f24; - _31 = f31; _32 = f32; _33 = f33; _34 = f34; - _41 = f41; _42 = f42; _43 = f43; _44 = f44; -} - -/* access grants */ -D3DXINLINE FLOAT& -D3DXMATRIX::operator () ( UINT iRow, UINT iCol ) -{ - return m[iRow][iCol]; -} - -D3DXINLINE FLOAT -D3DXMATRIX::operator () ( UINT iRow, UINT iCol ) const -{ - return m[iRow][iCol]; -} - - -/* casting operators */ -D3DXINLINE -D3DXMATRIX::operator FLOAT* () -{ - return (FLOAT *) &_11; -} - -D3DXINLINE -D3DXMATRIX::operator CONST FLOAT* () const -{ - return (CONST FLOAT *) &_11; -} - - -/* assignment operators */ -D3DXINLINE D3DXMATRIX& -D3DXMATRIX::operator *= ( CONST D3DXMATRIX& mat ) -{ - D3DXMatrixMultiply(this, this, &mat); - return *this; -} - -D3DXINLINE D3DXMATRIX& -D3DXMATRIX::operator += ( CONST D3DXMATRIX& mat ) -{ - _11 += mat._11; _12 += mat._12; _13 += mat._13; _14 += mat._14; - _21 += mat._21; _22 += mat._22; _23 += mat._23; _24 += mat._24; - _31 += mat._31; _32 += mat._32; _33 += mat._33; _34 += mat._34; - _41 += mat._41; _42 += mat._42; _43 += mat._43; _44 += mat._44; - return *this; -} - -D3DXINLINE D3DXMATRIX& -D3DXMATRIX::operator -= ( CONST D3DXMATRIX& mat ) -{ - _11 -= mat._11; _12 -= mat._12; _13 -= mat._13; _14 -= mat._14; - _21 -= mat._21; _22 -= mat._22; _23 -= mat._23; _24 -= mat._24; - _31 -= mat._31; _32 -= mat._32; _33 -= mat._33; _34 -= mat._34; - _41 -= mat._41; _42 -= mat._42; _43 -= mat._43; _44 -= mat._44; - return *this; -} - -D3DXINLINE D3DXMATRIX& -D3DXMATRIX::operator *= ( FLOAT f ) -{ - _11 *= f; _12 *= f; _13 *= f; _14 *= f; - _21 *= f; _22 *= f; _23 *= f; _24 *= f; - _31 *= f; _32 *= f; _33 *= f; _34 *= f; - _41 *= f; _42 *= f; _43 *= f; _44 *= f; - return *this; -} - -D3DXINLINE D3DXMATRIX& -D3DXMATRIX::operator /= ( FLOAT f ) -{ - FLOAT fInv = 1.0f / f; - _11 *= fInv; _12 *= fInv; _13 *= fInv; _14 *= fInv; - _21 *= fInv; _22 *= fInv; _23 *= fInv; _24 *= fInv; - _31 *= fInv; _32 *= fInv; _33 *= fInv; _34 *= fInv; - _41 *= fInv; _42 *= fInv; _43 *= fInv; _44 *= fInv; - return *this; -} - -/* unary operators */ -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator - () const -{ - return D3DXMATRIX(-_11, -_12, -_13, -_14, - -_21, -_22, -_23, -_24, - -_31, -_32, -_33, -_34, - -_41, -_42, -_43, -_44); -} - -/* binary operators */ -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator * ( CONST D3DXMATRIX& mat ) const -{ - D3DXMATRIX matT; - D3DXMatrixMultiply(&matT, this, &mat); - return matT; -} - -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator + ( CONST D3DXMATRIX& mat ) const -{ - return D3DXMATRIX(_11 + mat._11, _12 + mat._12, _13 + mat._13, _14 + mat._14, - _21 + mat._21, _22 + mat._22, _23 + mat._23, _24 + mat._24, - _31 + mat._31, _32 + mat._32, _33 + mat._33, _34 + mat._34, - _41 + mat._41, _42 + mat._42, _43 + mat._43, _44 + mat._44); -} - -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator - ( CONST D3DXMATRIX& mat ) const -{ - return D3DXMATRIX(_11 - mat._11, _12 - mat._12, _13 - mat._13, _14 - mat._14, - _21 - mat._21, _22 - mat._22, _23 - mat._23, _24 - mat._24, - _31 - mat._31, _32 - mat._32, _33 - mat._33, _34 - mat._34, - _41 - mat._41, _42 - mat._42, _43 - mat._43, _44 - mat._44); -} - -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator * ( FLOAT f ) const -{ - return D3DXMATRIX(_11 * f, _12 * f, _13 * f, _14 * f, - _21 * f, _22 * f, _23 * f, _24 * f, - _31 * f, _32 * f, _33 * f, _34 * f, - _41 * f, _42 * f, _43 * f, _44 * f); -} - -D3DXINLINE D3DXMATRIX -D3DXMATRIX::operator / ( FLOAT f ) const -{ - FLOAT fInv = 1.0f / f; - return D3DXMATRIX(_11 * fInv, _12 * fInv, _13 * fInv, _14 * fInv, - _21 * fInv, _22 * fInv, _23 * fInv, _24 * fInv, - _31 * fInv, _32 * fInv, _33 * fInv, _34 * fInv, - _41 * fInv, _42 * fInv, _43 * fInv, _44 * fInv); -} - - -D3DXINLINE D3DXMATRIX -operator * ( FLOAT f, CONST D3DXMATRIX& mat ) -{ - return D3DXMATRIX(f * mat._11, f * mat._12, f * mat._13, f * mat._14, - f * mat._21, f * mat._22, f * mat._23, f * mat._24, - f * mat._31, f * mat._32, f * mat._33, f * mat._34, - f * mat._41, f * mat._42, f * mat._43, f * mat._44); -} - - -D3DXINLINE BOOL -D3DXMATRIX::operator == ( CONST D3DXMATRIX& mat ) const -{ - return 0 == memcmp(this, &mat, sizeof(D3DXMATRIX)); -} - -D3DXINLINE BOOL -D3DXMATRIX::operator != ( CONST D3DXMATRIX& mat ) const -{ - return 0 != memcmp(this, &mat, sizeof(D3DXMATRIX)); -} - - - -/* - * Quaternion - */ - -D3DXINLINE -D3DXQUATERNION::D3DXQUATERNION( CONST FLOAT* pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - x = pf[0]; - y = pf[1]; - z = pf[2]; - w = pf[3]; -} - -D3DXINLINE -D3DXQUATERNION::D3DXQUATERNION( FLOAT fx, FLOAT fy, FLOAT fz, FLOAT fw ) -{ - x = fx; - y = fy; - z = fz; - w = fw; -} - - -/* casting */ -D3DXINLINE -D3DXQUATERNION::operator FLOAT* () -{ - return (FLOAT *) &x; -} - -D3DXINLINE -D3DXQUATERNION::operator CONST FLOAT* () const -{ - return (CONST FLOAT *) &x; -} - - -/* assignment operators */ -D3DXINLINE D3DXQUATERNION& -D3DXQUATERNION::operator += ( CONST D3DXQUATERNION& q ) -{ - x += q.x; - y += q.y; - z += q.z; - w += q.w; - return *this; -} - -D3DXINLINE D3DXQUATERNION& -D3DXQUATERNION::operator -= ( CONST D3DXQUATERNION& q ) -{ - x -= q.x; - y -= q.y; - z -= q.z; - w -= q.w; - return *this; -} - -D3DXINLINE D3DXQUATERNION& -D3DXQUATERNION::operator *= ( CONST D3DXQUATERNION& q ) -{ - D3DXQuaternionMultiply(this, this, &q); - return *this; -} - -D3DXINLINE D3DXQUATERNION& -D3DXQUATERNION::operator *= ( FLOAT f ) -{ - x *= f; - y *= f; - z *= f; - w *= f; - return *this; -} - -D3DXINLINE D3DXQUATERNION& -D3DXQUATERNION::operator /= ( FLOAT f ) -{ - FLOAT fInv = 1.0f / f; - x *= fInv; - y *= fInv; - z *= fInv; - w *= fInv; - return *this; -} - - -/* unary operators */ -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator - () const -{ - return D3DXQUATERNION(-x, -y, -z, -w); -} - - -/* binary operators */ -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator + ( CONST D3DXQUATERNION& q ) const -{ - return D3DXQUATERNION(x + q.x, y + q.y, z + q.z, w + q.w); -} - -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator - ( CONST D3DXQUATERNION& q ) const -{ - return D3DXQUATERNION(x - q.x, y - q.y, z - q.z, w - q.w); -} - -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator * ( CONST D3DXQUATERNION& q ) const -{ - D3DXQUATERNION qT; - D3DXQuaternionMultiply(&qT, this, &q); - return qT; -} - -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator * ( FLOAT f ) const -{ - return D3DXQUATERNION(x * f, y * f, z * f, w * f); -} - -D3DXINLINE D3DXQUATERNION -D3DXQUATERNION::operator / ( FLOAT f ) const -{ - FLOAT fInv = 1.0f / f; - return D3DXQUATERNION(x * fInv, y * fInv, z * fInv, w * fInv); -} - - -D3DXINLINE D3DXQUATERNION -operator * (FLOAT f, CONST D3DXQUATERNION& q ) -{ - return D3DXQUATERNION(f * q.x, f * q.y, f * q.z, f * q.w); -} - - -D3DXINLINE BOOL -D3DXQUATERNION::operator == ( CONST D3DXQUATERNION& q ) const -{ - return x == q.x && y == q.y && z == q.z && w == q.w; -} - -D3DXINLINE BOOL -D3DXQUATERNION::operator != ( CONST D3DXQUATERNION& q ) const -{ - return x != q.x || y != q.y || z != q.z || w != q.w; -} - - - -/* - * Plane - */ - -D3DXINLINE -D3DXPLANE::D3DXPLANE( CONST FLOAT* pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - a = pf[0]; - b = pf[1]; - c = pf[2]; - d = pf[3]; -} - -D3DXINLINE -D3DXPLANE::D3DXPLANE( FLOAT fa, FLOAT fb, FLOAT fc, FLOAT fd ) -{ - a = fa; - b = fb; - c = fc; - d = fd; -} - -/* casting */ -D3DXINLINE -D3DXPLANE::operator FLOAT* () -{ - return (FLOAT *) &a; -} - -D3DXINLINE -D3DXPLANE::operator CONST FLOAT* () const -{ - return (CONST FLOAT *) &a; -} - - -/* unary operators */ -D3DXINLINE D3DXPLANE -D3DXPLANE::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXPLANE -D3DXPLANE::operator - () const -{ - return D3DXPLANE(-a, -b, -c, -d); -} - -/* binary operators */ -D3DXINLINE BOOL -D3DXPLANE::operator == ( CONST D3DXPLANE& p ) const -{ - return a == p.a && b == p.b && c == p.c && d == p.d; -} - -D3DXINLINE BOOL -D3DXPLANE::operator != ( CONST D3DXPLANE& p ) const -{ - return a != p.a || b != p.b || c != p.c || d != p.d; -} - -/* - * Color - */ - -D3DXINLINE -D3DXCOLOR::D3DXCOLOR( DWORD dw ) -{ - CONST FLOAT f = 1.0f / 255.0f; - r = f * (FLOAT) (unsigned char) (dw >> 16); - g = f * (FLOAT) (unsigned char) (dw >> 8); - b = f * (FLOAT) (unsigned char) (dw >> 0); - a = f * (FLOAT) (unsigned char) (dw >> 24); -} - -D3DXINLINE -D3DXCOLOR::D3DXCOLOR( CONST FLOAT* pf ) -{ -#ifdef D3DX_DEBUG - if(!pf) - return; -#endif - - r = pf[0]; - g = pf[1]; - b = pf[2]; - a = pf[3]; -} - -D3DXINLINE -D3DXCOLOR::D3DXCOLOR( CONST D3DCOLORVALUE& c ) -{ - r = c.r; - g = c.g; - b = c.b; - a = c.a; -} - -D3DXINLINE -D3DXCOLOR::D3DXCOLOR( FLOAT fr, FLOAT fg, FLOAT fb, FLOAT fa ) -{ - r = fr; - g = fg; - b = fb; - a = fa; -} - -/* casting */ -D3DXINLINE -D3DXCOLOR::operator DWORD () const -{ - DWORD dwR = r >= 1.0f ? 0xff : r <= 0.0f ? 0x00 : (DWORD) (r * 255.0f + 0.5f); - DWORD dwG = g >= 1.0f ? 0xff : g <= 0.0f ? 0x00 : (DWORD) (g * 255.0f + 0.5f); - DWORD dwB = b >= 1.0f ? 0xff : b <= 0.0f ? 0x00 : (DWORD) (b * 255.0f + 0.5f); - DWORD dwA = a >= 1.0f ? 0xff : a <= 0.0f ? 0x00 : (DWORD) (a * 255.0f + 0.5f); - - return (dwA << 24) | (dwR << 16) | (dwG << 8) | dwB; -} - - -D3DXINLINE -D3DXCOLOR::operator FLOAT * () -{ - return (FLOAT *) &r; -} - -D3DXINLINE -D3DXCOLOR::operator CONST FLOAT * () const -{ - return (CONST FLOAT *) &r; -} - - -D3DXINLINE -D3DXCOLOR::operator D3DCOLORVALUE * () -{ - return (D3DCOLORVALUE *) &r; -} - -D3DXINLINE -D3DXCOLOR::operator CONST D3DCOLORVALUE * () const -{ - return (CONST D3DCOLORVALUE *) &r; -} - - -D3DXINLINE -D3DXCOLOR::operator D3DCOLORVALUE& () -{ - return *((D3DCOLORVALUE *) &r); -} - -D3DXINLINE -D3DXCOLOR::operator CONST D3DCOLORVALUE& () const -{ - return *((CONST D3DCOLORVALUE *) &r); -} - -/* assignment operators */ -D3DXINLINE D3DXCOLOR& -D3DXCOLOR::operator += ( CONST D3DXCOLOR& c ) -{ - r += c.r; - g += c.g; - b += c.b; - a += c.a; - return *this; -} - -D3DXINLINE D3DXCOLOR& -D3DXCOLOR::operator -= ( CONST D3DXCOLOR& c ) -{ - r -= c.r; - g -= c.g; - b -= c.b; - a -= c.a; - return *this; -} - -D3DXINLINE D3DXCOLOR& -D3DXCOLOR::operator *= ( FLOAT f ) -{ - r *= f; - g *= f; - b *= f; - a *= f; - return *this; -} - -D3DXINLINE D3DXCOLOR& -D3DXCOLOR::operator /= ( FLOAT f ) -{ - FLOAT fInv = 1.0f / f; - r *= fInv; - g *= fInv; - b *= fInv; - a *= fInv; - return *this; -} - -/* unary operators */ -D3DXINLINE D3DXCOLOR -D3DXCOLOR::operator + () const -{ - return *this; -} - -D3DXINLINE D3DXCOLOR -D3DXCOLOR::operator - () const -{ - return D3DXCOLOR(-r, -g, -b, -a); -} - - -/* binary operators */ -D3DXINLINE D3DXCOLOR -D3DXCOLOR::operator + ( CONST D3DXCOLOR& c ) const -{ - return D3DXCOLOR(r + c.r, g + c.g, b + c.b, a + c.a); -} - -D3DXINLINE D3DXCOLOR -D3DXCOLOR::operator - ( CONST D3DXCOLOR& c ) const -{ - return D3DXCOLOR(r - c.r, g - c.g, b - c.b, a - c.a); -} - -D3DXINLINE D3DXCOLOR -D3DXCOLOR::operator * ( FLOAT f ) const -{ - return D3DXCOLOR(r * f, g * f, b * f, a * f); -} - -D3DXINLINE D3DXCOLOR -D3DXCOLOR::operator / ( FLOAT f ) const -{ - FLOAT fInv = 1.0f / f; - return D3DXCOLOR(r * fInv, g * fInv, b * fInv, a * fInv); -} - - -D3DXINLINE D3DXCOLOR -operator * (FLOAT f, CONST D3DXCOLOR& c ) -{ - return D3DXCOLOR(f * c.r, f * c.g, f * c.b, f * c.a); -} - - -D3DXINLINE BOOL -D3DXCOLOR::operator == ( CONST D3DXCOLOR& c ) const -{ - return r == c.r && g == c.g && b == c.b && a == c.a; -} - -D3DXINLINE BOOL -D3DXCOLOR::operator != ( CONST D3DXCOLOR& c ) const -{ - return r != c.r || g != c.g || b != c.b || a != c.a; -} - - -#endif /* __cplusplus */ - -/* - * - * Inline functions - * - */ - - -/* - * 2D Vector - */ - -D3DXINLINE FLOAT D3DXVec2Length - ( CONST D3DXVECTOR2 *pV ) -{ -#ifdef D3DX_DEBUG - if(!pV) - return 0.0f; -#endif - -#ifdef __cplusplus - return sqrtf(pV->x * pV->x + pV->y * pV->y); -#else - return (FLOAT) sqrt(pV->x * pV->x + pV->y * pV->y); -#endif -} - -D3DXINLINE FLOAT D3DXVec2LengthSq - ( CONST D3DXVECTOR2 *pV ) -{ -#ifdef D3DX_DEBUG - if(!pV) - return 0.0f; -#endif - - return pV->x * pV->x + pV->y * pV->y; -} - -D3DXINLINE FLOAT D3DXVec2Dot - ( CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pV1 || !pV2) - return 0.0f; -#endif - - return pV1->x * pV2->x + pV1->y * pV2->y; -} - -D3DXINLINE FLOAT D3DXVec2CCW - ( CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pV1 || !pV2) - return 0.0f; -#endif - - return pV1->x * pV2->y - pV1->y * pV2->x; -} - -D3DXINLINE D3DXVECTOR2* D3DXVec2Add - ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x + pV2->x; - pOut->y = pV1->y + pV2->y; - return pOut; -} - -D3DXINLINE D3DXVECTOR2* D3DXVec2Subtract - ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x - pV2->x; - pOut->y = pV1->y - pV2->y; - return pOut; -} - -D3DXINLINE D3DXVECTOR2* D3DXVec2Minimize - ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x; - pOut->y = pV1->y < pV2->y ? pV1->y : pV2->y; - return pOut; -} - -D3DXINLINE D3DXVECTOR2* D3DXVec2Maximize - ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x; - pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y; - return pOut; -} - -D3DXINLINE D3DXVECTOR2* D3DXVec2Scale - ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV, FLOAT s ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV) - return NULL; -#endif - - pOut->x = pV->x * s; - pOut->y = pV->y * s; - return pOut; -} - -D3DXINLINE D3DXVECTOR2* D3DXVec2Lerp - ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2, - FLOAT s ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x + s * (pV2->x - pV1->x); - pOut->y = pV1->y + s * (pV2->y - pV1->y); - return pOut; -} - - -/* - * 3D Vector - */ - -D3DXINLINE FLOAT D3DXVec3Length - ( CONST D3DXVECTOR3 *pV ) -{ -#ifdef D3DX_DEBUG - if(!pV) - return 0.0f; -#endif - -#ifdef __cplusplus - return sqrtf(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z); -#else - return (FLOAT) sqrt(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z); -#endif -} - -D3DXINLINE FLOAT D3DXVec3LengthSq - ( CONST D3DXVECTOR3 *pV ) -{ -#ifdef D3DX_DEBUG - if(!pV) - return 0.0f; -#endif - - return pV->x * pV->x + pV->y * pV->y + pV->z * pV->z; -} - -D3DXINLINE FLOAT D3DXVec3Dot - ( CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pV1 || !pV2) - return 0.0f; -#endif - - return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Cross - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) -{ - D3DXVECTOR3 v; - -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - v.x = pV1->y * pV2->z - pV1->z * pV2->y; - v.y = pV1->z * pV2->x - pV1->x * pV2->z; - v.z = pV1->x * pV2->y - pV1->y * pV2->x; - - *pOut = v; - return pOut; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Add - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x + pV2->x; - pOut->y = pV1->y + pV2->y; - pOut->z = pV1->z + pV2->z; - return pOut; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Subtract - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x - pV2->x; - pOut->y = pV1->y - pV2->y; - pOut->z = pV1->z - pV2->z; - return pOut; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Minimize - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x; - pOut->y = pV1->y < pV2->y ? pV1->y : pV2->y; - pOut->z = pV1->z < pV2->z ? pV1->z : pV2->z; - return pOut; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Maximize - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x; - pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y; - pOut->z = pV1->z > pV2->z ? pV1->z : pV2->z; - return pOut; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Scale - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, FLOAT s) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV) - return NULL; -#endif - - pOut->x = pV->x * s; - pOut->y = pV->y * s; - pOut->z = pV->z * s; - return pOut; -} - -D3DXINLINE D3DXVECTOR3* D3DXVec3Lerp - ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2, - FLOAT s ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x + s * (pV2->x - pV1->x); - pOut->y = pV1->y + s * (pV2->y - pV1->y); - pOut->z = pV1->z + s * (pV2->z - pV1->z); - return pOut; -} - - -/* - * 4D Vector - */ - -D3DXINLINE FLOAT D3DXVec4Length - ( CONST D3DXVECTOR4 *pV ) -{ -#ifdef D3DX_DEBUG - if(!pV) - return 0.0f; -#endif - -#ifdef __cplusplus - return sqrtf(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z + pV->w * pV->w); -#else - return (FLOAT) sqrt(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z + pV->w * pV->w); -#endif -} - -D3DXINLINE FLOAT D3DXVec4LengthSq - ( CONST D3DXVECTOR4 *pV ) -{ -#ifdef D3DX_DEBUG - if(!pV) - return 0.0f; -#endif - - return pV->x * pV->x + pV->y * pV->y + pV->z * pV->z + pV->w * pV->w; -} - -D3DXINLINE FLOAT D3DXVec4Dot - ( CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2 ) -{ -#ifdef D3DX_DEBUG - if(!pV1 || !pV2) - return 0.0f; -#endif - - return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z + pV1->w * pV2->w; -} - -D3DXINLINE D3DXVECTOR4* D3DXVec4Add - ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x + pV2->x; - pOut->y = pV1->y + pV2->y; - pOut->z = pV1->z + pV2->z; - pOut->w = pV1->w + pV2->w; - return pOut; -} - -D3DXINLINE D3DXVECTOR4* D3DXVec4Subtract - ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x - pV2->x; - pOut->y = pV1->y - pV2->y; - pOut->z = pV1->z - pV2->z; - pOut->w = pV1->w - pV2->w; - return pOut; -} - -D3DXINLINE D3DXVECTOR4* D3DXVec4Minimize - ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x; - pOut->y = pV1->y < pV2->y ? pV1->y : pV2->y; - pOut->z = pV1->z < pV2->z ? pV1->z : pV2->z; - pOut->w = pV1->w < pV2->w ? pV1->w : pV2->w; - return pOut; -} - -D3DXINLINE D3DXVECTOR4* D3DXVec4Maximize - ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x; - pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y; - pOut->z = pV1->z > pV2->z ? pV1->z : pV2->z; - pOut->w = pV1->w > pV2->w ? pV1->w : pV2->w; - return pOut; -} - -D3DXINLINE D3DXVECTOR4* D3DXVec4Scale - ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, FLOAT s) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV) - return NULL; -#endif - - pOut->x = pV->x * s; - pOut->y = pV->y * s; - pOut->z = pV->z * s; - pOut->w = pV->w * s; - return pOut; -} - -D3DXINLINE D3DXVECTOR4* D3DXVec4Lerp - ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2, - FLOAT s ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pV1 || !pV2) - return NULL; -#endif - - pOut->x = pV1->x + s * (pV2->x - pV1->x); - pOut->y = pV1->y + s * (pV2->y - pV1->y); - pOut->z = pV1->z + s * (pV2->z - pV1->z); - pOut->w = pV1->w + s * (pV2->w - pV1->w); - return pOut; -} - - -/* - * 4D Matrix - */ - -D3DXINLINE D3DXMATRIX* D3DXMatrixIdentity - ( D3DXMATRIX *pOut ) -{ -#ifdef D3DX_DEBUG - if(!pOut) - return NULL; -#endif - - pOut->m[0][1] = pOut->m[0][2] = pOut->m[0][3] = - pOut->m[1][0] = pOut->m[1][2] = pOut->m[1][3] = - pOut->m[2][0] = pOut->m[2][1] = pOut->m[2][3] = - pOut->m[3][0] = pOut->m[3][1] = pOut->m[3][2] = 0.0f; - - pOut->m[0][0] = pOut->m[1][1] = pOut->m[2][2] = pOut->m[3][3] = 1.0f; - return pOut; -} - - -D3DXINLINE BOOL D3DXMatrixIsIdentity - ( CONST D3DXMATRIX *pM ) -{ -#ifdef D3DX_DEBUG - if(!pM) - return FALSE; -#endif - - return pM->m[0][0] == 1.0f && pM->m[0][1] == 0.0f && pM->m[0][2] == 0.0f && pM->m[0][3] == 0.0f && - pM->m[1][0] == 0.0f && pM->m[1][1] == 1.0f && pM->m[1][2] == 0.0f && pM->m[1][3] == 0.0f && - pM->m[2][0] == 0.0f && pM->m[2][1] == 0.0f && pM->m[2][2] == 1.0f && pM->m[2][3] == 0.0f && - pM->m[3][0] == 0.0f && pM->m[3][1] == 0.0f && pM->m[3][2] == 0.0f && pM->m[3][3] == 1.0f; -} - - -/* - * Quaternion - */ - -D3DXINLINE FLOAT D3DXQuaternionLength - ( CONST D3DXQUATERNION *pQ ) -{ -#ifdef D3DX_DEBUG - if(!pQ) - return 0.0f; -#endif - -#ifdef __cplusplus - return sqrtf(pQ->x * pQ->x + pQ->y * pQ->y + pQ->z * pQ->z + pQ->w * pQ->w); -#else - return (FLOAT) sqrt(pQ->x * pQ->x + pQ->y * pQ->y + pQ->z * pQ->z + pQ->w * pQ->w); -#endif -} - -D3DXINLINE FLOAT D3DXQuaternionLengthSq - ( CONST D3DXQUATERNION *pQ ) -{ -#ifdef D3DX_DEBUG - if(!pQ) - return 0.0f; -#endif - - return pQ->x * pQ->x + pQ->y * pQ->y + pQ->z * pQ->z + pQ->w * pQ->w; -} - -D3DXINLINE FLOAT D3DXQuaternionDot - ( CONST D3DXQUATERNION *pQ1, CONST D3DXQUATERNION *pQ2 ) -{ -#ifdef D3DX_DEBUG - if(!pQ1 || !pQ2) - return 0.0f; -#endif - - return pQ1->x * pQ2->x + pQ1->y * pQ2->y + pQ1->z * pQ2->z + pQ1->w * pQ2->w; -} - - -D3DXINLINE D3DXQUATERNION* D3DXQuaternionIdentity - ( D3DXQUATERNION *pOut ) -{ -#ifdef D3DX_DEBUG - if(!pOut) - return NULL; -#endif - - pOut->x = pOut->y = pOut->z = 0.0f; - pOut->w = 1.0f; - return pOut; -} - -D3DXINLINE BOOL D3DXQuaternionIsIdentity - ( CONST D3DXQUATERNION *pQ ) -{ -#ifdef D3DX_DEBUG - if(!pQ) - return FALSE; -#endif - - return pQ->x == 0.0f && pQ->y == 0.0f && pQ->z == 0.0f && pQ->w == 1.0f; -} - - -D3DXINLINE D3DXQUATERNION* D3DXQuaternionConjugate - ( D3DXQUATERNION *pOut, CONST D3DXQUATERNION *pQ ) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pQ) - return NULL; -#endif - - pOut->x = -pQ->x; - pOut->y = -pQ->y; - pOut->z = -pQ->z; - pOut->w = pQ->w; - return pOut; -} - - -/* - * Plane - */ - -D3DXINLINE FLOAT D3DXPlaneDot - ( CONST D3DXPLANE *pP, CONST D3DXVECTOR4 *pV) -{ -#ifdef D3DX_DEBUG - if(!pP || !pV) - return 0.0f; -#endif - - return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z + pP->d * pV->w; -} - -D3DXINLINE FLOAT D3DXPlaneDotCoord - ( CONST D3DXPLANE *pP, CONST D3DXVECTOR3 *pV) -{ -#ifdef D3DX_DEBUG - if(!pP || !pV) - return 0.0f; -#endif - - return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z + pP->d; -} - -D3DXINLINE FLOAT D3DXPlaneDotNormal - ( CONST D3DXPLANE *pP, CONST D3DXVECTOR3 *pV) -{ -#ifdef D3DX_DEBUG - if(!pP || !pV) - return 0.0f; -#endif - - return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z; -} - - -/* - * Color - */ - -D3DXINLINE D3DXCOLOR* D3DXColorNegative - (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pC) - return NULL; -#endif - - pOut->r = 1.0f - pC->r; - pOut->g = 1.0f - pC->g; - pOut->b = 1.0f - pC->b; - pOut->a = pC->a; - return pOut; -} - -D3DXINLINE D3DXCOLOR* D3DXColorAdd - (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pC1 || !pC2) - return NULL; -#endif - - pOut->r = pC1->r + pC2->r; - pOut->g = pC1->g + pC2->g; - pOut->b = pC1->b + pC2->b; - pOut->a = pC1->a + pC2->a; - return pOut; -} - -D3DXINLINE D3DXCOLOR* D3DXColorSubtract - (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pC1 || !pC2) - return NULL; -#endif - - pOut->r = pC1->r - pC2->r; - pOut->g = pC1->g - pC2->g; - pOut->b = pC1->b - pC2->b; - pOut->a = pC1->a - pC2->a; - return pOut; -} - -D3DXINLINE D3DXCOLOR* D3DXColorScale - (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC, FLOAT s) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pC) - return NULL; -#endif - - pOut->r = pC->r * s; - pOut->g = pC->g * s; - pOut->b = pC->b * s; - pOut->a = pC->a * s; - return pOut; -} - -D3DXINLINE D3DXCOLOR* D3DXColorModulate - (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pC1 || !pC2) - return NULL; -#endif - - pOut->r = pC1->r * pC2->r; - pOut->g = pC1->g * pC2->g; - pOut->b = pC1->b * pC2->b; - pOut->a = pC1->a * pC2->a; - return pOut; -} - -D3DXINLINE D3DXCOLOR* D3DXColorLerp - (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2, FLOAT s) -{ -#ifdef D3DX_DEBUG - if(!pOut || !pC1 || !pC2) - return NULL; -#endif - - pOut->r = pC1->r + s * (pC2->r - pC1->r); - pOut->g = pC1->g + s * (pC2->g - pC1->g); - pOut->b = pC1->b + s * (pC2->b - pC1->b); - pOut->a = pC1->a + s * (pC2->a - pC1->a); - return pOut; -} - - -#endif /* __D3DX8MATH_INL__ */ +/* + * + * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved. + * + * File: d3dx8math.inl + * Content: D3DX math inline functions + * + */ + +#ifndef __D3DX8MATH_INL__ +#define __D3DX8MATH_INL__ + +/* + * + * Inline Class Methods + * + */ + +#ifdef __cplusplus + +/* + * 2D Vector + */ + +D3DXINLINE +D3DXVECTOR2::D3DXVECTOR2( CONST FLOAT *pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + x = pf[0]; + y = pf[1]; +} + +D3DXINLINE +D3DXVECTOR2::D3DXVECTOR2( FLOAT fx, FLOAT fy ) +{ + x = fx; + y = fy; +} + +/* casting */ +D3DXINLINE +D3DXVECTOR2::operator FLOAT* () +{ + return (FLOAT *) &x; +} + +D3DXINLINE +D3DXVECTOR2::operator CONST FLOAT* () const +{ + return (CONST FLOAT *) &x; +} + +/* assignment operators */ +D3DXINLINE D3DXVECTOR2& +D3DXVECTOR2::operator += ( CONST D3DXVECTOR2& v ) +{ + x += v.x; + y += v.y; + return *this; +} + +D3DXINLINE D3DXVECTOR2& +D3DXVECTOR2::operator -= ( CONST D3DXVECTOR2& v ) +{ + x -= v.x; + y -= v.y; + return *this; +} + +D3DXINLINE D3DXVECTOR2& +D3DXVECTOR2::operator *= ( FLOAT f ) +{ + x *= f; + y *= f; + return *this; +} + +D3DXINLINE D3DXVECTOR2& +D3DXVECTOR2::operator /= ( FLOAT f ) +{ + FLOAT fInv = 1.0f / f; + x *= fInv; + y *= fInv; + return *this; +} + +/* unary operators */ +D3DXINLINE D3DXVECTOR2 +D3DXVECTOR2::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXVECTOR2 +D3DXVECTOR2::operator - () const +{ + return D3DXVECTOR2(-x, -y); +} + +/* binary operators */ +D3DXINLINE D3DXVECTOR2 +D3DXVECTOR2::operator + ( CONST D3DXVECTOR2& v ) const +{ + return D3DXVECTOR2(x + v.x, y + v.y); +} + +D3DXINLINE D3DXVECTOR2 +D3DXVECTOR2::operator - ( CONST D3DXVECTOR2& v ) const +{ + return D3DXVECTOR2(x - v.x, y - v.y); +} + +D3DXINLINE D3DXVECTOR2 +D3DXVECTOR2::operator * ( FLOAT f ) const +{ + return D3DXVECTOR2(x * f, y * f); +} + +D3DXINLINE D3DXVECTOR2 +D3DXVECTOR2::operator / ( FLOAT f ) const +{ + FLOAT fInv = 1.0f / f; + return D3DXVECTOR2(x * fInv, y * fInv); +} + + +D3DXINLINE D3DXVECTOR2 +operator * ( FLOAT f, CONST D3DXVECTOR2& v ) +{ + return D3DXVECTOR2(f * v.x, f * v.y); +} + +D3DXINLINE BOOL +D3DXVECTOR2::operator == ( CONST D3DXVECTOR2& v ) const +{ + return x == v.x && y == v.y; +} + +D3DXINLINE BOOL +D3DXVECTOR2::operator != ( CONST D3DXVECTOR2& v ) const +{ + return x != v.x || y != v.y; +} + + + + +/* + * 3D Vector + */ +D3DXINLINE +D3DXVECTOR3::D3DXVECTOR3( CONST FLOAT *pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + x = pf[0]; + y = pf[1]; + z = pf[2]; +} + +D3DXINLINE +D3DXVECTOR3::D3DXVECTOR3( CONST D3DVECTOR& v ) +{ + x = v.x; + y = v.y; + z = v.z; +} + +D3DXINLINE +D3DXVECTOR3::D3DXVECTOR3( FLOAT fx, FLOAT fy, FLOAT fz ) +{ + x = fx; + y = fy; + z = fz; +} + + +/* casting */ +D3DXINLINE +D3DXVECTOR3::operator FLOAT* () +{ + return (FLOAT *) &x; +} + +D3DXINLINE +D3DXVECTOR3::operator CONST FLOAT* () const +{ + return (CONST FLOAT *) &x; +} + + +/* assignment operators */ +D3DXINLINE D3DXVECTOR3& +D3DXVECTOR3::operator += ( CONST D3DXVECTOR3& v ) +{ + x += v.x; + y += v.y; + z += v.z; + return *this; +} + +D3DXINLINE D3DXVECTOR3& +D3DXVECTOR3::operator -= ( CONST D3DXVECTOR3& v ) +{ + x -= v.x; + y -= v.y; + z -= v.z; + return *this; +} + +D3DXINLINE D3DXVECTOR3& +D3DXVECTOR3::operator *= ( FLOAT f ) +{ + x *= f; + y *= f; + z *= f; + return *this; +} + +D3DXINLINE D3DXVECTOR3& +D3DXVECTOR3::operator /= ( FLOAT f ) +{ + FLOAT fInv = 1.0f / f; + x *= fInv; + y *= fInv; + z *= fInv; + return *this; +} + +/* unary operators */ +D3DXINLINE D3DXVECTOR3 +D3DXVECTOR3::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXVECTOR3 +D3DXVECTOR3::operator - () const +{ + return D3DXVECTOR3(-x, -y, -z); +} + +/* binary operators */ +D3DXINLINE D3DXVECTOR3 +D3DXVECTOR3::operator + ( CONST D3DXVECTOR3& v ) const +{ + return D3DXVECTOR3(x + v.x, y + v.y, z + v.z); +} + +D3DXINLINE D3DXVECTOR3 +D3DXVECTOR3::operator - ( CONST D3DXVECTOR3& v ) const +{ + return D3DXVECTOR3(x - v.x, y - v.y, z - v.z); +} + +D3DXINLINE D3DXVECTOR3 +D3DXVECTOR3::operator * ( FLOAT f ) const +{ + return D3DXVECTOR3(x * f, y * f, z * f); +} + +D3DXINLINE D3DXVECTOR3 +D3DXVECTOR3::operator / ( FLOAT f ) const +{ + FLOAT fInv = 1.0f / f; + return D3DXVECTOR3(x * fInv, y * fInv, z * fInv); +} + + +D3DXINLINE D3DXVECTOR3 +operator * ( FLOAT f, CONST struct D3DXVECTOR3& v ) +{ + return D3DXVECTOR3(f * v.x, f * v.y, f * v.z); +} + + +D3DXINLINE BOOL +D3DXVECTOR3::operator == ( CONST D3DXVECTOR3& v ) const +{ + return x == v.x && y == v.y && z == v.z; +} + +D3DXINLINE BOOL +D3DXVECTOR3::operator != ( CONST D3DXVECTOR3& v ) const +{ + return x != v.x || y != v.y || z != v.z; +} + +/* + * 4D Vector + */ +D3DXINLINE +D3DXVECTOR4::D3DXVECTOR4( CONST FLOAT *pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + x = pf[0]; + y = pf[1]; + z = pf[2]; + w = pf[3]; +} + +D3DXINLINE +D3DXVECTOR4::D3DXVECTOR4( FLOAT fx, FLOAT fy, FLOAT fz, FLOAT fw ) +{ + x = fx; + y = fy; + z = fz; + w = fw; +} + +/* casting */ +D3DXINLINE +D3DXVECTOR4::operator FLOAT* () +{ + return (FLOAT *) &x; +} + +D3DXINLINE +D3DXVECTOR4::operator CONST FLOAT* () const +{ + return (CONST FLOAT *) &x; +} + + +/* assignment operators */ +D3DXINLINE D3DXVECTOR4& +D3DXVECTOR4::operator += ( CONST D3DXVECTOR4& v ) +{ + x += v.x; + y += v.y; + z += v.z; + w += v.w; + return *this; +} + +D3DXINLINE D3DXVECTOR4& +D3DXVECTOR4::operator -= ( CONST D3DXVECTOR4& v ) +{ + x -= v.x; + y -= v.y; + z -= v.z; + w -= v.w; + return *this; +} + +D3DXINLINE D3DXVECTOR4& +D3DXVECTOR4::operator *= ( FLOAT f ) +{ + x *= f; + y *= f; + z *= f; + w *= f; + return *this; +} + +D3DXINLINE D3DXVECTOR4& +D3DXVECTOR4::operator /= ( FLOAT f ) +{ + FLOAT fInv = 1.0f / f; + x *= fInv; + y *= fInv; + z *= fInv; + w *= fInv; + return *this; +} + +/* unary operators */ +D3DXINLINE D3DXVECTOR4 +D3DXVECTOR4::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXVECTOR4 +D3DXVECTOR4::operator - () const +{ + return D3DXVECTOR4(-x, -y, -z, -w); +} + + +/* binary operators */ +D3DXINLINE D3DXVECTOR4 +D3DXVECTOR4::operator + ( CONST D3DXVECTOR4& v ) const +{ + return D3DXVECTOR4(x + v.x, y + v.y, z + v.z, w + v.w); +} + +D3DXINLINE D3DXVECTOR4 +D3DXVECTOR4::operator - ( CONST D3DXVECTOR4& v ) const +{ + return D3DXVECTOR4(x - v.x, y - v.y, z - v.z, w - v.w); +} + +D3DXINLINE D3DXVECTOR4 +D3DXVECTOR4::operator * ( FLOAT f ) const +{ + return D3DXVECTOR4(x * f, y * f, z * f, w * f); +} + +D3DXINLINE D3DXVECTOR4 +D3DXVECTOR4::operator / ( FLOAT f ) const +{ + FLOAT fInv = 1.0f / f; + return D3DXVECTOR4(x * fInv, y * fInv, z * fInv, w * fInv); +} + + +D3DXINLINE D3DXVECTOR4 +operator * ( FLOAT f, CONST D3DXVECTOR4& v ) +{ + return D3DXVECTOR4(f * v.x, f * v.y, f * v.z, f * v.w); +} + + +D3DXINLINE BOOL +D3DXVECTOR4::operator == ( CONST D3DXVECTOR4& v ) const +{ + return x == v.x && y == v.y && z == v.z && w == v.w; +} + +D3DXINLINE BOOL +D3DXVECTOR4::operator != ( CONST D3DXVECTOR4& v ) const +{ + return x != v.x || y != v.y || z != v.z || w != v.w; +} + + +/* + * Matrix + */ +D3DXINLINE +D3DXMATRIX::D3DXMATRIX( CONST FLOAT* pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + memcpy(&_11, pf, sizeof(D3DXMATRIX)); +} + +D3DXINLINE +D3DXMATRIX::D3DXMATRIX( CONST D3DMATRIX& mat ) +{ + memcpy(&_11, &mat, sizeof(D3DXMATRIX)); +} + +D3DXINLINE +D3DXMATRIX::D3DXMATRIX( FLOAT f11, FLOAT f12, FLOAT f13, FLOAT f14, + FLOAT f21, FLOAT f22, FLOAT f23, FLOAT f24, + FLOAT f31, FLOAT f32, FLOAT f33, FLOAT f34, + FLOAT f41, FLOAT f42, FLOAT f43, FLOAT f44 ) +{ + _11 = f11; _12 = f12; _13 = f13; _14 = f14; + _21 = f21; _22 = f22; _23 = f23; _24 = f24; + _31 = f31; _32 = f32; _33 = f33; _34 = f34; + _41 = f41; _42 = f42; _43 = f43; _44 = f44; +} + +/* access grants */ +D3DXINLINE FLOAT& +D3DXMATRIX::operator () ( UINT iRow, UINT iCol ) +{ + return m[iRow][iCol]; +} + +D3DXINLINE FLOAT +D3DXMATRIX::operator () ( UINT iRow, UINT iCol ) const +{ + return m[iRow][iCol]; +} + + +/* casting operators */ +D3DXINLINE +D3DXMATRIX::operator FLOAT* () +{ + return (FLOAT *) &_11; +} + +D3DXINLINE +D3DXMATRIX::operator CONST FLOAT* () const +{ + return (CONST FLOAT *) &_11; +} + + +/* assignment operators */ +D3DXINLINE D3DXMATRIX& +D3DXMATRIX::operator *= ( CONST D3DXMATRIX& mat ) +{ + D3DXMatrixMultiply(this, this, &mat); + return *this; +} + +D3DXINLINE D3DXMATRIX& +D3DXMATRIX::operator += ( CONST D3DXMATRIX& mat ) +{ + _11 += mat._11; _12 += mat._12; _13 += mat._13; _14 += mat._14; + _21 += mat._21; _22 += mat._22; _23 += mat._23; _24 += mat._24; + _31 += mat._31; _32 += mat._32; _33 += mat._33; _34 += mat._34; + _41 += mat._41; _42 += mat._42; _43 += mat._43; _44 += mat._44; + return *this; +} + +D3DXINLINE D3DXMATRIX& +D3DXMATRIX::operator -= ( CONST D3DXMATRIX& mat ) +{ + _11 -= mat._11; _12 -= mat._12; _13 -= mat._13; _14 -= mat._14; + _21 -= mat._21; _22 -= mat._22; _23 -= mat._23; _24 -= mat._24; + _31 -= mat._31; _32 -= mat._32; _33 -= mat._33; _34 -= mat._34; + _41 -= mat._41; _42 -= mat._42; _43 -= mat._43; _44 -= mat._44; + return *this; +} + +D3DXINLINE D3DXMATRIX& +D3DXMATRIX::operator *= ( FLOAT f ) +{ + _11 *= f; _12 *= f; _13 *= f; _14 *= f; + _21 *= f; _22 *= f; _23 *= f; _24 *= f; + _31 *= f; _32 *= f; _33 *= f; _34 *= f; + _41 *= f; _42 *= f; _43 *= f; _44 *= f; + return *this; +} + +D3DXINLINE D3DXMATRIX& +D3DXMATRIX::operator /= ( FLOAT f ) +{ + FLOAT fInv = 1.0f / f; + _11 *= fInv; _12 *= fInv; _13 *= fInv; _14 *= fInv; + _21 *= fInv; _22 *= fInv; _23 *= fInv; _24 *= fInv; + _31 *= fInv; _32 *= fInv; _33 *= fInv; _34 *= fInv; + _41 *= fInv; _42 *= fInv; _43 *= fInv; _44 *= fInv; + return *this; +} + +/* unary operators */ +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator - () const +{ + return D3DXMATRIX(-_11, -_12, -_13, -_14, + -_21, -_22, -_23, -_24, + -_31, -_32, -_33, -_34, + -_41, -_42, -_43, -_44); +} + +/* binary operators */ +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator * ( CONST D3DXMATRIX& mat ) const +{ + D3DXMATRIX matT; + D3DXMatrixMultiply(&matT, this, &mat); + return matT; +} + +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator + ( CONST D3DXMATRIX& mat ) const +{ + return D3DXMATRIX(_11 + mat._11, _12 + mat._12, _13 + mat._13, _14 + mat._14, + _21 + mat._21, _22 + mat._22, _23 + mat._23, _24 + mat._24, + _31 + mat._31, _32 + mat._32, _33 + mat._33, _34 + mat._34, + _41 + mat._41, _42 + mat._42, _43 + mat._43, _44 + mat._44); +} + +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator - ( CONST D3DXMATRIX& mat ) const +{ + return D3DXMATRIX(_11 - mat._11, _12 - mat._12, _13 - mat._13, _14 - mat._14, + _21 - mat._21, _22 - mat._22, _23 - mat._23, _24 - mat._24, + _31 - mat._31, _32 - mat._32, _33 - mat._33, _34 - mat._34, + _41 - mat._41, _42 - mat._42, _43 - mat._43, _44 - mat._44); +} + +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator * ( FLOAT f ) const +{ + return D3DXMATRIX(_11 * f, _12 * f, _13 * f, _14 * f, + _21 * f, _22 * f, _23 * f, _24 * f, + _31 * f, _32 * f, _33 * f, _34 * f, + _41 * f, _42 * f, _43 * f, _44 * f); +} + +D3DXINLINE D3DXMATRIX +D3DXMATRIX::operator / ( FLOAT f ) const +{ + FLOAT fInv = 1.0f / f; + return D3DXMATRIX(_11 * fInv, _12 * fInv, _13 * fInv, _14 * fInv, + _21 * fInv, _22 * fInv, _23 * fInv, _24 * fInv, + _31 * fInv, _32 * fInv, _33 * fInv, _34 * fInv, + _41 * fInv, _42 * fInv, _43 * fInv, _44 * fInv); +} + + +D3DXINLINE D3DXMATRIX +operator * ( FLOAT f, CONST D3DXMATRIX& mat ) +{ + return D3DXMATRIX(f * mat._11, f * mat._12, f * mat._13, f * mat._14, + f * mat._21, f * mat._22, f * mat._23, f * mat._24, + f * mat._31, f * mat._32, f * mat._33, f * mat._34, + f * mat._41, f * mat._42, f * mat._43, f * mat._44); +} + + +D3DXINLINE BOOL +D3DXMATRIX::operator == ( CONST D3DXMATRIX& mat ) const +{ + return 0 == memcmp(this, &mat, sizeof(D3DXMATRIX)); +} + +D3DXINLINE BOOL +D3DXMATRIX::operator != ( CONST D3DXMATRIX& mat ) const +{ + return 0 != memcmp(this, &mat, sizeof(D3DXMATRIX)); +} + + + +/* + * Quaternion + */ + +D3DXINLINE +D3DXQUATERNION::D3DXQUATERNION( CONST FLOAT* pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + x = pf[0]; + y = pf[1]; + z = pf[2]; + w = pf[3]; +} + +D3DXINLINE +D3DXQUATERNION::D3DXQUATERNION( FLOAT fx, FLOAT fy, FLOAT fz, FLOAT fw ) +{ + x = fx; + y = fy; + z = fz; + w = fw; +} + + +/* casting */ +D3DXINLINE +D3DXQUATERNION::operator FLOAT* () +{ + return (FLOAT *) &x; +} + +D3DXINLINE +D3DXQUATERNION::operator CONST FLOAT* () const +{ + return (CONST FLOAT *) &x; +} + + +/* assignment operators */ +D3DXINLINE D3DXQUATERNION& +D3DXQUATERNION::operator += ( CONST D3DXQUATERNION& q ) +{ + x += q.x; + y += q.y; + z += q.z; + w += q.w; + return *this; +} + +D3DXINLINE D3DXQUATERNION& +D3DXQUATERNION::operator -= ( CONST D3DXQUATERNION& q ) +{ + x -= q.x; + y -= q.y; + z -= q.z; + w -= q.w; + return *this; +} + +D3DXINLINE D3DXQUATERNION& +D3DXQUATERNION::operator *= ( CONST D3DXQUATERNION& q ) +{ + D3DXQuaternionMultiply(this, this, &q); + return *this; +} + +D3DXINLINE D3DXQUATERNION& +D3DXQUATERNION::operator *= ( FLOAT f ) +{ + x *= f; + y *= f; + z *= f; + w *= f; + return *this; +} + +D3DXINLINE D3DXQUATERNION& +D3DXQUATERNION::operator /= ( FLOAT f ) +{ + FLOAT fInv = 1.0f / f; + x *= fInv; + y *= fInv; + z *= fInv; + w *= fInv; + return *this; +} + + +/* unary operators */ +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator - () const +{ + return D3DXQUATERNION(-x, -y, -z, -w); +} + + +/* binary operators */ +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator + ( CONST D3DXQUATERNION& q ) const +{ + return D3DXQUATERNION(x + q.x, y + q.y, z + q.z, w + q.w); +} + +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator - ( CONST D3DXQUATERNION& q ) const +{ + return D3DXQUATERNION(x - q.x, y - q.y, z - q.z, w - q.w); +} + +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator * ( CONST D3DXQUATERNION& q ) const +{ + D3DXQUATERNION qT; + D3DXQuaternionMultiply(&qT, this, &q); + return qT; +} + +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator * ( FLOAT f ) const +{ + return D3DXQUATERNION(x * f, y * f, z * f, w * f); +} + +D3DXINLINE D3DXQUATERNION +D3DXQUATERNION::operator / ( FLOAT f ) const +{ + FLOAT fInv = 1.0f / f; + return D3DXQUATERNION(x * fInv, y * fInv, z * fInv, w * fInv); +} + + +D3DXINLINE D3DXQUATERNION +operator * (FLOAT f, CONST D3DXQUATERNION& q ) +{ + return D3DXQUATERNION(f * q.x, f * q.y, f * q.z, f * q.w); +} + + +D3DXINLINE BOOL +D3DXQUATERNION::operator == ( CONST D3DXQUATERNION& q ) const +{ + return x == q.x && y == q.y && z == q.z && w == q.w; +} + +D3DXINLINE BOOL +D3DXQUATERNION::operator != ( CONST D3DXQUATERNION& q ) const +{ + return x != q.x || y != q.y || z != q.z || w != q.w; +} + + + +/* + * Plane + */ + +D3DXINLINE +D3DXPLANE::D3DXPLANE( CONST FLOAT* pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + a = pf[0]; + b = pf[1]; + c = pf[2]; + d = pf[3]; +} + +D3DXINLINE +D3DXPLANE::D3DXPLANE( FLOAT fa, FLOAT fb, FLOAT fc, FLOAT fd ) +{ + a = fa; + b = fb; + c = fc; + d = fd; +} + +/* casting */ +D3DXINLINE +D3DXPLANE::operator FLOAT* () +{ + return (FLOAT *) &a; +} + +D3DXINLINE +D3DXPLANE::operator CONST FLOAT* () const +{ + return (CONST FLOAT *) &a; +} + + +/* unary operators */ +D3DXINLINE D3DXPLANE +D3DXPLANE::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXPLANE +D3DXPLANE::operator - () const +{ + return D3DXPLANE(-a, -b, -c, -d); +} + +/* binary operators */ +D3DXINLINE BOOL +D3DXPLANE::operator == ( CONST D3DXPLANE& p ) const +{ + return a == p.a && b == p.b && c == p.c && d == p.d; +} + +D3DXINLINE BOOL +D3DXPLANE::operator != ( CONST D3DXPLANE& p ) const +{ + return a != p.a || b != p.b || c != p.c || d != p.d; +} + +/* + * Color + */ + +D3DXINLINE +D3DXCOLOR::D3DXCOLOR( DWORD dw ) +{ + CONST FLOAT f = 1.0f / 255.0f; + r = f * (FLOAT) (unsigned char) (dw >> 16); + g = f * (FLOAT) (unsigned char) (dw >> 8); + b = f * (FLOAT) (unsigned char) (dw >> 0); + a = f * (FLOAT) (unsigned char) (dw >> 24); +} + +D3DXINLINE +D3DXCOLOR::D3DXCOLOR( CONST FLOAT* pf ) +{ +#ifdef D3DX_DEBUG + if(!pf) + return; +#endif + + r = pf[0]; + g = pf[1]; + b = pf[2]; + a = pf[3]; +} + +D3DXINLINE +D3DXCOLOR::D3DXCOLOR( CONST D3DCOLORVALUE& c ) +{ + r = c.r; + g = c.g; + b = c.b; + a = c.a; +} + +D3DXINLINE +D3DXCOLOR::D3DXCOLOR( FLOAT fr, FLOAT fg, FLOAT fb, FLOAT fa ) +{ + r = fr; + g = fg; + b = fb; + a = fa; +} + +/* casting */ +D3DXINLINE +D3DXCOLOR::operator DWORD () const +{ + DWORD dwR = r >= 1.0f ? 0xff : r <= 0.0f ? 0x00 : (DWORD) (r * 255.0f + 0.5f); + DWORD dwG = g >= 1.0f ? 0xff : g <= 0.0f ? 0x00 : (DWORD) (g * 255.0f + 0.5f); + DWORD dwB = b >= 1.0f ? 0xff : b <= 0.0f ? 0x00 : (DWORD) (b * 255.0f + 0.5f); + DWORD dwA = a >= 1.0f ? 0xff : a <= 0.0f ? 0x00 : (DWORD) (a * 255.0f + 0.5f); + + return (dwA << 24) | (dwR << 16) | (dwG << 8) | dwB; +} + + +D3DXINLINE +D3DXCOLOR::operator FLOAT * () +{ + return (FLOAT *) &r; +} + +D3DXINLINE +D3DXCOLOR::operator CONST FLOAT * () const +{ + return (CONST FLOAT *) &r; +} + + +D3DXINLINE +D3DXCOLOR::operator D3DCOLORVALUE * () +{ + return (D3DCOLORVALUE *) &r; +} + +D3DXINLINE +D3DXCOLOR::operator CONST D3DCOLORVALUE * () const +{ + return (CONST D3DCOLORVALUE *) &r; +} + + +D3DXINLINE +D3DXCOLOR::operator D3DCOLORVALUE& () +{ + return *((D3DCOLORVALUE *) &r); +} + +D3DXINLINE +D3DXCOLOR::operator CONST D3DCOLORVALUE& () const +{ + return *((CONST D3DCOLORVALUE *) &r); +} + +/* assignment operators */ +D3DXINLINE D3DXCOLOR& +D3DXCOLOR::operator += ( CONST D3DXCOLOR& c ) +{ + r += c.r; + g += c.g; + b += c.b; + a += c.a; + return *this; +} + +D3DXINLINE D3DXCOLOR& +D3DXCOLOR::operator -= ( CONST D3DXCOLOR& c ) +{ + r -= c.r; + g -= c.g; + b -= c.b; + a -= c.a; + return *this; +} + +D3DXINLINE D3DXCOLOR& +D3DXCOLOR::operator *= ( FLOAT f ) +{ + r *= f; + g *= f; + b *= f; + a *= f; + return *this; +} + +D3DXINLINE D3DXCOLOR& +D3DXCOLOR::operator /= ( FLOAT f ) +{ + FLOAT fInv = 1.0f / f; + r *= fInv; + g *= fInv; + b *= fInv; + a *= fInv; + return *this; +} + +/* unary operators */ +D3DXINLINE D3DXCOLOR +D3DXCOLOR::operator + () const +{ + return *this; +} + +D3DXINLINE D3DXCOLOR +D3DXCOLOR::operator - () const +{ + return D3DXCOLOR(-r, -g, -b, -a); +} + + +/* binary operators */ +D3DXINLINE D3DXCOLOR +D3DXCOLOR::operator + ( CONST D3DXCOLOR& c ) const +{ + return D3DXCOLOR(r + c.r, g + c.g, b + c.b, a + c.a); +} + +D3DXINLINE D3DXCOLOR +D3DXCOLOR::operator - ( CONST D3DXCOLOR& c ) const +{ + return D3DXCOLOR(r - c.r, g - c.g, b - c.b, a - c.a); +} + +D3DXINLINE D3DXCOLOR +D3DXCOLOR::operator * ( FLOAT f ) const +{ + return D3DXCOLOR(r * f, g * f, b * f, a * f); +} + +D3DXINLINE D3DXCOLOR +D3DXCOLOR::operator / ( FLOAT f ) const +{ + FLOAT fInv = 1.0f / f; + return D3DXCOLOR(r * fInv, g * fInv, b * fInv, a * fInv); +} + + +D3DXINLINE D3DXCOLOR +operator * (FLOAT f, CONST D3DXCOLOR& c ) +{ + return D3DXCOLOR(f * c.r, f * c.g, f * c.b, f * c.a); +} + + +D3DXINLINE BOOL +D3DXCOLOR::operator == ( CONST D3DXCOLOR& c ) const +{ + return r == c.r && g == c.g && b == c.b && a == c.a; +} + +D3DXINLINE BOOL +D3DXCOLOR::operator != ( CONST D3DXCOLOR& c ) const +{ + return r != c.r || g != c.g || b != c.b || a != c.a; +} + + +#endif /* __cplusplus */ + +/* + * + * Inline functions + * + */ + + +/* + * 2D Vector + */ + +D3DXINLINE FLOAT D3DXVec2Length + ( CONST D3DXVECTOR2 *pV ) +{ +#ifdef D3DX_DEBUG + if(!pV) + return 0.0f; +#endif + +#ifdef __cplusplus + return sqrtf(pV->x * pV->x + pV->y * pV->y); +#else + return (FLOAT) sqrt(pV->x * pV->x + pV->y * pV->y); +#endif +} + +D3DXINLINE FLOAT D3DXVec2LengthSq + ( CONST D3DXVECTOR2 *pV ) +{ +#ifdef D3DX_DEBUG + if(!pV) + return 0.0f; +#endif + + return pV->x * pV->x + pV->y * pV->y; +} + +D3DXINLINE FLOAT D3DXVec2Dot + ( CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pV1 || !pV2) + return 0.0f; +#endif + + return pV1->x * pV2->x + pV1->y * pV2->y; +} + +D3DXINLINE FLOAT D3DXVec2CCW + ( CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pV1 || !pV2) + return 0.0f; +#endif + + return pV1->x * pV2->y - pV1->y * pV2->x; +} + +D3DXINLINE D3DXVECTOR2* D3DXVec2Add + ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x + pV2->x; + pOut->y = pV1->y + pV2->y; + return pOut; +} + +D3DXINLINE D3DXVECTOR2* D3DXVec2Subtract + ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x - pV2->x; + pOut->y = pV1->y - pV2->y; + return pOut; +} + +D3DXINLINE D3DXVECTOR2* D3DXVec2Minimize + ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x; + pOut->y = pV1->y < pV2->y ? pV1->y : pV2->y; + return pOut; +} + +D3DXINLINE D3DXVECTOR2* D3DXVec2Maximize + ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x; + pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y; + return pOut; +} + +D3DXINLINE D3DXVECTOR2* D3DXVec2Scale + ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV, FLOAT s ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV) + return NULL; +#endif + + pOut->x = pV->x * s; + pOut->y = pV->y * s; + return pOut; +} + +D3DXINLINE D3DXVECTOR2* D3DXVec2Lerp + ( D3DXVECTOR2 *pOut, CONST D3DXVECTOR2 *pV1, CONST D3DXVECTOR2 *pV2, + FLOAT s ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x + s * (pV2->x - pV1->x); + pOut->y = pV1->y + s * (pV2->y - pV1->y); + return pOut; +} + + +/* + * 3D Vector + */ + +D3DXINLINE FLOAT D3DXVec3Length + ( CONST D3DXVECTOR3 *pV ) +{ +#ifdef D3DX_DEBUG + if(!pV) + return 0.0f; +#endif + +#ifdef __cplusplus + return sqrtf(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z); +#else + return (FLOAT) sqrt(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z); +#endif +} + +D3DXINLINE FLOAT D3DXVec3LengthSq + ( CONST D3DXVECTOR3 *pV ) +{ +#ifdef D3DX_DEBUG + if(!pV) + return 0.0f; +#endif + + return pV->x * pV->x + pV->y * pV->y + pV->z * pV->z; +} + +D3DXINLINE FLOAT D3DXVec3Dot + ( CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pV1 || !pV2) + return 0.0f; +#endif + + return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Cross + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ + D3DXVECTOR3 v; + +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + v.x = pV1->y * pV2->z - pV1->z * pV2->y; + v.y = pV1->z * pV2->x - pV1->x * pV2->z; + v.z = pV1->x * pV2->y - pV1->y * pV2->x; + + *pOut = v; + return pOut; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Add + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x + pV2->x; + pOut->y = pV1->y + pV2->y; + pOut->z = pV1->z + pV2->z; + return pOut; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Subtract + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x - pV2->x; + pOut->y = pV1->y - pV2->y; + pOut->z = pV1->z - pV2->z; + return pOut; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Minimize + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x; + pOut->y = pV1->y < pV2->y ? pV1->y : pV2->y; + pOut->z = pV1->z < pV2->z ? pV1->z : pV2->z; + return pOut; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Maximize + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x; + pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y; + pOut->z = pV1->z > pV2->z ? pV1->z : pV2->z; + return pOut; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Scale + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, FLOAT s) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV) + return NULL; +#endif + + pOut->x = pV->x * s; + pOut->y = pV->y * s; + pOut->z = pV->z * s; + return pOut; +} + +D3DXINLINE D3DXVECTOR3* D3DXVec3Lerp + ( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2, + FLOAT s ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x + s * (pV2->x - pV1->x); + pOut->y = pV1->y + s * (pV2->y - pV1->y); + pOut->z = pV1->z + s * (pV2->z - pV1->z); + return pOut; +} + + +/* + * 4D Vector + */ + +D3DXINLINE FLOAT D3DXVec4Length + ( CONST D3DXVECTOR4 *pV ) +{ +#ifdef D3DX_DEBUG + if(!pV) + return 0.0f; +#endif + +#ifdef __cplusplus + return sqrtf(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z + pV->w * pV->w); +#else + return (FLOAT) sqrt(pV->x * pV->x + pV->y * pV->y + pV->z * pV->z + pV->w * pV->w); +#endif +} + +D3DXINLINE FLOAT D3DXVec4LengthSq + ( CONST D3DXVECTOR4 *pV ) +{ +#ifdef D3DX_DEBUG + if(!pV) + return 0.0f; +#endif + + return pV->x * pV->x + pV->y * pV->y + pV->z * pV->z + pV->w * pV->w; +} + +D3DXINLINE FLOAT D3DXVec4Dot + ( CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2 ) +{ +#ifdef D3DX_DEBUG + if(!pV1 || !pV2) + return 0.0f; +#endif + + return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z + pV1->w * pV2->w; +} + +D3DXINLINE D3DXVECTOR4* D3DXVec4Add + ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x + pV2->x; + pOut->y = pV1->y + pV2->y; + pOut->z = pV1->z + pV2->z; + pOut->w = pV1->w + pV2->w; + return pOut; +} + +D3DXINLINE D3DXVECTOR4* D3DXVec4Subtract + ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x - pV2->x; + pOut->y = pV1->y - pV2->y; + pOut->z = pV1->z - pV2->z; + pOut->w = pV1->w - pV2->w; + return pOut; +} + +D3DXINLINE D3DXVECTOR4* D3DXVec4Minimize + ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x < pV2->x ? pV1->x : pV2->x; + pOut->y = pV1->y < pV2->y ? pV1->y : pV2->y; + pOut->z = pV1->z < pV2->z ? pV1->z : pV2->z; + pOut->w = pV1->w < pV2->w ? pV1->w : pV2->w; + return pOut; +} + +D3DXINLINE D3DXVECTOR4* D3DXVec4Maximize + ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x; + pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y; + pOut->z = pV1->z > pV2->z ? pV1->z : pV2->z; + pOut->w = pV1->w > pV2->w ? pV1->w : pV2->w; + return pOut; +} + +D3DXINLINE D3DXVECTOR4* D3DXVec4Scale + ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, FLOAT s) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV) + return NULL; +#endif + + pOut->x = pV->x * s; + pOut->y = pV->y * s; + pOut->z = pV->z * s; + pOut->w = pV->w * s; + return pOut; +} + +D3DXINLINE D3DXVECTOR4* D3DXVec4Lerp + ( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV1, CONST D3DXVECTOR4 *pV2, + FLOAT s ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pV1 || !pV2) + return NULL; +#endif + + pOut->x = pV1->x + s * (pV2->x - pV1->x); + pOut->y = pV1->y + s * (pV2->y - pV1->y); + pOut->z = pV1->z + s * (pV2->z - pV1->z); + pOut->w = pV1->w + s * (pV2->w - pV1->w); + return pOut; +} + + +/* + * 4D Matrix + */ + +D3DXINLINE D3DXMATRIX* D3DXMatrixIdentity + ( D3DXMATRIX *pOut ) +{ +#ifdef D3DX_DEBUG + if(!pOut) + return NULL; +#endif + + pOut->m[0][1] = pOut->m[0][2] = pOut->m[0][3] = + pOut->m[1][0] = pOut->m[1][2] = pOut->m[1][3] = + pOut->m[2][0] = pOut->m[2][1] = pOut->m[2][3] = + pOut->m[3][0] = pOut->m[3][1] = pOut->m[3][2] = 0.0f; + + pOut->m[0][0] = pOut->m[1][1] = pOut->m[2][2] = pOut->m[3][3] = 1.0f; + return pOut; +} + + +D3DXINLINE BOOL D3DXMatrixIsIdentity + ( CONST D3DXMATRIX *pM ) +{ +#ifdef D3DX_DEBUG + if(!pM) + return FALSE; +#endif + + return pM->m[0][0] == 1.0f && pM->m[0][1] == 0.0f && pM->m[0][2] == 0.0f && pM->m[0][3] == 0.0f && + pM->m[1][0] == 0.0f && pM->m[1][1] == 1.0f && pM->m[1][2] == 0.0f && pM->m[1][3] == 0.0f && + pM->m[2][0] == 0.0f && pM->m[2][1] == 0.0f && pM->m[2][2] == 1.0f && pM->m[2][3] == 0.0f && + pM->m[3][0] == 0.0f && pM->m[3][1] == 0.0f && pM->m[3][2] == 0.0f && pM->m[3][3] == 1.0f; +} + + +/* + * Quaternion + */ + +D3DXINLINE FLOAT D3DXQuaternionLength + ( CONST D3DXQUATERNION *pQ ) +{ +#ifdef D3DX_DEBUG + if(!pQ) + return 0.0f; +#endif + +#ifdef __cplusplus + return sqrtf(pQ->x * pQ->x + pQ->y * pQ->y + pQ->z * pQ->z + pQ->w * pQ->w); +#else + return (FLOAT) sqrt(pQ->x * pQ->x + pQ->y * pQ->y + pQ->z * pQ->z + pQ->w * pQ->w); +#endif +} + +D3DXINLINE FLOAT D3DXQuaternionLengthSq + ( CONST D3DXQUATERNION *pQ ) +{ +#ifdef D3DX_DEBUG + if(!pQ) + return 0.0f; +#endif + + return pQ->x * pQ->x + pQ->y * pQ->y + pQ->z * pQ->z + pQ->w * pQ->w; +} + +D3DXINLINE FLOAT D3DXQuaternionDot + ( CONST D3DXQUATERNION *pQ1, CONST D3DXQUATERNION *pQ2 ) +{ +#ifdef D3DX_DEBUG + if(!pQ1 || !pQ2) + return 0.0f; +#endif + + return pQ1->x * pQ2->x + pQ1->y * pQ2->y + pQ1->z * pQ2->z + pQ1->w * pQ2->w; +} + + +D3DXINLINE D3DXQUATERNION* D3DXQuaternionIdentity + ( D3DXQUATERNION *pOut ) +{ +#ifdef D3DX_DEBUG + if(!pOut) + return NULL; +#endif + + pOut->x = pOut->y = pOut->z = 0.0f; + pOut->w = 1.0f; + return pOut; +} + +D3DXINLINE BOOL D3DXQuaternionIsIdentity + ( CONST D3DXQUATERNION *pQ ) +{ +#ifdef D3DX_DEBUG + if(!pQ) + return FALSE; +#endif + + return pQ->x == 0.0f && pQ->y == 0.0f && pQ->z == 0.0f && pQ->w == 1.0f; +} + + +D3DXINLINE D3DXQUATERNION* D3DXQuaternionConjugate + ( D3DXQUATERNION *pOut, CONST D3DXQUATERNION *pQ ) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pQ) + return NULL; +#endif + + pOut->x = -pQ->x; + pOut->y = -pQ->y; + pOut->z = -pQ->z; + pOut->w = pQ->w; + return pOut; +} + + +/* + * Plane + */ + +D3DXINLINE FLOAT D3DXPlaneDot + ( CONST D3DXPLANE *pP, CONST D3DXVECTOR4 *pV) +{ +#ifdef D3DX_DEBUG + if(!pP || !pV) + return 0.0f; +#endif + + return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z + pP->d * pV->w; +} + +D3DXINLINE FLOAT D3DXPlaneDotCoord + ( CONST D3DXPLANE *pP, CONST D3DXVECTOR3 *pV) +{ +#ifdef D3DX_DEBUG + if(!pP || !pV) + return 0.0f; +#endif + + return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z + pP->d; +} + +D3DXINLINE FLOAT D3DXPlaneDotNormal + ( CONST D3DXPLANE *pP, CONST D3DXVECTOR3 *pV) +{ +#ifdef D3DX_DEBUG + if(!pP || !pV) + return 0.0f; +#endif + + return pP->a * pV->x + pP->b * pV->y + pP->c * pV->z; +} + + +/* + * Color + */ + +D3DXINLINE D3DXCOLOR* D3DXColorNegative + (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pC) + return NULL; +#endif + + pOut->r = 1.0f - pC->r; + pOut->g = 1.0f - pC->g; + pOut->b = 1.0f - pC->b; + pOut->a = pC->a; + return pOut; +} + +D3DXINLINE D3DXCOLOR* D3DXColorAdd + (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pC1 || !pC2) + return NULL; +#endif + + pOut->r = pC1->r + pC2->r; + pOut->g = pC1->g + pC2->g; + pOut->b = pC1->b + pC2->b; + pOut->a = pC1->a + pC2->a; + return pOut; +} + +D3DXINLINE D3DXCOLOR* D3DXColorSubtract + (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pC1 || !pC2) + return NULL; +#endif + + pOut->r = pC1->r - pC2->r; + pOut->g = pC1->g - pC2->g; + pOut->b = pC1->b - pC2->b; + pOut->a = pC1->a - pC2->a; + return pOut; +} + +D3DXINLINE D3DXCOLOR* D3DXColorScale + (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC, FLOAT s) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pC) + return NULL; +#endif + + pOut->r = pC->r * s; + pOut->g = pC->g * s; + pOut->b = pC->b * s; + pOut->a = pC->a * s; + return pOut; +} + +D3DXINLINE D3DXCOLOR* D3DXColorModulate + (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pC1 || !pC2) + return NULL; +#endif + + pOut->r = pC1->r * pC2->r; + pOut->g = pC1->g * pC2->g; + pOut->b = pC1->b * pC2->b; + pOut->a = pC1->a * pC2->a; + return pOut; +} + +D3DXINLINE D3DXCOLOR* D3DXColorLerp + (D3DXCOLOR *pOut, CONST D3DXCOLOR *pC1, CONST D3DXCOLOR *pC2, FLOAT s) +{ +#ifdef D3DX_DEBUG + if(!pOut || !pC1 || !pC2) + return NULL; +#endif + + pOut->r = pC1->r + s * (pC2->r - pC1->r); + pOut->g = pC1->g + s * (pC2->g - pC1->g); + pOut->b = pC1->b + s * (pC2->b - pC1->b); + pOut->a = pC1->a + s * (pC2->a - pC1->a); + return pOut; +} + + +#endif /* __D3DX8MATH_INL__ */ diff --git a/gfx/video_crt_switch.c b/gfx/video_crt_switch.c index cfe73b8e58..f55456529d 100644 --- a/gfx/video_crt_switch.c +++ b/gfx/video_crt_switch.c @@ -1,364 +1,364 @@ -/* CRT SwitchRes Core - * Copyright (C) 2018 Alphanu / Ben Templeman. - * - * RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ -#include -#include -#include - -#include "video_driver.h" -#include "video_crt_switch.h" -#include "video_display_server.h" - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#if defined(HAVE_VIDEOCORE) -#include "include/userland/interface/vmcs_host/vc_vchi_gencmd.h" -static void crt_rpi_switch(int width, int height, float hz); -#endif - -static unsigned ra_core_width = 0; -static unsigned ra_core_height = 0; -static unsigned ra_tmp_width = 0; -static unsigned ra_tmp_height = 0; -static unsigned ra_set_core_hz = 0; -static unsigned orig_width = 0; -static unsigned orig_height = 0; -static int crt_center_adjust = 0; - -static bool first_run = true; - -static float ra_tmp_core_hz = 0.0f; -static float fly_aspect = 0.0f; -static float ra_core_hz = 0.0f; -static unsigned crt_index = 0; - -static void crt_check_first_run(void) -{ - if (!first_run) - return; - - first_run = false; -} - -static void switch_crt_hz(void) -{ - if (ra_core_hz == ra_tmp_core_hz) - return; - /* set hz float to an int for windows switching */ - if (ra_core_hz < 100) - { - if (ra_core_hz < 53) - ra_set_core_hz = 50; - if (ra_core_hz >= 53 && ra_core_hz < 57) - ra_set_core_hz = 55; - if (ra_core_hz >= 57) - ra_set_core_hz = 60; - } - - if (ra_core_hz > 100) - { - if (ra_core_hz < 106) - ra_set_core_hz = 120; - if (ra_core_hz >= 106 && ra_core_hz < 114) - ra_set_core_hz = 110; - if (ra_core_hz >= 114) - ra_set_core_hz = 120; - } - - video_monitor_set_refresh_rate(ra_set_core_hz); - - ra_tmp_core_hz = ra_core_hz; -} - -void crt_aspect_ratio_switch(unsigned width, unsigned height) -{ - /* send aspect float to videeo_driver */ - fly_aspect = (float)width / height; - video_driver_set_aspect_ratio_value((float)fly_aspect); -} - -static void switch_res_crt(unsigned width, unsigned height) -{ - video_display_server_set_resolution(width, height, - ra_set_core_hz, ra_core_hz, crt_center_adjust, crt_index); -#if defined(HAVE_VIDEOCORE) - crt_rpi_switch(width, height, ra_core_hz); - video_monitor_set_refresh_rate(ra_core_hz); - crt_switch_driver_reinit(); -#endif - video_driver_apply_state_changes(); -} - -/* Create correct aspect to fit video if resolution does not exist */ -static void crt_screen_setup_aspect(unsigned width, unsigned height) -{ -#if defined(HAVE_VIDEOCORE) - if (height > 300) - height = height/2; -#endif - - switch_crt_hz(); - /* get original resolution of core */ - if (height == 4) - { - /* detect menu only */ - if (width < 1920) - width = 320; - - height = 240; - - crt_aspect_ratio_switch(width, height); - } - - if (height < 200 && height != 144) - { - crt_aspect_ratio_switch(width, height); - height = 200; - } - - if (height > 200) - crt_aspect_ratio_switch(width, height); - - if (height == 144 && ra_set_core_hz == 50) - { - height = 288; - crt_aspect_ratio_switch(width, height); - } - - if (height > 200 && height < 224) - { - crt_aspect_ratio_switch(width, height); - height = 224; - } - - if (height > 224 && height < 240) - { - crt_aspect_ratio_switch(width, height); - height = 240; - } - - if (height > 240 && height < 255) - { - crt_aspect_ratio_switch(width, height); - height = 254; - } - - if (height == 528 && ra_set_core_hz == 60) - { - crt_aspect_ratio_switch(width, height); - height = 480; - } - - if (height >= 240 && height < 255 && ra_set_core_hz == 55) - { - crt_aspect_ratio_switch(width, height); - height = 254; - } - - switch_res_crt(width, height); -} - -void crt_switch_res_core(unsigned width, unsigned height, - float hz, unsigned crt_mode, - int crt_switch_center_adjust, int monitor_index) -{ - /* ra_core_hz float passed from within - * void video_driver_monitor_adjust_system_rates(void) */ - - ra_core_width = width; - ra_core_height = height; - ra_core_hz = hz; - crt_center_adjust = crt_switch_center_adjust; - crt_index = monitor_index; - - if (crt_mode == 2) - { - if (hz > 53) - ra_core_hz = hz * 2; - - if (hz <= 53) - ra_core_hz = 120.0f; - } - - crt_check_first_run(); - - /* Detect resolution change and switch */ - if ( - (ra_tmp_height != ra_core_height) || - (ra_core_width != ra_tmp_width) - ) - crt_screen_setup_aspect(width, height); - - ra_tmp_height = ra_core_height; - ra_tmp_width = ra_core_width; - - /* Check if aspect is correct, if notchange */ - if (video_driver_get_aspect_ratio() != fly_aspect) - { - video_driver_set_aspect_ratio_value((float)fly_aspect); - video_driver_apply_state_changes(); - } -} - -void crt_video_restore(void) -{ - if (first_run) - return; - - first_run = true; -} - -#if defined(HAVE_VIDEOCORE) -static void crt_rpi_switch(int width, int height, float hz) -{ - char buffer[1024]; - VCHI_INSTANCE_T vchi_instance; - VCHI_CONNECTION_T *vchi_connection = NULL; - static char output[250] = {0}; - static char output1[250] = {0}; - static char output2[250] = {0}; - static char set_hdmi[250] = {0}; - static char set_hdmi_timing[250] = {0}; - int i = 0; - int hfp = 0; - int hsp = 0; - int hbp = 0; - int vfp = 0; - int vsp = 0; - int vbp = 0; - int hmax = 0; - int vmax = 0; - int pdefault = 8; - int pwidth = 0; - float roundw = 0.0f; - float roundh = 0.0f; - float pixel_clock = 0; - int ip_flag = 0; - - /* set core refresh from hz */ - video_monitor_set_refresh_rate(hz); - - /* following code is the mode line generator */ - - pwidth = width; - - if (height < 400 && width > 400) - pwidth = width / 2; - - roundw = roundf((float)pwidth / (float)height * 100) / 100; - - if (height > width) - roundw = roundf((float)height / (float)width * 100) / 100; - - if (roundw > 1.35) - roundw = 1.25; - - if (roundw < 1.20) - roundw = 1.34; - hfp = width * 0.065; - - hsp = width * 0.1433-hfp; - - hbp = width * 0.3-hsp-hfp; - - - if (height < 241) - vmax = 261; - if (height < 241 && hz > 56 && hz < 58) - vmax = 280; - if (height < 241 && hz < 55) - vmax = 313; - if (height > 250 && height < 260 && hz > 54) - vmax = 296; - if (height > 250 && height < 260 && hz > 52 && hz < 54) - vmax = 285; - if (height > 250 && height < 260 && hz < 52) - vmax = 313; - if (height > 260 && height < 300) - vmax = 318; - - if (height > 400 && hz > 56) - vmax = 533; - if (height > 520 && hz < 57) - vmax = 580; - - if (height > 300 && hz < 56) - vmax = 615; - if (height > 500 && hz < 56) - vmax = 624; - if (height > 300) - pdefault = pdefault * 2; - - vfp = (height + ((vmax - height) / 2) - pdefault) - height; - - if (height < 300) - vsp = vfp + 3; /* needs to be 3 for progressive */ - if (height > 300) - vsp = vfp + 6; /* needs to be 6 for interlaced */ - - vsp = 3; - - vbp = (vmax-height)-vsp-vfp; - - hmax = width+hfp+hsp+hbp; - - if (height < 300) - { - pixel_clock = (hmax * vmax * hz) ; - ip_flag = 0; - } - - if (height > 300) - { - pixel_clock = (hmax * vmax * (hz/2)) /2 ; - ip_flag = 1; - } - /* above code is the modeline generator */ - - snprintf(set_hdmi_timing, sizeof(set_hdmi_timing), - "hdmi_timings %d 1 %d %d %d %d 1 %d %d %d 0 0 0 %f %d %f 1 ", - width, hfp, hsp, hbp, height, vfp,vsp, vbp, - hz, ip_flag, pixel_clock); - - vcos_init (); - - vchi_initialise (&vchi_instance); - - vchi_connect (NULL, 0, vchi_instance); - - vc_vchi_gencmd_init (vchi_instance, &vchi_connection, 1); - - - vc_gencmd (buffer, sizeof (buffer), set_hdmi_timing); - - vc_gencmd_stop (); - - vchi_disconnect (vchi_instance); - - snprintf(output1, sizeof(output1), - "tvservice -e \"DMT 87\" > /dev/null"); - system(output1); - snprintf(output2, sizeof(output1), - "fbset -g %d %d %d %d 24 > /dev/null", - width, height, width, height); - system(output2); -} -#endif - +/* CRT SwitchRes Core + * Copyright (C) 2018 Alphanu / Ben Templeman. + * + * RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ +#include +#include +#include + +#include "video_driver.h" +#include "video_crt_switch.h" +#include "video_display_server.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#if defined(HAVE_VIDEOCORE) +#include "include/userland/interface/vmcs_host/vc_vchi_gencmd.h" +static void crt_rpi_switch(int width, int height, float hz); +#endif + +static unsigned ra_core_width = 0; +static unsigned ra_core_height = 0; +static unsigned ra_tmp_width = 0; +static unsigned ra_tmp_height = 0; +static unsigned ra_set_core_hz = 0; +static unsigned orig_width = 0; +static unsigned orig_height = 0; +static int crt_center_adjust = 0; + +static bool first_run = true; + +static float ra_tmp_core_hz = 0.0f; +static float fly_aspect = 0.0f; +static float ra_core_hz = 0.0f; +static unsigned crt_index = 0; + +static void crt_check_first_run(void) +{ + if (!first_run) + return; + + first_run = false; +} + +static void switch_crt_hz(void) +{ + if (ra_core_hz == ra_tmp_core_hz) + return; + /* set hz float to an int for windows switching */ + if (ra_core_hz < 100) + { + if (ra_core_hz < 53) + ra_set_core_hz = 50; + if (ra_core_hz >= 53 && ra_core_hz < 57) + ra_set_core_hz = 55; + if (ra_core_hz >= 57) + ra_set_core_hz = 60; + } + + if (ra_core_hz > 100) + { + if (ra_core_hz < 106) + ra_set_core_hz = 120; + if (ra_core_hz >= 106 && ra_core_hz < 114) + ra_set_core_hz = 110; + if (ra_core_hz >= 114) + ra_set_core_hz = 120; + } + + video_monitor_set_refresh_rate(ra_set_core_hz); + + ra_tmp_core_hz = ra_core_hz; +} + +void crt_aspect_ratio_switch(unsigned width, unsigned height) +{ + /* send aspect float to videeo_driver */ + fly_aspect = (float)width / height; + video_driver_set_aspect_ratio_value((float)fly_aspect); +} + +static void switch_res_crt(unsigned width, unsigned height) +{ + video_display_server_set_resolution(width, height, + ra_set_core_hz, ra_core_hz, crt_center_adjust, crt_index); +#if defined(HAVE_VIDEOCORE) + crt_rpi_switch(width, height, ra_core_hz); + video_monitor_set_refresh_rate(ra_core_hz); + crt_switch_driver_reinit(); +#endif + video_driver_apply_state_changes(); +} + +/* Create correct aspect to fit video if resolution does not exist */ +static void crt_screen_setup_aspect(unsigned width, unsigned height) +{ +#if defined(HAVE_VIDEOCORE) + if (height > 300) + height = height/2; +#endif + + switch_crt_hz(); + /* get original resolution of core */ + if (height == 4) + { + /* detect menu only */ + if (width < 1920) + width = 320; + + height = 240; + + crt_aspect_ratio_switch(width, height); + } + + if (height < 200 && height != 144) + { + crt_aspect_ratio_switch(width, height); + height = 200; + } + + if (height > 200) + crt_aspect_ratio_switch(width, height); + + if (height == 144 && ra_set_core_hz == 50) + { + height = 288; + crt_aspect_ratio_switch(width, height); + } + + if (height > 200 && height < 224) + { + crt_aspect_ratio_switch(width, height); + height = 224; + } + + if (height > 224 && height < 240) + { + crt_aspect_ratio_switch(width, height); + height = 240; + } + + if (height > 240 && height < 255) + { + crt_aspect_ratio_switch(width, height); + height = 254; + } + + if (height == 528 && ra_set_core_hz == 60) + { + crt_aspect_ratio_switch(width, height); + height = 480; + } + + if (height >= 240 && height < 255 && ra_set_core_hz == 55) + { + crt_aspect_ratio_switch(width, height); + height = 254; + } + + switch_res_crt(width, height); +} + +void crt_switch_res_core(unsigned width, unsigned height, + float hz, unsigned crt_mode, + int crt_switch_center_adjust, int monitor_index) +{ + /* ra_core_hz float passed from within + * void video_driver_monitor_adjust_system_rates(void) */ + + ra_core_width = width; + ra_core_height = height; + ra_core_hz = hz; + crt_center_adjust = crt_switch_center_adjust; + crt_index = monitor_index; + + if (crt_mode == 2) + { + if (hz > 53) + ra_core_hz = hz * 2; + + if (hz <= 53) + ra_core_hz = 120.0f; + } + + crt_check_first_run(); + + /* Detect resolution change and switch */ + if ( + (ra_tmp_height != ra_core_height) || + (ra_core_width != ra_tmp_width) + ) + crt_screen_setup_aspect(width, height); + + ra_tmp_height = ra_core_height; + ra_tmp_width = ra_core_width; + + /* Check if aspect is correct, if notchange */ + if (video_driver_get_aspect_ratio() != fly_aspect) + { + video_driver_set_aspect_ratio_value((float)fly_aspect); + video_driver_apply_state_changes(); + } +} + +void crt_video_restore(void) +{ + if (first_run) + return; + + first_run = true; +} + +#if defined(HAVE_VIDEOCORE) +static void crt_rpi_switch(int width, int height, float hz) +{ + char buffer[1024]; + VCHI_INSTANCE_T vchi_instance; + VCHI_CONNECTION_T *vchi_connection = NULL; + static char output[250] = {0}; + static char output1[250] = {0}; + static char output2[250] = {0}; + static char set_hdmi[250] = {0}; + static char set_hdmi_timing[250] = {0}; + int i = 0; + int hfp = 0; + int hsp = 0; + int hbp = 0; + int vfp = 0; + int vsp = 0; + int vbp = 0; + int hmax = 0; + int vmax = 0; + int pdefault = 8; + int pwidth = 0; + float roundw = 0.0f; + float roundh = 0.0f; + float pixel_clock = 0; + int ip_flag = 0; + + /* set core refresh from hz */ + video_monitor_set_refresh_rate(hz); + + /* following code is the mode line generator */ + + pwidth = width; + + if (height < 400 && width > 400) + pwidth = width / 2; + + roundw = roundf((float)pwidth / (float)height * 100) / 100; + + if (height > width) + roundw = roundf((float)height / (float)width * 100) / 100; + + if (roundw > 1.35) + roundw = 1.25; + + if (roundw < 1.20) + roundw = 1.34; + hfp = width * 0.065; + + hsp = width * 0.1433-hfp; + + hbp = width * 0.3-hsp-hfp; + + + if (height < 241) + vmax = 261; + if (height < 241 && hz > 56 && hz < 58) + vmax = 280; + if (height < 241 && hz < 55) + vmax = 313; + if (height > 250 && height < 260 && hz > 54) + vmax = 296; + if (height > 250 && height < 260 && hz > 52 && hz < 54) + vmax = 285; + if (height > 250 && height < 260 && hz < 52) + vmax = 313; + if (height > 260 && height < 300) + vmax = 318; + + if (height > 400 && hz > 56) + vmax = 533; + if (height > 520 && hz < 57) + vmax = 580; + + if (height > 300 && hz < 56) + vmax = 615; + if (height > 500 && hz < 56) + vmax = 624; + if (height > 300) + pdefault = pdefault * 2; + + vfp = (height + ((vmax - height) / 2) - pdefault) - height; + + if (height < 300) + vsp = vfp + 3; /* needs to be 3 for progressive */ + if (height > 300) + vsp = vfp + 6; /* needs to be 6 for interlaced */ + + vsp = 3; + + vbp = (vmax-height)-vsp-vfp; + + hmax = width+hfp+hsp+hbp; + + if (height < 300) + { + pixel_clock = (hmax * vmax * hz) ; + ip_flag = 0; + } + + if (height > 300) + { + pixel_clock = (hmax * vmax * (hz/2)) /2 ; + ip_flag = 1; + } + /* above code is the modeline generator */ + + snprintf(set_hdmi_timing, sizeof(set_hdmi_timing), + "hdmi_timings %d 1 %d %d %d %d 1 %d %d %d 0 0 0 %f %d %f 1 ", + width, hfp, hsp, hbp, height, vfp,vsp, vbp, + hz, ip_flag, pixel_clock); + + vcos_init (); + + vchi_initialise (&vchi_instance); + + vchi_connect (NULL, 0, vchi_instance); + + vc_vchi_gencmd_init (vchi_instance, &vchi_connection, 1); + + + vc_gencmd (buffer, sizeof (buffer), set_hdmi_timing); + + vc_gencmd_stop (); + + vchi_disconnect (vchi_instance); + + snprintf(output1, sizeof(output1), + "tvservice -e \"DMT 87\" > /dev/null"); + system(output1); + snprintf(output2, sizeof(output1), + "fbset -g %d %d %d %d 24 > /dev/null", + width, height, width, height); + system(output2); +} +#endif + diff --git a/gfx/video_crt_switch.h b/gfx/video_crt_switch.h index df388ec2ce..8bf588bae7 100644 --- a/gfx/video_crt_switch.h +++ b/gfx/video_crt_switch.h @@ -1,38 +1,38 @@ -/* CRT SwitchRes Core - * Copyright (C) 2018 Alphanu / Ben Templeman. - * - * RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __VIDEO_CRT_SWITCH_H__ -#define __VIDEO_CRT_SWITCH_H__ - -#include - -#include -#include - -RETRO_BEGIN_DECLS - -void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust, int monitor_index); - -void crt_aspect_ratio_switch(unsigned width, unsigned height); - -void crt_video_restore(void); - -RETRO_END_DECLS - -#endif +/* CRT SwitchRes Core + * Copyright (C) 2018 Alphanu / Ben Templeman. + * + * RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __VIDEO_CRT_SWITCH_H__ +#define __VIDEO_CRT_SWITCH_H__ + +#include + +#include +#include + +RETRO_BEGIN_DECLS + +void crt_switch_res_core(unsigned width, unsigned height, float hz, unsigned crt_mode, int crt_switch_center_adjust, int monitor_index); + +void crt_aspect_ratio_switch(unsigned width, unsigned height); + +void crt_video_restore(void); + +RETRO_END_DECLS + +#endif diff --git a/gfx/video_display_server.c b/gfx/video_display_server.c index 9917de9ddd..31d1b3a5b0 100644 --- a/gfx/video_display_server.c +++ b/gfx/video_display_server.c @@ -1,112 +1,112 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2016-2017 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include "video_display_server.h" -#include "video_driver.h" -#include "../verbosity.h" - -static const video_display_server_t *current_display_server = &dispserv_null; -static void *current_display_server_data = NULL; - -const char *video_display_server_get_ident(void) -{ - if (!current_display_server) - return "null"; - return current_display_server->ident; -} - -void* video_display_server_init(void) -{ - enum rarch_display_type type = video_driver_display_type_get(); - - video_display_server_destroy(); - - switch (type) - { - case RARCH_DISPLAY_WIN32: -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) - current_display_server = &dispserv_win32; -#endif - break; - case RARCH_DISPLAY_X11: -#if defined(HAVE_X11) - current_display_server = &dispserv_x11; -#endif - break; - default: - current_display_server = &dispserv_null; - break; - } - - current_display_server_data = current_display_server->init(); - - RARCH_LOG("[Video]: Found display server: %s\n", - current_display_server->ident); - - return current_display_server_data; -} - -void video_display_server_destroy(void) -{ - if (current_display_server && current_display_server->destroy) - if (current_display_server_data) - current_display_server->destroy(current_display_server_data); -} - -bool video_display_server_set_window_opacity(unsigned opacity) -{ - if (current_display_server && current_display_server->set_window_opacity) - return current_display_server->set_window_opacity(current_display_server_data, opacity); - return false; -} - -bool video_display_server_set_window_progress(int progress, bool finished) -{ - if (current_display_server && current_display_server->set_window_progress) - return current_display_server->set_window_progress(current_display_server_data, progress, finished); - return false; -} - -bool video_display_server_set_window_decorations(bool on) -{ - if (current_display_server && current_display_server->set_window_decorations) - return current_display_server->set_window_decorations(current_display_server_data, on); - return false; -} - -bool video_display_server_set_resolution(unsigned width, unsigned height, - int int_hz, float hz, int center, int monitor_index) -{ - if (current_display_server && current_display_server->set_resolution) - return current_display_server->set_resolution(current_display_server_data, width, height, int_hz, hz, center, monitor_index); - return false; -} - -void *video_display_server_get_resolution_list(unsigned *size) -{ - if (current_display_server && current_display_server->get_resolution_list) - return current_display_server->get_resolution_list(current_display_server_data, size); - return NULL; -} - -const char *video_display_server_get_output_options(void) -{ - if (current_display_server && current_display_server->get_output_options) - return current_display_server->get_output_options(current_display_server_data); - return NULL; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include "video_display_server.h" +#include "video_driver.h" +#include "../verbosity.h" + +static const video_display_server_t *current_display_server = &dispserv_null; +static void *current_display_server_data = NULL; + +const char *video_display_server_get_ident(void) +{ + if (!current_display_server) + return "null"; + return current_display_server->ident; +} + +void* video_display_server_init(void) +{ + enum rarch_display_type type = video_driver_display_type_get(); + + video_display_server_destroy(); + + switch (type) + { + case RARCH_DISPLAY_WIN32: +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) + current_display_server = &dispserv_win32; +#endif + break; + case RARCH_DISPLAY_X11: +#if defined(HAVE_X11) + current_display_server = &dispserv_x11; +#endif + break; + default: + current_display_server = &dispserv_null; + break; + } + + current_display_server_data = current_display_server->init(); + + RARCH_LOG("[Video]: Found display server: %s\n", + current_display_server->ident); + + return current_display_server_data; +} + +void video_display_server_destroy(void) +{ + if (current_display_server && current_display_server->destroy) + if (current_display_server_data) + current_display_server->destroy(current_display_server_data); +} + +bool video_display_server_set_window_opacity(unsigned opacity) +{ + if (current_display_server && current_display_server->set_window_opacity) + return current_display_server->set_window_opacity(current_display_server_data, opacity); + return false; +} + +bool video_display_server_set_window_progress(int progress, bool finished) +{ + if (current_display_server && current_display_server->set_window_progress) + return current_display_server->set_window_progress(current_display_server_data, progress, finished); + return false; +} + +bool video_display_server_set_window_decorations(bool on) +{ + if (current_display_server && current_display_server->set_window_decorations) + return current_display_server->set_window_decorations(current_display_server_data, on); + return false; +} + +bool video_display_server_set_resolution(unsigned width, unsigned height, + int int_hz, float hz, int center, int monitor_index) +{ + if (current_display_server && current_display_server->set_resolution) + return current_display_server->set_resolution(current_display_server_data, width, height, int_hz, hz, center, monitor_index); + return false; +} + +void *video_display_server_get_resolution_list(unsigned *size) +{ + if (current_display_server && current_display_server->get_resolution_list) + return current_display_server->get_resolution_list(current_display_server_data, size); + return NULL; +} + +const char *video_display_server_get_output_options(void) +{ + if (current_display_server && current_display_server->get_output_options) + return current_display_server->get_output_options(current_display_server_data); + return NULL; +} diff --git a/gfx/video_display_server.h b/gfx/video_display_server.h index d3c990ca85..8cb3be269f 100644 --- a/gfx/video_display_server.h +++ b/gfx/video_display_server.h @@ -1,77 +1,77 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2016-2017 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __VIDEO_DISPLAY_SERVER__H -#define __VIDEO_DISPLAY_SERVER__H - -#include -#include - -RETRO_BEGIN_DECLS - -typedef struct video_display_config -{ - unsigned width; - unsigned height; - unsigned bpp; - unsigned refreshrate; - unsigned idx; - bool current; -} video_display_config_t; - -typedef struct video_display_server -{ - void *(*init)(void); - void (*destroy)(void *data); - bool (*set_window_opacity)(void *data, unsigned opacity); - bool (*set_window_progress)(void *data, int progress, bool finished); - bool (*set_window_decorations)(void *data, bool on); - bool (*set_resolution)(void *data, unsigned width, - unsigned height, int int_hz, float hz, int center, int monitor_index); - void *(*get_resolution_list)(void *data, - unsigned *size); - const char *(*get_output_options)(void *data); - const char *ident; -} video_display_server_t; - -void* video_display_server_init(void); - -void video_display_server_destroy(void); - -bool video_display_server_set_window_opacity(unsigned opacity); - -bool video_display_server_set_window_progress(int progress, bool finished); - -bool video_display_server_set_window_decorations(bool on); - -bool video_display_server_set_resolution( - unsigned width, unsigned height, - int int_hz, float hz, int center, int monitor_index); - -void *video_display_server_get_resolution_list(unsigned *size); - -const char *video_display_server_get_output_options(void); - -const char *video_display_server_get_ident(void); - -extern const video_display_server_t dispserv_win32; -extern const video_display_server_t dispserv_x11; -extern const video_display_server_t dispserv_null; - -RETRO_END_DECLS - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __VIDEO_DISPLAY_SERVER__H +#define __VIDEO_DISPLAY_SERVER__H + +#include +#include + +RETRO_BEGIN_DECLS + +typedef struct video_display_config +{ + unsigned width; + unsigned height; + unsigned bpp; + unsigned refreshrate; + unsigned idx; + bool current; +} video_display_config_t; + +typedef struct video_display_server +{ + void *(*init)(void); + void (*destroy)(void *data); + bool (*set_window_opacity)(void *data, unsigned opacity); + bool (*set_window_progress)(void *data, int progress, bool finished); + bool (*set_window_decorations)(void *data, bool on); + bool (*set_resolution)(void *data, unsigned width, + unsigned height, int int_hz, float hz, int center, int monitor_index); + void *(*get_resolution_list)(void *data, + unsigned *size); + const char *(*get_output_options)(void *data); + const char *ident; +} video_display_server_t; + +void* video_display_server_init(void); + +void video_display_server_destroy(void); + +bool video_display_server_set_window_opacity(unsigned opacity); + +bool video_display_server_set_window_progress(int progress, bool finished); + +bool video_display_server_set_window_decorations(bool on); + +bool video_display_server_set_resolution( + unsigned width, unsigned height, + int int_hz, float hz, int center, int monitor_index); + +void *video_display_server_get_resolution_list(unsigned *size); + +const char *video_display_server_get_output_options(void); + +const char *video_display_server_get_ident(void); + +extern const video_display_server_t dispserv_win32; +extern const video_display_server_t dispserv_x11; +extern const video_display_server_t dispserv_null; + +RETRO_END_DECLS + +#endif diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 4ef0611f4a..d0230e2201 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -1,3634 +1,3634 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../audio/audio_driver.h" -#include "../menu/menu_shader.h" - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#include "../dynamic.h" - -#ifdef HAVE_THREADS -#include -#endif - -#ifdef HAVE_MENU -#include "../menu/menu_driver.h" -#include "../menu/menu_setting.h" -#endif - -#include "video_thread_wrapper.h" -#include "video_driver.h" -#include "video_display_server.h" -#include "video_crt_switch.h" - -#include "../frontend/frontend_driver.h" -#include "../record/record_driver.h" -#include "../config.def.h" -#include "../configuration.h" -#include "../driver.h" -#include "../retroarch.h" -#include "../input/input_driver.h" -#include "../list_special.h" -#include "../core.h" -#include "../command.h" -#include "../msg_hash.h" -#include "../verbosity.h" - -#define MEASURE_FRAME_TIME_SAMPLES_COUNT (2 * 1024) - -#define TIME_TO_FPS(last_time, new_time, frames) ((1000000.0f * (frames)) / ((new_time) - (last_time))) - -#define FPS_UPDATE_INTERVAL 256 - -#ifdef HAVE_THREADS -#define video_driver_is_threaded_internal() ((!video_driver_is_hw_context() && video_driver_threaded) ? true : false) -#else -#define video_driver_is_threaded_internal() (false) -#endif - -#ifdef HAVE_THREADS -#define video_driver_lock() \ - if (display_lock) \ - slock_lock(display_lock) - -#define video_driver_unlock() \ - if (display_lock) \ - slock_unlock(display_lock) - -#define video_driver_context_lock() \ - if (context_lock) \ - slock_lock(context_lock) - -#define video_driver_context_unlock() \ - if (context_lock) \ - slock_unlock(context_lock) - -#define video_driver_lock_free() \ - slock_free(display_lock); \ - slock_free(context_lock); \ - display_lock = NULL; \ - context_lock = NULL - -#define video_driver_threaded_lock(is_threaded) \ - if (is_threaded) \ - video_driver_lock() - -#define video_driver_threaded_unlock(is_threaded) \ - if (is_threaded) \ - video_driver_unlock() -#else -#define video_driver_lock() ((void)0) -#define video_driver_unlock() ((void)0) -#define video_driver_lock_free() ((void)0) -#define video_driver_threaded_lock(is_threaded) ((void)0) -#define video_driver_threaded_unlock(is_threaded) ((void)0) -#define video_driver_context_lock() ((void)0) -#define video_driver_context_unlock() ((void)0) -#endif - -typedef struct video_pixel_scaler -{ - struct scaler_ctx *scaler; - void *scaler_out; -} video_pixel_scaler_t; - -static bool (*video_driver_cb_shader_set_mvp)(void *data, - void *shader_data, const void *mat_data); -bool (*video_driver_cb_has_focus)(void); - -/* Opaque handles to currently running window. - * Used by e.g. input drivers which bind to a window. - * Drivers are responsible for setting these if an input driver - * could potentially make use of this. */ -static uintptr_t video_driver_display = 0; -static uintptr_t video_driver_window = 0; - -static rarch_softfilter_t *video_driver_state_filter = NULL; -static void *video_driver_state_buffer = NULL; -static unsigned video_driver_state_scale = 0; -static unsigned video_driver_state_out_bpp = 0; -static bool video_driver_state_out_rgb32 = false; -static bool video_driver_crt_switching_active = false; - -static struct retro_system_av_info video_driver_av_info; - -static enum retro_pixel_format video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555; - -static const void *frame_cache_data = NULL; -static unsigned frame_cache_width = 0; -static unsigned frame_cache_height = 0; -static size_t frame_cache_pitch = 0; -static bool video_driver_threaded = false; - -static float video_driver_core_hz = 0.0f; -static float video_driver_aspect_ratio = 0.0f; -static unsigned video_driver_width = 0; -static unsigned video_driver_height = 0; - -static enum rarch_display_type video_driver_display_type = RARCH_DISPLAY_NONE; -static char video_driver_title_buf[64] = {0}; -static char video_driver_window_title[512] = {0}; -static bool video_driver_window_title_update = true; - -static retro_time_t video_driver_frame_time_samples[MEASURE_FRAME_TIME_SAMPLES_COUNT]; -static uint64_t video_driver_frame_time_count = 0; -static uint64_t video_driver_frame_count = 0; - -static void *video_driver_data = NULL; -static video_driver_t *current_video = NULL; - -/* Interface for "poking". */ -static const video_poke_interface_t *video_driver_poke = NULL; - -/* Used for 15-bit -> 16-bit conversions that take place before - * being passed to video driver. */ -static video_pixel_scaler_t *video_driver_scaler_ptr = NULL; - -static struct retro_hw_render_callback hw_render; - -static const struct -retro_hw_render_context_negotiation_interface * -hw_render_context_negotiation = NULL; - -/* Graphics driver requires RGBA byte order data (ABGR on little-endian) - * for 32-bit. - * This takes effect for overlay and shader cores that wants to load - * data into graphics driver. Kinda hackish to place it here, it is only - * used for GLES. - * TODO: Refactor this better. */ -static bool video_driver_use_rgba = false; -static bool video_driver_data_own = false; -static bool video_driver_active = false; - -static video_driver_frame_t frame_bak = NULL; - -/* If set during context deinit, the driver should keep - * graphics context alive to avoid having to reset all - * context state. */ -static bool video_driver_cache_context = false; - -/* Set to true by driver if context caching succeeded. */ -static bool video_driver_cache_context_ack = false; -static uint8_t *video_driver_record_gpu_buffer = NULL; - -#ifdef HAVE_THREADS -static slock_t *display_lock = NULL; -static slock_t *context_lock = NULL; -#endif - -static gfx_ctx_driver_t current_video_context; - -static void *video_context_data = NULL; - -/** - * dynamic.c:dynamic_request_hw_context will try to set flag data when the context - * is in the middle of being rebuilt; in these cases we will save flag - * data and set this to true. - * When the context is reinit, it checks this, reads from - * deferred_flag_data and cleans it. - * - * TODO - Dirty hack, fix it better - */ -static bool deferred_video_context_driver_set_flags = false; -static gfx_ctx_flags_t deferred_flag_data = {0}; - -static bool video_started_fullscreen = false; - -static shader_backend_t *current_shader = NULL; -static void *current_shader_data = NULL; - -struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { - { "4:3", 1.3333f }, - { "16:9", 1.7778f }, - { "16:10", 1.6f }, - { "16:15", 16.0f / 15.0f }, - { "21:9", 21.0f / 9.0f }, - { "1:1", 1.0f }, - { "2:1", 2.0f }, - { "3:2", 1.5f }, - { "3:4", 0.75f }, - { "4:1", 4.0f }, - { "9:16", 0.5625f }, - { "5:4", 1.25f }, - { "6:5", 1.2f }, - { "7:9", 0.7777f }, - { "8:3", 2.6666f }, - { "8:7", 1.1428f }, - { "19:12", 1.5833f }, - { "19:14", 1.3571f }, - { "30:17", 1.7647f }, - { "32:9", 3.5555f }, - { "Config", 0.0f }, - { "Square pixel", 1.0f }, - { "Core provided", 1.0f }, - { "Custom", 0.0f } -}; - -static const video_driver_t *video_drivers[] = { -#ifdef HAVE_OPENGL - &video_gl, -#endif -#ifdef HAVE_VULKAN - &video_vulkan, -#endif -#ifdef HAVE_METAL - &video_metal, -#endif -#ifdef XENON - &video_xenon360, -#endif -#if defined(HAVE_D3D12) - &video_d3d12, -#endif -#if defined(HAVE_D3D11) - &video_d3d11, -#endif -#if defined(HAVE_D3D10) - &video_d3d10, -#endif -#if defined(HAVE_D3D9) - &video_d3d9, -#endif -#if defined(HAVE_D3D8) - &video_d3d8, -#endif -#ifdef HAVE_VITA2D - &video_vita2d, -#endif -#ifdef PSP - &video_psp1, -#endif -#ifdef PS2 - &video_ps2, -#endif -#ifdef _3DS - &video_ctr, -#endif -#ifdef SWITCH - &video_switch, -#endif -#ifdef HAVE_SDL - &video_sdl, -#endif -#ifdef HAVE_SDL2 - &video_sdl2, -#endif -#ifdef HAVE_XVIDEO - &video_xvideo, -#endif -#ifdef GEKKO - &video_gx, -#endif -#ifdef WIIU - &video_wiiu, -#endif -#ifdef HAVE_VG - &video_vg, -#endif -#ifdef HAVE_OMAP - &video_omap, -#endif -#ifdef HAVE_EXYNOS - &video_exynos, -#endif -#ifdef HAVE_DISPMANX - &video_dispmanx, -#endif -#ifdef HAVE_SUNXI - &video_sunxi, -#endif -#ifdef HAVE_PLAIN_DRM - &video_drm, -#endif -#ifdef HAVE_XSHM - &video_xshm, -#endif -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) - &video_gdi, -#endif -#ifdef DJGPP - &video_vga, -#endif -#ifdef HAVE_SIXEL - &video_sixel, -#endif -#ifdef HAVE_CACA - &video_caca, -#endif - &video_null, - NULL, -}; - -static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { -#if defined(ORBIS) - &orbis_ctx, -#endif -#if defined(HAVE_LIBNX) && defined(HAVE_OPENGL) - &switch_ctx, -#endif -#if defined(__CELLOS_LV2__) - &gfx_ctx_ps3, -#endif -#if defined(HAVE_VIDEOCORE) - &gfx_ctx_videocore, -#endif -#if defined(HAVE_MALI_FBDEV) - &gfx_ctx_mali_fbdev, -#endif -#if defined(HAVE_VIVANTE_FBDEV) - &gfx_ctx_vivante_fbdev, -#endif -#if defined(HAVE_OPENDINGUX_FBDEV) - &gfx_ctx_opendingux_fbdev, -#endif -#if defined(_WIN32) && (defined(HAVE_OPENGL) || defined(HAVE_VULKAN)) - &gfx_ctx_wgl, -#endif -#if defined(HAVE_WAYLAND) - &gfx_ctx_wayland, -#endif -#if defined(HAVE_X11) && !defined(HAVE_OPENGLES) -#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) - &gfx_ctx_x, -#endif -#endif -#if defined(HAVE_X11) && defined(HAVE_OPENGL) && defined(HAVE_EGL) - &gfx_ctx_x_egl, -#endif -#if defined(HAVE_KMS) - &gfx_ctx_drm, -#endif -#if defined(ANDROID) - &gfx_ctx_android, -#endif -#if defined(__QNX__) - &gfx_ctx_qnx, -#endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) - &gfx_ctx_cocoagl, -#endif -#if defined(__APPLE__) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE) - &gfx_ctx_cgl, -#endif -#if (defined(HAVE_SDL) || defined(HAVE_SDL2)) && defined(HAVE_OPENGL) - &gfx_ctx_sdl_gl, -#endif -#ifdef HAVE_OSMESA - &gfx_ctx_osmesa, -#endif -#ifdef EMSCRIPTEN - &gfx_ctx_emscripten, -#endif -#if defined(HAVE_VULKAN) && defined(HAVE_VULKAN_DISPLAY) - &gfx_ctx_khr_display, -#endif -#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) - &gfx_ctx_gdi, -#endif -#ifdef HAVE_SIXEL - &gfx_ctx_sixel, -#endif - &gfx_ctx_null, - NULL -}; - -static const shader_backend_t *shader_ctx_drivers[] = { -#ifdef HAVE_GLSL - &gl_glsl_backend, -#endif -#ifdef HAVE_CG - &gl_cg_backend, -#endif - &shader_null_backend, - NULL -}; - -bool video_driver_started_fullscreen(void) -{ - return video_started_fullscreen; -} - -/* Stub functions */ - -static void update_window_title_null(void *data, void *data2) -{ -} - -static void swap_buffers_null(void *data, void *data2) -{ -} - -static bool get_metrics_null(void *data, enum display_metric_types type, - float *value) -{ - return false; -} - -static bool set_resize_null(void *a, unsigned b, unsigned c) -{ - return false; -} - -/** - * video_driver_find_handle: - * @idx : index of driver to get handle to. - * - * Returns: handle to video driver at index. Can be NULL - * if nothing found. - **/ -const void *video_driver_find_handle(int idx) -{ - const void *drv = video_drivers[idx]; - if (!drv) - return NULL; - return drv; -} - -/** - * video_driver_find_ident: - * @idx : index of driver to get handle to. - * - * Returns: Human-readable identifier of video driver at index. Can be NULL - * if nothing found. - **/ -const char *video_driver_find_ident(int idx) -{ - const video_driver_t *drv = video_drivers[idx]; - if (!drv) - return NULL; - return drv->ident; -} - -/** - * config_get_video_driver_options: - * - * Get an enumerated list of all video driver names, separated by '|'. - * - * Returns: string listing of all video driver names, separated by '|'. - **/ -const char* config_get_video_driver_options(void) -{ - return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL); -} - -bool video_driver_is_threaded(void) -{ - return video_driver_is_threaded_internal(); -} - -#ifdef HAVE_VULKAN -static bool hw_render_context_is_vulkan(enum retro_hw_context_type type) -{ - return type == RETRO_HW_CONTEXT_VULKAN; -} -#endif - -#if defined(HAVE_OPENGL) -static bool hw_render_context_is_gl(enum retro_hw_context_type type) -{ - switch (type) - { - case RETRO_HW_CONTEXT_OPENGL: - case RETRO_HW_CONTEXT_OPENGLES2: - case RETRO_HW_CONTEXT_OPENGL_CORE: - case RETRO_HW_CONTEXT_OPENGLES3: - case RETRO_HW_CONTEXT_OPENGLES_VERSION: - return true; - default: - break; - } - - return false; -} -#endif - -bool *video_driver_get_threaded(void) -{ - return &video_driver_threaded; -} - -void video_driver_set_threaded(bool val) -{ - video_driver_threaded = val; -} - -/** - * video_driver_get_ptr: - * - * Use this if you need the real video driver - * and driver data pointers. - * - * Returns: video driver's userdata. - **/ -void *video_driver_get_ptr(bool force_nonthreaded_data) -{ -#ifdef HAVE_THREADS - if (video_driver_is_threaded_internal() && !force_nonthreaded_data) - return video_thread_get_ptr(NULL); -#endif - - return video_driver_data; -} - -const char *video_driver_get_ident(void) -{ - return (current_video) ? current_video->ident : NULL; -} - -const video_poke_interface_t *video_driver_get_poke(void) -{ - return video_driver_poke; -} - -static bool video_context_has_focus(void) -{ - return current_video_context.has_focus && current_video_context.has_focus(video_context_data); -} - -static bool video_driver_has_focus(void) -{ - return current_video && current_video->focus && current_video->focus(video_driver_data); -} - -static bool null_driver_has_focus(void) -{ - return true; -} - -static void video_context_driver_reset(void) -{ - if (!current_video_context.get_metrics) - current_video_context.get_metrics = get_metrics_null; - - if (!current_video_context.update_window_title) - current_video_context.update_window_title = update_window_title_null; - - if (!current_video_context.set_resize) - current_video_context.set_resize = set_resize_null; - - if (!current_video_context.swap_buffers) - current_video_context.swap_buffers = swap_buffers_null; - - if (current_video_context.has_focus) - video_driver_cb_has_focus = video_context_has_focus; - -} - -bool video_context_driver_set(const gfx_ctx_driver_t *data) -{ - if (!data) - return false; - current_video_context = *data; - video_context_driver_reset(); - return true; -} - -void video_context_driver_destroy(void) -{ - current_video_context.init = NULL; - current_video_context.bind_api = NULL; - current_video_context.swap_interval = NULL; - current_video_context.set_video_mode = NULL; - current_video_context.get_video_size = NULL; - current_video_context.get_video_output_size = NULL; - current_video_context.get_video_output_prev = NULL; - current_video_context.get_video_output_next = NULL; - current_video_context.get_metrics = get_metrics_null; - current_video_context.translate_aspect = NULL; - current_video_context.update_window_title = update_window_title_null; - current_video_context.check_window = NULL; - current_video_context.set_resize = set_resize_null; - current_video_context.has_focus = NULL; - current_video_context.suppress_screensaver = NULL; - current_video_context.has_windowed = NULL; - current_video_context.swap_buffers = swap_buffers_null; - current_video_context.input_driver = NULL; - current_video_context.get_proc_address = NULL; - current_video_context.image_buffer_init = NULL; - current_video_context.image_buffer_write = NULL; - current_video_context.show_mouse = NULL; - current_video_context.ident = NULL; - current_video_context.get_flags = NULL; - current_video_context.set_flags = NULL; - current_video_context.bind_hw_render = NULL; - current_video_context.get_context_data = NULL; - current_video_context.make_current = NULL; -} - -/** - * video_driver_get_current_framebuffer: - * - * Gets pointer to current hardware renderer framebuffer object. - * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. - * - * Returns: pointer to hardware framebuffer object, otherwise 0. - **/ -uintptr_t video_driver_get_current_framebuffer(void) -{ - if (video_driver_poke && video_driver_poke->get_current_framebuffer) - return video_driver_poke->get_current_framebuffer(video_driver_data); - return 0; -} - -retro_proc_address_t video_driver_get_proc_address(const char *sym) -{ - if (video_driver_poke && video_driver_poke->get_proc_address) - return video_driver_poke->get_proc_address(video_driver_data, sym); - return NULL; -} - -bool video_driver_set_shader(enum rarch_shader_type type, - const char *path) -{ - if (current_video->set_shader) - return current_video->set_shader(video_driver_data, type, path); - return false; -} - -static void video_driver_filter_free(void) -{ - if (video_driver_state_filter) - rarch_softfilter_free(video_driver_state_filter); - video_driver_state_filter = NULL; - - if (video_driver_state_buffer) - { -#ifdef _3DS - linearFree(video_driver_state_buffer); -#else - free(video_driver_state_buffer); -#endif - } - video_driver_state_buffer = NULL; - - video_driver_state_scale = 0; - video_driver_state_out_bpp = 0; - video_driver_state_out_rgb32 = false; -} - -static void video_driver_init_filter(enum retro_pixel_format colfmt_int) -{ - unsigned pow2_x, pow2_y, maxsize; - void *buf = NULL; - settings_t *settings = config_get_ptr(); - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - unsigned width = geom->max_width; - unsigned height = geom->max_height; - /* Deprecated format. Gets pre-converted. */ - enum retro_pixel_format colfmt = - (colfmt_int == RETRO_PIXEL_FORMAT_0RGB1555) ? - RETRO_PIXEL_FORMAT_RGB565 : colfmt_int; - - if (video_driver_is_hw_context()) - { - RARCH_WARN("Cannot use CPU filters when hardware rendering is used.\n"); - return; - } - - video_driver_state_filter = rarch_softfilter_new( - settings->paths.path_softfilter_plugin, - RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height); - - if (!video_driver_state_filter) - { - RARCH_ERR("[Video]: Failed to load filter.\n"); - return; - } - - rarch_softfilter_get_max_output_size(video_driver_state_filter, - &width, &height); - - pow2_x = next_pow2(width); - pow2_y = next_pow2(height); - maxsize = MAX(pow2_x, pow2_y); - video_driver_state_scale = maxsize / RARCH_SCALE_BASE; - video_driver_state_out_rgb32 = rarch_softfilter_get_output_format( - video_driver_state_filter) == - RETRO_PIXEL_FORMAT_XRGB8888; - - video_driver_state_out_bpp = video_driver_state_out_rgb32 ? - sizeof(uint32_t) : - sizeof(uint16_t); - - /* TODO: Aligned output. */ -#ifdef _3DS - buf = linearMemAlign( - width * height * video_driver_state_out_bpp, 0x80); -#else - buf = malloc( - width * height * video_driver_state_out_bpp); -#endif - if (!buf) - { - RARCH_ERR("[Video]: Softfilter initialization failed.\n"); - video_driver_filter_free(); - return; - } - - video_driver_state_buffer = buf; -} - -static void video_driver_init_input(const input_driver_t *tmp) -{ - const input_driver_t **input = input_get_double_ptr(); - if (*input) - return; - - /* Video driver didn't provide an input driver, - * so we use configured one. */ - RARCH_LOG("[Video]: Graphics driver did not initialize an input driver." - " Attempting to pick a suitable driver.\n"); - - if (tmp) - *input = tmp; - else - input_driver_find_driver(); - - /* This should never really happen as tmp (driver.input) is always - * found before this in find_driver_input(), or we have aborted - * in a similar fashion anyways. */ - if (!input_get_ptr()) - goto error; - - if (input_driver_init()) - return; - -error: - RARCH_ERR("[Video]: Cannot initialize input driver. Exiting ...\n"); - retroarch_fail(1, "video_driver_init_input()"); -} - -/** - * video_driver_monitor_compute_fps_statistics: - * - * Computes monitor FPS statistics. - **/ -static void video_driver_monitor_compute_fps_statistics(void) -{ - double avg_fps = 0.0; - double stddev = 0.0; - unsigned samples = 0; - - if (video_driver_frame_time_count < - (2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)) - { - RARCH_LOG( - "[Video]: Does not have enough samples for monitor refresh rate" - " estimation. Requires to run for at least %u frames.\n", - 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT); - return; - } - - if (video_monitor_fps_statistics(&avg_fps, &stddev, &samples)) - { - RARCH_LOG("[Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time" - " deviation, based on %u last samples).\n", - avg_fps, 100.0 * stddev, samples); - } -} - -static void video_driver_pixel_converter_free(void) -{ - if (!video_driver_scaler_ptr) - return; - - scaler_ctx_gen_reset(video_driver_scaler_ptr->scaler); - - if (video_driver_scaler_ptr->scaler) - free(video_driver_scaler_ptr->scaler); - video_driver_scaler_ptr->scaler = NULL; - - if (video_driver_scaler_ptr->scaler_out) - free(video_driver_scaler_ptr->scaler_out); - video_driver_scaler_ptr->scaler_out = NULL; - - if (video_driver_scaler_ptr) - free(video_driver_scaler_ptr); - video_driver_scaler_ptr = NULL; -} - -static void video_driver_free_internal(void) -{ -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); -#endif - - command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); - - if (!video_driver_is_video_cache_context()) - video_driver_free_hw_context(); - - if ( - !input_driver_owns_driver() && - !input_driver_is_data_ptr_same(video_driver_data) - ) - input_driver_deinit(); - - if ( - !video_driver_data_own - && video_driver_data - && current_video && current_video->free - ) - current_video->free(video_driver_data); - - video_driver_pixel_converter_free(); - video_driver_filter_free(); - - command_event(CMD_EVENT_SHADER_DIR_DEINIT, NULL); - -#ifdef HAVE_THREADS - if (is_threaded) - return; -#endif - - video_driver_monitor_compute_fps_statistics(); -} - -static bool video_driver_pixel_converter_init(unsigned size) -{ - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); - void *scalr_out = NULL; - video_pixel_scaler_t *scalr = NULL; - struct scaler_ctx *scalr_ctx = NULL; - - /* If pixel format is not 0RGB1555, we don't need to do - * any internal pixel conversion. */ - if (video_driver_pix_fmt != RETRO_PIXEL_FORMAT_0RGB1555) - return true; - - /* No need to perform pixel conversion for HW rendering contexts. */ - if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) - return true; - - RARCH_WARN("0RGB1555 pixel format is deprecated," - " and will be slower. For 15/16-bit, RGB565" - " format is preferred.\n"); - - scalr = (video_pixel_scaler_t*)calloc(1, sizeof(*scalr)); - - if (!scalr) - goto error; - - video_driver_scaler_ptr = scalr; - - scalr_ctx = (struct scaler_ctx*)calloc(1, sizeof(*scalr_ctx)); - - if (!scalr_ctx) - goto error; - - video_driver_scaler_ptr->scaler = scalr_ctx; - video_driver_scaler_ptr->scaler->scaler_type = SCALER_TYPE_POINT; - video_driver_scaler_ptr->scaler->in_fmt = SCALER_FMT_0RGB1555; - - /* TODO: Pick either ARGB8888 or RGB565 depending on driver. */ - video_driver_scaler_ptr->scaler->out_fmt = SCALER_FMT_RGB565; - - if (!scaler_ctx_gen_filter(scalr_ctx)) - goto error; - - scalr_out = calloc(sizeof(uint16_t), size * size); - - if (!scalr_out) - goto error; - - video_driver_scaler_ptr->scaler_out = scalr_out; - - return true; - -error: - video_driver_pixel_converter_free(); - video_driver_filter_free(); - - return false; -} - -static bool video_driver_init_internal(bool *video_is_threaded) -{ - video_info_t video; - unsigned max_dim, scale, width, height; - video_viewport_t *custom_vp = NULL; - const input_driver_t *tmp = NULL; - rarch_system_info_t *system = NULL; - static uint16_t dummy_pixels[32] = {0}; - settings_t *settings = config_get_ptr(); - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - - if (!string_is_empty(settings->paths.path_softfilter_plugin)) - video_driver_init_filter(video_driver_pix_fmt); - - max_dim = MAX(geom->max_width, geom->max_height); - scale = next_pow2(max_dim) / RARCH_SCALE_BASE; - scale = MAX(scale, 1); - - if (video_driver_state_filter) - scale = video_driver_state_scale; - - /* Update core-dependent aspect ratio values. */ - video_driver_set_viewport_square_pixel(); - video_driver_set_viewport_core(); - video_driver_set_viewport_config(); - - /* Update CUSTOM viewport. */ - custom_vp = video_viewport_get_custom(); - - if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) - { - float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; - aspectratio_lut[ASPECT_RATIO_CUSTOM].value = - (custom_vp->width && custom_vp->height) ? - (float)custom_vp->width / custom_vp->height : default_aspect; - } - - video_driver_set_aspect_ratio_value( - aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); - - if (settings->bools.video_fullscreen|| retroarch_is_forced_fullscreen()) - { - width = settings->uints.video_fullscreen_x; - height = settings->uints.video_fullscreen_y; - } - else - { - /* To-Do: remove when the new window resizing core is hooked */ - if (settings->bools.video_window_save_positions && - (settings->uints.window_position_width || settings->uints.window_position_height)) - { - width = settings->uints.window_position_width; - height = settings->uints.window_position_height; - } - else - { - if (settings->bools.video_force_aspect) - { - /* Do rounding here to simplify integer scale correctness. */ - unsigned base_width = - roundf(geom->base_height * video_driver_get_aspect_ratio()); - width = roundf(base_width * settings->floats.video_scale); - } - else - width = roundf(geom->base_width * settings->floats.video_scale); - height = roundf(geom->base_height * settings->floats.video_scale); -} - } - - if (width && height) - RARCH_LOG("[Video]: Video @ %ux%u\n", width, height); - else - RARCH_LOG("[Video]: Video @ fullscreen\n"); - - video_driver_display_type_set(RARCH_DISPLAY_NONE); - video_driver_display_set(0); - video_driver_window_set(0); - - if (!video_driver_pixel_converter_init(RARCH_SCALE_BASE * scale)) - { - RARCH_ERR("[Video]: Failed to initialize pixel converter.\n"); - goto error; - } - - video.width = width; - video.height = height; - video.fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); - video.vsync = settings->bools.video_vsync && !rarch_ctl(RARCH_CTL_IS_NONBLOCK_FORCED, NULL); - video.force_aspect = settings->bools.video_force_aspect; - video.font_enable = settings->bools.video_font_enable; - video.swap_interval = settings->uints.video_swap_interval; -#ifdef GEKKO - video.viwidth = settings->uints.video_viwidth; - video.vfilter = settings->bools.video_vfilter; -#endif - video.smooth = settings->bools.video_smooth; - video.input_scale = scale; - video.rgb32 = video_driver_state_filter ? - video_driver_state_out_rgb32 : - (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); - video.parent = 0; - - video_started_fullscreen = video.fullscreen; - - /* Reset video frame count */ - video_driver_frame_count = 0; - - tmp = input_get_ptr(); - /* Need to grab the "real" video driver interface on a reinit. */ - video_driver_find_driver(); - -#ifdef HAVE_THREADS - video.is_threaded = video_driver_is_threaded_internal(); - *video_is_threaded = video.is_threaded; - - if (video.is_threaded) - { - /* Can't do hardware rendering with threaded driver currently. */ - RARCH_LOG("[Video]: Starting threaded video driver ...\n"); - - if (!video_init_thread((const video_driver_t**)¤t_video, - &video_driver_data, - input_get_double_ptr(), input_driver_get_data_ptr(), - current_video, video)) - { - RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n"); - goto error; - } - } - else -#endif - video_driver_data = current_video->init( - &video, input_get_double_ptr(), - input_driver_get_data_ptr()); - - if (!video_driver_data) - { - RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n"); - goto error; - } - - if (current_video->focus) - video_driver_cb_has_focus = video_driver_has_focus; - - video_driver_poke = NULL; - if (current_video->poke_interface) - current_video->poke_interface(video_driver_data, &video_driver_poke); - - if (current_video->viewport_info && - (!custom_vp->width || - !custom_vp->height)) - { - /* Force custom viewport to have sane parameters. */ - custom_vp->width = width; - custom_vp->height = height; - - video_driver_get_viewport_info(custom_vp); - } - - system = runloop_get_system_info(); - - video_driver_set_rotation( - (settings->uints.video_rotation + system->rotation) % 4); - - current_video->suppress_screensaver(video_driver_data, - settings->bools.ui_suspend_screensaver_enable); - - video_driver_init_input(tmp); - - command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); - command_event(CMD_EVENT_OVERLAY_INIT, NULL); - - if (!core_is_game_loaded()) - video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8); - -#if defined(PSP) - video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f); -#endif - - video_context_driver_reset(); - - video_display_server_init(); - - command_event(CMD_EVENT_SHADER_DIR_INIT, NULL); - - return true; - -error: - retroarch_fail(1, "init_video()"); - return false; -} - -bool video_driver_set_viewport(unsigned width, unsigned height, - bool force_fullscreen, bool allow_rotate) -{ - if (!current_video || !current_video->set_viewport) - return false; - current_video->set_viewport(video_driver_data, width, height, - force_fullscreen, allow_rotate); - return true; -} - -bool video_driver_set_rotation(unsigned rotation) -{ - if (!current_video || !current_video->set_rotation) - return false; - current_video->set_rotation(video_driver_data, rotation); - return true; -} - -bool video_driver_set_video_mode(unsigned width, - unsigned height, bool fullscreen) -{ - gfx_ctx_mode_t mode; - - if (video_driver_poke && video_driver_poke->set_video_mode) - { - video_driver_poke->set_video_mode(video_driver_data, - width, height, fullscreen); - return true; - } - - mode.width = width; - mode.height = height; - mode.fullscreen = fullscreen; - - return video_context_driver_set_video_mode(&mode); -} - -bool video_driver_get_video_output_size(unsigned *width, unsigned *height) -{ - if (!video_driver_poke || !video_driver_poke->get_video_output_size) - return false; - video_driver_poke->get_video_output_size(video_driver_data, - width, height); - return true; -} - -void video_driver_set_osd_msg(const char *msg, const void *data, void *font) -{ - video_frame_info_t video_info; - video_driver_build_info(&video_info); - if (video_driver_poke && video_driver_poke->set_osd_msg) - video_driver_poke->set_osd_msg(video_driver_data, &video_info, msg, data, font); -} - -void video_driver_set_texture_enable(bool enable, bool fullscreen) -{ - if (video_driver_poke && video_driver_poke->set_texture_enable) - video_driver_poke->set_texture_enable(video_driver_data, - enable, fullscreen); -} - -void video_driver_set_texture_frame(const void *frame, bool rgb32, - unsigned width, unsigned height, float alpha) -{ - if (video_driver_poke && video_driver_poke->set_texture_frame) - video_driver_poke->set_texture_frame(video_driver_data, - frame, rgb32, width, height, alpha); -} - -#ifdef HAVE_OVERLAY -bool video_driver_overlay_interface(const video_overlay_interface_t **iface) -{ - if (!current_video || !current_video->overlay_interface) - return false; - current_video->overlay_interface(video_driver_data, iface); - return true; -} -#endif - -void *video_driver_read_frame_raw(unsigned *width, - unsigned *height, size_t *pitch) -{ - if (!current_video || !current_video->read_frame_raw) - return NULL; - return current_video->read_frame_raw(video_driver_data, width, - height, pitch); -} - -void video_driver_set_filtering(unsigned index, bool smooth) -{ - if (video_driver_poke && video_driver_poke->set_filtering) - video_driver_poke->set_filtering(video_driver_data, index, smooth); -} - -void video_driver_cached_frame_set(const void *data, unsigned width, - unsigned height, size_t pitch) -{ - if (data) - frame_cache_data = data; - frame_cache_width = width; - frame_cache_height = height; - frame_cache_pitch = pitch; -} - -void video_driver_cached_frame_get(const void **data, unsigned *width, - unsigned *height, size_t *pitch) -{ - if (data) - *data = frame_cache_data; - if (width) - *width = frame_cache_width; - if (height) - *height = frame_cache_height; - if (pitch) - *pitch = frame_cache_pitch; -} - -void video_driver_get_size(unsigned *width, unsigned *height) -{ -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); - video_driver_threaded_lock(is_threaded); -#endif - if (width) - *width = video_driver_width; - if (height) - *height = video_driver_height; -#ifdef HAVE_THREADS - video_driver_threaded_unlock(is_threaded); -#endif -} - -void video_driver_set_size(unsigned *width, unsigned *height) -{ -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); - video_driver_threaded_lock(is_threaded); -#endif - if (width) - video_driver_width = *width; - if (height) - video_driver_height = *height; -#ifdef HAVE_THREADS - video_driver_threaded_unlock(is_threaded); -#endif -} - -/** - * video_monitor_set_refresh_rate: - * @hz : New refresh rate for monitor. - * - * Sets monitor refresh rate to new value. - **/ -void video_monitor_set_refresh_rate(float hz) -{ - char msg[128]; - settings_t *settings = config_get_ptr(); - - snprintf(msg, sizeof(msg), - "Setting refresh rate to: %.3f Hz.", hz); - runloop_msg_queue_push(msg, 1, 180, false); - RARCH_LOG("%s\n", msg); - - configuration_set_float(settings, - settings->floats.video_refresh_rate, - hz); -} - -/** - * video_monitor_fps_statistics - * @refresh_rate : Monitor refresh rate. - * @deviation : Deviation from measured refresh rate. - * @sample_points : Amount of sampled points. - * - * Gets the monitor FPS statistics based on the current - * runtime. - * - * Returns: true (1) on success. - * false (0) if: - * a) threaded video mode is enabled - * b) less than 2 frame time samples. - * c) FPS monitor enable is off. - **/ -bool video_monitor_fps_statistics(double *refresh_rate, - double *deviation, unsigned *sample_points) -{ - unsigned i; - retro_time_t accum = 0; - retro_time_t avg = 0; - retro_time_t accum_var = 0; - unsigned samples = 0; - -#ifdef HAVE_THREADS - if (video_driver_is_threaded_internal()) - return false; -#endif - - samples = MIN(MEASURE_FRAME_TIME_SAMPLES_COUNT, - (unsigned)video_driver_frame_time_count); - - if (samples < 2) - return false; - - /* Measure statistics on frame time (microsecs), *not* FPS. */ - for (i = 0; i < samples; i++) - { - accum += video_driver_frame_time_samples[i]; -#if 0 - RARCH_LOG("[Video]: Interval #%u: %d usec / frame.\n", - i, (int)frame_time_samples[i]); -#endif - } - - avg = accum / samples; - - /* Drop first measurement. It is likely to be bad. */ - for (i = 0; i < samples; i++) - { - retro_time_t diff = video_driver_frame_time_samples[i] - avg; - accum_var += diff * diff; - } - - *deviation = sqrt((double)accum_var / (samples - 1)) / avg; - - if (refresh_rate) - *refresh_rate = 1000000.0 / avg; - - if (sample_points) - *sample_points = samples; - - return true; -} - -float video_driver_get_aspect_ratio(void) -{ - return video_driver_aspect_ratio; -} - -void video_driver_set_aspect_ratio_value(float value) -{ - video_driver_aspect_ratio = value; -} - -static bool video_driver_frame_filter( - const void *data, - video_frame_info_t *video_info, - unsigned width, unsigned height, - size_t pitch, - unsigned *output_width, unsigned *output_height, - unsigned *output_pitch) -{ - rarch_softfilter_get_output_size(video_driver_state_filter, - output_width, output_height, width, height); - - *output_pitch = (*output_width) * video_driver_state_out_bpp; - - rarch_softfilter_process(video_driver_state_filter, - video_driver_state_buffer, *output_pitch, - data, width, height, pitch); - - if (video_info->post_filter_record && recording_data) - recording_dump_frame(video_driver_state_buffer, - *output_width, *output_height, *output_pitch, - video_info->runloop_is_idle); - - return true; -} - -rarch_softfilter_t *video_driver_frame_filter_get_ptr(void) -{ - return video_driver_state_filter; -} - -enum retro_pixel_format video_driver_get_pixel_format(void) -{ - return video_driver_pix_fmt; -} - -void video_driver_set_pixel_format(enum retro_pixel_format fmt) -{ - video_driver_pix_fmt = fmt; -} - -/** - * video_driver_cached_frame: - * - * Renders the current video frame. - **/ -bool video_driver_cached_frame(void) -{ - void *recording = recording_driver_get_data_ptr(); - - recording_driver_lock(); - - /* Cannot allow recording when pushing duped frames. */ - recording_data = NULL; - - retro_ctx.frame_cb( - (frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID) - ? frame_cache_data : NULL, - frame_cache_width, - frame_cache_height, frame_cache_pitch); - - recording_data = recording; - - recording_driver_unlock(); - - return true; -} - -void video_driver_monitor_adjust_system_rates(void) -{ - float timing_skew = 0.0f; - settings_t *settings = config_get_ptr(); - float video_refresh_rate = settings->floats.video_refresh_rate; - float timing_skew_hz = video_refresh_rate; - const struct retro_system_timing *info = (const struct retro_system_timing*)&video_driver_av_info.timing; - - rarch_ctl(RARCH_CTL_UNSET_NONBLOCK_FORCED, NULL); - - if (!info || info->fps <= 0.0) - return; - - video_driver_core_hz = info->fps; - - if (video_driver_crt_switching_active) - timing_skew_hz = video_driver_core_hz; - timing_skew = fabs( - 1.0f - info->fps / timing_skew_hz); - - if (!settings->bools.vrr_runloop_enable) - { - /* We don't want to adjust pitch too much. If we have extreme cases, - * just don't readjust at all. */ - if (timing_skew <= settings->floats.audio_max_timing_skew) - return; - - RARCH_LOG("[Video]: Timings deviate too much. Will not adjust." - " (Display = %.2f Hz, Game = %.2f Hz)\n", - video_refresh_rate, - (float)info->fps); - } - - if (info->fps <= timing_skew_hz) - return; - - /* We won't be able to do VSync reliably when game FPS > monitor FPS. */ - rarch_ctl(RARCH_CTL_SET_NONBLOCK_FORCED, NULL); - RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n"); -} - -void video_driver_menu_settings(void **list_data, void *list_info_data, - void *group_data, void *subgroup_data, const char *parent_group) -{ -#ifdef HAVE_MENU - rarch_setting_t **list = (rarch_setting_t**)list_data; - rarch_setting_info_t *list_info = (rarch_setting_info_t*)list_info_data; - rarch_setting_group_info_t *group_info = (rarch_setting_group_info_t*)group_data; - rarch_setting_group_info_t *subgroup_info = (rarch_setting_group_info_t*)subgroup_data; - global_t *global = global_get_ptr(); - - (void)list; - (void)list_info; - (void)group_info; - (void)subgroup_info; - (void)global; - -#if defined(__CELLOS_LV2__) - CONFIG_BOOL( - list, list_info, - &global->console.screen.pal60_enable, - MENU_ENUM_LABEL_PAL60_ENABLE, - MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, - false, - MENU_ENUM_LABEL_VALUE_OFF, - MENU_ENUM_LABEL_VALUE_ON, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler, - SD_FLAG_NONE); -#endif -#if defined(GEKKO) || defined(_XBOX360) - CONFIG_UINT( - list, list_info, - &global->console.screen.gamma_correction, - MENU_ENUM_LABEL_VIDEO_GAMMA, - MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - 0, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - menu_settings_list_current_add_cmd( - list, - list_info, - CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); - menu_settings_list_current_add_range( - list, - list_info, - 0, - MAX_GAMMA_SETTING, - 1, - true, - true); - settings_data_list_current_add_flags(list, list_info, - SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); -#endif -#if defined(_XBOX1) || defined(HW_RVL) - CONFIG_BOOL( - list, list_info, - &global->console.softfilter_enable, - MENU_ENUM_LABEL_VIDEO_SOFT_FILTER, - MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - false, - MENU_ENUM_LABEL_VALUE_OFF, - MENU_ENUM_LABEL_VALUE_ON, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler, - SD_FLAG_NONE); - menu_settings_list_current_add_cmd( - list, - list_info, - CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); -#endif -#ifdef _XBOX1 - CONFIG_UINT( - list, list_info, - &global->console.screen.flicker_filter_index, - MENU_ENUM_LABEL_VIDEO_FILTER_FLICKER, - MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - 0, - group_info, - subgroup_info, - parent_group, - general_write_handler, - general_read_handler); - menu_settings_list_current_add_range(list, list_info, - 0, 5, 1, true, true); -#endif -#endif -} - -static void video_driver_lock_new(void) -{ - video_driver_lock_free(); -#ifdef HAVE_THREADS - if (!display_lock) - display_lock = slock_new(); - retro_assert(display_lock); - - if (!context_lock) - context_lock = slock_new(); - retro_assert(context_lock); -#endif -} - -void video_driver_destroy(void) -{ - video_display_server_destroy(); - crt_video_restore(); - - video_driver_cb_has_focus = null_driver_has_focus; - video_driver_use_rgba = false; - video_driver_data_own = false; - video_driver_active = false; - video_driver_cache_context = false; - video_driver_cache_context_ack = false; - video_driver_record_gpu_buffer = NULL; - current_video = NULL; - video_driver_set_cached_frame_ptr(NULL); -} - -void video_driver_set_cached_frame_ptr(const void *data) -{ - if (data) - frame_cache_data = data; -} - -void video_driver_set_stub_frame(void) -{ - frame_bak = current_video->frame; - current_video->frame = video_null.frame; -} - -void video_driver_unset_stub_frame(void) -{ - if (frame_bak != NULL) - current_video->frame = frame_bak; - - frame_bak = NULL; -} - -bool video_driver_is_stub_frame(void) -{ - return current_video->frame == video_null.frame; -} - -bool video_driver_supports_recording(void) -{ - settings_t *settings = config_get_ptr(); - return settings->bools.video_gpu_record - && current_video->read_viewport; -} - -bool video_driver_supports_viewport_read(void) -{ - settings_t *settings = config_get_ptr(); - return (settings->bools.video_gpu_screenshot || - (video_driver_is_hw_context() && !current_video->read_frame_raw)) - && current_video->read_viewport && current_video->viewport_info; -} - -bool video_driver_supports_read_frame_raw(void) -{ - if (current_video->read_frame_raw) - return true; - return false; -} - -void video_driver_set_viewport_config(void) -{ - settings_t *settings = config_get_ptr(); - - if (settings->floats.video_aspect_ratio < 0.0f) - { - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - - if (geom->aspect_ratio > 0.0f && - settings->bools.video_aspect_ratio_auto) - aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio; - else - { - unsigned base_width = geom->base_width; - unsigned base_height = geom->base_height; - - /* Get around division by zero errors */ - if (base_width == 0) - base_width = 1; - if (base_height == 0) - base_height = 1; - aspectratio_lut[ASPECT_RATIO_CONFIG].value = - (float)base_width / base_height; /* 1:1 PAR. */ - } - } - else - { - aspectratio_lut[ASPECT_RATIO_CONFIG].value = - settings->floats.video_aspect_ratio; - } -} - -void video_driver_set_viewport_square_pixel(void) -{ - unsigned len, highest, i, aspect_x, aspect_y; - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - unsigned width = geom->base_width; - unsigned height = geom->base_height; - - if (width == 0 || height == 0) - return; - - len = MIN(width, height); - highest = 1; - - for (i = 1; i < len; i++) - { - if ((width % i) == 0 && (height % i) == 0) - highest = i; - } - - aspect_x = width / highest; - aspect_y = height / highest; - - snprintf(aspectratio_lut[ASPECT_RATIO_SQUARE].name, - sizeof(aspectratio_lut[ASPECT_RATIO_SQUARE].name), - "1:1 PAR (%u:%u DAR)", aspect_x, aspect_y); - - aspectratio_lut[ASPECT_RATIO_SQUARE].value = (float)aspect_x / aspect_y; -} - -void video_driver_set_viewport_core(void) -{ - struct retro_game_geometry *geom = &video_driver_av_info.geometry; - - if (!geom || geom->base_width <= 0.0f || geom->base_height <= 0.0f) - return; - - /* Fallback to 1:1 pixel ratio if none provided */ - if (geom->aspect_ratio > 0.0f) - aspectratio_lut[ASPECT_RATIO_CORE].value = geom->aspect_ratio; - else - aspectratio_lut[ASPECT_RATIO_CORE].value = - (float)geom->base_width / geom->base_height; -} - -void video_driver_reset_custom_viewport(void) -{ - struct video_viewport *custom_vp = video_viewport_get_custom(); - - custom_vp->width = 0; - custom_vp->height = 0; - custom_vp->x = 0; - custom_vp->y = 0; -} - -void video_driver_set_rgba(void) -{ - video_driver_lock(); - video_driver_use_rgba = true; - video_driver_unlock(); -} - -void video_driver_unset_rgba(void) -{ - video_driver_lock(); - video_driver_use_rgba = false; - video_driver_unlock(); -} - -bool video_driver_supports_rgba(void) -{ - bool tmp; - video_driver_lock(); - tmp = video_driver_use_rgba; - video_driver_unlock(); - return tmp; -} - -bool video_driver_get_next_video_out(void) -{ - if (!video_driver_poke) - return false; - - if (!video_driver_poke->get_video_output_next) - return video_context_driver_get_video_output_next(); - video_driver_poke->get_video_output_next(video_driver_data); - return true; -} - -bool video_driver_get_prev_video_out(void) -{ - if (!video_driver_poke) - return false; - - if (!video_driver_poke->get_video_output_prev) - return video_context_driver_get_video_output_prev(); - video_driver_poke->get_video_output_prev(video_driver_data); - return true; -} - -bool video_driver_init(bool *video_is_threaded) -{ - video_driver_lock_new(); - video_driver_filter_free(); - video_driver_set_cached_frame_ptr(NULL); - return video_driver_init_internal(video_is_threaded); -} - -void video_driver_destroy_data(void) -{ - video_driver_data = NULL; -} - -void video_driver_free(void) -{ - video_driver_free_internal(); - video_driver_lock_free(); - video_driver_data = NULL; - video_driver_set_cached_frame_ptr(NULL); -} - -void video_driver_monitor_reset(void) -{ - video_driver_frame_time_count = 0; -} - -void video_driver_set_aspect_ratio(void) -{ - settings_t *settings = config_get_ptr(); - - switch (settings->uints.video_aspect_ratio_idx) - { - case ASPECT_RATIO_SQUARE: - video_driver_set_viewport_square_pixel(); - break; - - case ASPECT_RATIO_CORE: - video_driver_set_viewport_core(); - break; - - case ASPECT_RATIO_CONFIG: - video_driver_set_viewport_config(); - break; - - default: - break; - } - - video_driver_set_aspect_ratio_value( - aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); - - if (!video_driver_poke || !video_driver_poke->set_aspect_ratio) - return; - video_driver_poke->set_aspect_ratio( - video_driver_data, settings->uints.video_aspect_ratio_idx); -} - -void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect) -{ - gfx_ctx_aspect_t aspect_data; - float device_aspect = (float)vp->full_width / vp->full_height; - settings_t* settings = config_get_ptr(); - - aspect_data.aspect = &device_aspect; - aspect_data.width = vp->full_width; - aspect_data.height = vp->full_height; - - video_context_driver_translate_aspect(&aspect_data); - - vp->x = 0; - vp->y = 0; - vp->width = vp->full_width; - vp->height = vp->full_height; - - if (settings->bools.video_scale_integer && !force_full) - { - video_viewport_get_scaled_integer( - vp, vp->full_width, vp->full_height, video_driver_get_aspect_ratio(), keep_aspect); - } - else if (keep_aspect && !force_full) - { - float desired_aspect = video_driver_get_aspect_ratio(); - -#if defined(HAVE_MENU) - if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) - { - const struct video_viewport* custom = video_viewport_get_custom(); - - vp->x = custom->x; - vp->y = custom->y; - vp->width = custom->width; - vp->height = custom->height; - } - else -#endif - { - float delta; - - if (fabsf(device_aspect - desired_aspect) < 0.0001f) - { - /* If the aspect ratios of screen and desired aspect - * ratio are sufficiently equal (floating point stuff), - * assume they are actually equal. - */ - } - else if (device_aspect > desired_aspect) - { - delta = (desired_aspect / device_aspect - 1.0f) - / 2.0f + 0.5f; - vp->x = (int)roundf(vp->full_width * (0.5f - delta)); - vp->width = (unsigned)roundf(2.0f * vp->full_width * delta); - vp->y = 0; - vp->height = vp->full_height; - } - else - { - vp->x = 0; - vp->width = vp->full_width; - delta = (device_aspect / desired_aspect - 1.0f) - / 2.0f + 0.5f; - vp->y = (int)roundf(vp->full_height * (0.5f - delta)); - vp->height = (unsigned)roundf(2.0f * vp->full_height * delta); - } - } - } - -#if defined(RARCH_MOBILE) - /* In portrait mode, we want viewport to gravitate to top of screen. */ - if (device_aspect < 1.0f) - vp->y = 0; -#endif -} - -void video_driver_show_mouse(void) -{ - if (video_driver_poke && video_driver_poke->show_mouse) - video_driver_poke->show_mouse(video_driver_data, true); -} - -void video_driver_hide_mouse(void) -{ - if (video_driver_poke && video_driver_poke->show_mouse) - video_driver_poke->show_mouse(video_driver_data, false); -} - -void video_driver_set_nonblock_state(bool toggle) -{ - if (current_video->set_nonblock_state) - current_video->set_nonblock_state(video_driver_data, toggle); -} - -bool video_driver_find_driver(void) -{ - int i; - driver_ctx_info_t drv; - settings_t *settings = config_get_ptr(); - - if (video_driver_is_hw_context()) - { - struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); - - current_video = NULL; - - (void)hwr; - -#if defined(HAVE_VULKAN) - if (hwr && hw_render_context_is_vulkan(hwr->context_type)) - { - RARCH_LOG("[Video]: Using HW render, Vulkan driver forced.\n"); - current_video = &video_vulkan; - } -#endif - -#if defined(HAVE_OPENGL) - if (hwr && hw_render_context_is_gl(hwr->context_type)) - { - RARCH_LOG("[Video]: Using HW render, OpenGL driver forced.\n"); - current_video = &video_gl; - } -#endif - - if (current_video) - return true; - } - - if (frontend_driver_has_get_video_driver_func()) - { - current_video = (video_driver_t*)frontend_driver_get_video_driver(); - - if (current_video) - return true; - RARCH_WARN("Frontend supports get_video_driver() but did not specify one.\n"); - } - - drv.label = "video_driver"; - drv.s = settings->arrays.video_driver; - - driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv); - - i = (int)drv.len; - - if (i >= 0) - current_video = (video_driver_t*)video_driver_find_handle(i); - else - { - if (verbosity_is_enabled()) - { - unsigned d; - RARCH_ERR("Couldn't find any video driver named \"%s\"\n", - settings->arrays.video_driver); - RARCH_LOG_OUTPUT("Available video drivers are:\n"); - for (d = 0; video_driver_find_handle(d); d++) - RARCH_LOG_OUTPUT("\t%s\n", video_driver_find_ident(d)); - RARCH_WARN("Going to default to first video driver...\n"); - } - - current_video = (video_driver_t*)video_driver_find_handle(0); - - if (!current_video) - retroarch_fail(1, "find_video_driver()"); - } - return true; -} - -void video_driver_apply_state_changes(void) -{ - if (video_driver_poke && - video_driver_poke->apply_state_changes) - video_driver_poke->apply_state_changes(video_driver_data); -} - -bool video_driver_read_viewport(uint8_t *buffer, bool is_idle) -{ - if ( current_video->read_viewport - && current_video->read_viewport( - video_driver_data, buffer, is_idle)) - return true; - return false; -} - -bool video_driver_frame_filter_alive(void) -{ - return !!video_driver_state_filter; -} - -bool video_driver_frame_filter_is_32bit(void) -{ - return video_driver_state_out_rgb32; -} - -void video_driver_default_settings(void) -{ - global_t *global = global_get_ptr(); - - if (!global) - return; - - global->console.screen.gamma_correction = DEFAULT_GAMMA; - global->console.flickerfilter_enable = false; - global->console.softfilter_enable = false; - - global->console.screen.resolutions.current.id = 0; -} - -void video_driver_load_settings(config_file_t *conf) -{ - bool tmp_bool = false; - global_t *global = global_get_ptr(); - - if (!conf) - return; - -#ifdef _XBOX - CONFIG_GET_BOOL_BASE(conf, global, - console.screen.gamma_correction, "gamma_correction"); -#else - CONFIG_GET_INT_BASE(conf, global, - console.screen.gamma_correction, "gamma_correction"); -#endif - - if (config_get_bool(conf, "flicker_filter_enable", - &tmp_bool)) - global->console.flickerfilter_enable = tmp_bool; - - if (config_get_bool(conf, "soft_filter_enable", - &tmp_bool)) - global->console.softfilter_enable = tmp_bool; - - CONFIG_GET_INT_BASE(conf, global, - console.screen.soft_filter_index, - "soft_filter_index"); - CONFIG_GET_INT_BASE(conf, global, - console.screen.resolutions.current.id, - "current_resolution_id"); - CONFIG_GET_INT_BASE(conf, global, - console.screen.flicker_filter_index, - "flicker_filter_index"); -} - -void video_driver_save_settings(config_file_t *conf) -{ - global_t *global = global_get_ptr(); - if (!conf) - return; - -#ifdef _XBOX - config_set_bool(conf, "gamma_correction", - global->console.screen.gamma_correction); -#else - config_set_int(conf, "gamma_correction", - global->console.screen.gamma_correction); -#endif - config_set_bool(conf, "flicker_filter_enable", - global->console.flickerfilter_enable); - config_set_bool(conf, "soft_filter_enable", - global->console.softfilter_enable); - - config_set_int(conf, "soft_filter_index", - global->console.screen.soft_filter_index); - config_set_int(conf, "current_resolution_id", - global->console.screen.resolutions.current.id); - config_set_int(conf, "flicker_filter_index", - global->console.screen.flicker_filter_index); -} - -void video_driver_reinit(void) -{ - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); - - if (hwr->cache_context) - video_driver_cache_context = true; - else - video_driver_cache_context = false; - - video_driver_cache_context_ack = false; - command_event(CMD_EVENT_RESET_CONTEXT, NULL); - video_driver_cache_context = false; -} - -void video_driver_set_own_driver(void) -{ - video_driver_data_own = true; -} - -void video_driver_unset_own_driver(void) -{ - video_driver_data_own = false; -} - -bool video_driver_owns_driver(void) -{ - return video_driver_data_own; -} - -bool video_driver_is_hw_context(void) -{ - bool is_hw_context = false; - - video_driver_context_lock(); - is_hw_context = (hw_render.context_type != RETRO_HW_CONTEXT_NONE); - video_driver_context_unlock(); - - return is_hw_context; -} - -void video_driver_free_hw_context(void) -{ - video_driver_context_lock(); - - if (hw_render.context_destroy) - hw_render.context_destroy(); - - memset(&hw_render, 0, sizeof(hw_render)); - - video_driver_context_unlock(); - - hw_render_context_negotiation = NULL; -} - -struct retro_hw_render_callback *video_driver_get_hw_context(void) -{ - return &hw_render; -} - -const struct retro_hw_render_context_negotiation_interface * - video_driver_get_context_negotiation_interface(void) -{ - return hw_render_context_negotiation; -} - -void video_driver_set_context_negotiation_interface( - const struct retro_hw_render_context_negotiation_interface *iface) -{ - hw_render_context_negotiation = iface; -} - -bool video_driver_is_video_cache_context(void) -{ - return video_driver_cache_context; -} - -void video_driver_set_video_cache_context_ack(void) -{ - video_driver_cache_context_ack = true; -} - -void video_driver_unset_video_cache_context_ack(void) -{ - video_driver_cache_context_ack = false; -} - -bool video_driver_is_video_cache_context_ack(void) -{ - return video_driver_cache_context_ack; -} - -void video_driver_set_active(void) -{ - video_driver_active = true; -} - -void video_driver_unset_active(void) -{ - video_driver_active = false; -} - -bool video_driver_is_active(void) -{ - return video_driver_active; -} - -void video_driver_get_record_status( - bool *has_gpu_record, - uint8_t **gpu_buf) -{ - *gpu_buf = video_driver_record_gpu_buffer; - *has_gpu_record = video_driver_record_gpu_buffer != NULL; -} - -bool video_driver_gpu_record_init(unsigned size) -{ - video_driver_record_gpu_buffer = (uint8_t*)malloc(size); - if (!video_driver_record_gpu_buffer) - return false; - return true; -} - -void video_driver_gpu_record_deinit(void) -{ - free(video_driver_record_gpu_buffer); - video_driver_record_gpu_buffer = NULL; -} - -bool video_driver_get_current_software_framebuffer( - struct retro_framebuffer *fb) -{ - if ( - video_driver_poke - && video_driver_poke->get_current_software_framebuffer - && video_driver_poke->get_current_software_framebuffer( - video_driver_data, fb)) - return true; - - return false; -} - -bool video_driver_get_hw_render_interface( - const struct retro_hw_render_interface **iface) -{ - if ( - video_driver_poke - && video_driver_poke->get_hw_render_interface - && video_driver_poke->get_hw_render_interface( - video_driver_data, iface)) - return true; - - return false; -} - -bool video_driver_get_viewport_info(struct video_viewport *viewport) -{ - if (!current_video || !current_video->viewport_info) - return false; - current_video->viewport_info(video_driver_data, viewport); - return true; -} - -void video_driver_set_title_buf(void) -{ - struct retro_system_info info; - core_get_system_info(&info); - - fill_pathname_join_concat_noext( - video_driver_title_buf, - msg_hash_to_str(MSG_PROGRAM), - " ", - info.library_name, - sizeof(video_driver_title_buf)); - strlcat(video_driver_title_buf, - " ", sizeof(video_driver_title_buf)); - strlcat(video_driver_title_buf, - info.library_version, - sizeof(video_driver_title_buf)); -} - -/** - * video_viewport_get_scaled_integer: - * @vp : Viewport handle - * @width : Width. - * @height : Height. - * @aspect_ratio : Aspect ratio (in float). - * @keep_aspect : Preserve aspect ratio? - * - * Gets viewport scaling dimensions based on - * scaled integer aspect ratio. - **/ -void video_viewport_get_scaled_integer(struct video_viewport *vp, - unsigned width, unsigned height, - float aspect_ratio, bool keep_aspect) -{ - int padding_x = 0; - int padding_y = 0; - settings_t *settings = config_get_ptr(); - - if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) - { - struct video_viewport *custom = video_viewport_get_custom(); - - if (custom) - { - padding_x = width - custom->width; - padding_y = height - custom->height; - width = custom->width; - height = custom->height; - } - } - else - { - unsigned base_width; - /* Use system reported sizes as these define the - * geometry for the "normal" case. */ - unsigned base_height = - video_driver_av_info.geometry.base_height; - - if (base_height == 0) - base_height = 1; - - /* Account for non-square pixels. - * This is sort of contradictory with the goal of integer scale, - * but it is desirable in some cases. - * - * If square pixels are used, base_height will be equal to - * system->av_info.base_height. */ - base_width = (unsigned)roundf(base_height * aspect_ratio); - - /* Make sure that we don't get 0x scale ... */ - if (width >= base_width && height >= base_height) - { - if (keep_aspect) - { - /* X/Y scale must be same. */ - unsigned max_scale = MIN(width / base_width, - height / base_height); - padding_x = width - base_width * max_scale; - padding_y = height - base_height * max_scale; - } - else - { - /* X/Y can be independent, each scaled as much as possible. */ - padding_x = width % base_width; - padding_y = height % base_height; - } - } - - width -= padding_x; - height -= padding_y; - } - - vp->width = width; - vp->height = height; - vp->x = padding_x / 2; - vp->y = padding_y / 2; -} - -struct retro_system_av_info *video_viewport_get_system_av_info(void) -{ - return &video_driver_av_info; -} - -struct video_viewport *video_viewport_get_custom(void) -{ - settings_t *settings = config_get_ptr(); - return &settings->video_viewport_custom; -} - -unsigned video_pixel_get_alignment(unsigned pitch) -{ - if (pitch & 1) - return 1; - if (pitch & 2) - return 2; - if (pitch & 4) - return 4; - return 8; -} - -/** - * video_driver_frame: - * @data : pointer to data of the video frame. - * @width : width of the video frame. - * @height : height of the video frame. - * @pitch : pitch of the video frame. - * - * Video frame render callback function. - **/ -void video_driver_frame(const void *data, unsigned width, - unsigned height, size_t pitch) -{ - static char video_driver_msg[256]; - static char title[256]; - video_frame_info_t video_info; - static retro_time_t curr_time; - static retro_time_t fps_time; - static float last_fps, frame_time; - unsigned output_width = 0; - unsigned output_height = 0; - unsigned output_pitch = 0; - const char *msg = NULL; - retro_time_t new_time = - cpu_features_get_time_usec(); - - if (!video_driver_active) - return; - - if (video_driver_scaler_ptr && data && - (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_0RGB1555) && - (data != RETRO_HW_FRAME_BUFFER_VALID)) - { - if (video_pixel_frame_scale( - video_driver_scaler_ptr->scaler, - video_driver_scaler_ptr->scaler_out, - data, width, height, pitch)) - { - data = video_driver_scaler_ptr->scaler_out; - pitch = video_driver_scaler_ptr->scaler->out_stride; - } - } - - if (data) - frame_cache_data = data; - frame_cache_width = width; - frame_cache_height = height; - frame_cache_pitch = pitch; - - video_driver_build_info(&video_info); - - /* Get the amount of frames per seconds. */ - if (video_driver_frame_count) - { - unsigned write_index = - video_driver_frame_time_count++ & - (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1); - frame_time = new_time - fps_time; - video_driver_frame_time_samples[write_index] = frame_time; - fps_time = new_time; - - if (video_driver_frame_count == 1) - strlcpy(title, video_driver_window_title, sizeof(title)); - - if ((video_driver_frame_count % FPS_UPDATE_INTERVAL) == 0) - { - char frames_text[64]; - last_fps = TIME_TO_FPS(curr_time, new_time, FPS_UPDATE_INTERVAL); - - if (video_info.fps_show || video_info.framecount_show) - { - if (video_info.fps_show) - { - snprintf(video_info.fps_text, sizeof(video_info.fps_text), - " || FPS: %6.1f ", last_fps); - } - if (video_info.framecount_show) - { - snprintf(frames_text, - sizeof(frames_text), - " || Frames: %" PRIu64, - (uint64_t)video_driver_frame_count); - } - snprintf(video_driver_window_title, sizeof(video_driver_window_title), - "%s%s%s", title, - video_info.fps_show ? video_info.fps_text : "", - video_info.framecount_show ? frames_text : ""); - } - else - { - if (!string_is_equal(video_driver_window_title, title)) - strlcpy(video_driver_window_title, title, sizeof(video_driver_window_title)); - } - - curr_time = new_time; - video_driver_window_title_update = true; - } - - if (video_info.fps_show) - { - if (video_info.framecount_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f || %s: %" PRIu64, - last_fps, - msg_hash_to_str(MSG_FRAMES), - (uint64_t)video_driver_frame_count); - else - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f", - last_fps); - } - - if (video_info.fps_show && video_info.framecount_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f || %s: %" PRIu64, - last_fps, - msg_hash_to_str(MSG_FRAMES), - (uint64_t)video_driver_frame_count); - else if (video_info.framecount_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "%s: %" PRIu64, - msg_hash_to_str(MSG_FRAMES), - (uint64_t)video_driver_frame_count); - else if (video_info.fps_show) - snprintf( - video_info.fps_text, - sizeof(video_info.fps_text), - "FPS: %6.1f", - last_fps); - } - else - { - - curr_time = fps_time = new_time; - - strlcpy(video_driver_window_title, - video_driver_title_buf, - sizeof(video_driver_window_title)); - - if (video_info.fps_show) - strlcpy(video_info.fps_text, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), - sizeof(video_info.fps_text)); - - video_driver_window_title_update = true; - } - - video_info.frame_rate = last_fps; - video_info.frame_time = frame_time / 1000.0f; - video_info.frame_count = (uint64_t) video_driver_frame_count; - - /* Slightly messy code, - * but we really need to do processing before blocking on VSync - * for best possible scheduling. - */ - if ( - ( - !video_driver_state_filter - || !video_info.post_filter_record - || !data - || video_driver_record_gpu_buffer - ) && recording_data - ) - recording_dump_frame(data, width, height, - pitch, video_info.runloop_is_idle); - - if (data && video_driver_state_filter && - video_driver_frame_filter(data, &video_info, width, height, pitch, - &output_width, &output_height, &output_pitch)) - { - data = video_driver_state_buffer; - width = output_width; - height = output_height; - pitch = output_pitch; - } - - video_driver_msg[0] = '\0'; - - if ( video_info.font_enable - && runloop_msg_queue_pull((const char**)&msg) - && msg) - { -#ifdef HAVE_THREADS - /* the msg pointer may point to data modified by another thread */ - runloop_msg_queue_lock(); -#endif - strlcpy(video_driver_msg, msg, sizeof(video_driver_msg)); -#ifdef HAVE_THREADS - runloop_msg_queue_unlock(); -#endif - } - - if (video_info.statistics_show) - { - audio_statistics_t audio_stats = {0.0f}; - double stddev = 0.0; - struct retro_system_av_info *av_info = &video_driver_av_info; - unsigned red = 255; - unsigned green = 255; - unsigned blue = 255; - unsigned alpha = 255; - - video_monitor_fps_statistics(NULL, &stddev, NULL); - - video_info.osd_stat_params.x = 0.010f; - video_info.osd_stat_params.y = 0.950f; - video_info.osd_stat_params.scale = 1.0f; - video_info.osd_stat_params.full_screen = true; - video_info.osd_stat_params.drop_x = -2; - video_info.osd_stat_params.drop_y = -2; - video_info.osd_stat_params.drop_mod = 0.3f; - video_info.osd_stat_params.drop_alpha = 1.0f; - video_info.osd_stat_params.color = COLOR_ABGR( - red, green, blue, alpha); - - compute_audio_buffer_statistics(&audio_stats); - - snprintf(video_info.stat_text, - sizeof(video_info.stat_text), - "Video Statistics:\n -Frame rate: %6.2f fps\n -Frame time: %6.2f ms\n -Frame time deviation: %.3f %%\n" - " -Frame count: %" PRIu64"\n -Viewport: %d x %d x %3.2f\n" - "Audio Statistics:\n -Average buffer saturation: %.2f %%\n -Standard deviation: %.2f %%\n -Time spent close to underrun: %.2f %%\n -Time spent close to blocking: %.2f %%\n -Sample count: %d\n" - "Core Geometry:\n -Size: %u x %u\n -Max Size: %u x %u\n -Aspect: %3.2f\nCore Timing:\n -FPS: %3.2f\n -Sample Rate: %6.2f\n", - video_info.frame_rate, - video_info.frame_time, - 100.0 * stddev, - video_info.frame_count, - video_info.width, - video_info.height, - video_info.refresh_rate, - audio_stats.average_buffer_saturation, - audio_stats.std_deviation_percentage, - audio_stats.close_to_underrun, - audio_stats.close_to_blocking, - audio_stats.samples, - av_info->geometry.base_width, - av_info->geometry.base_height, - av_info->geometry.max_width, - av_info->geometry.max_height, - av_info->geometry.aspect_ratio, - av_info->timing.fps, - av_info->timing.sample_rate); - - /* TODO/FIXME - add OSD chat text here */ -#if 0 - snprintf(video_info.chat_text, sizeof(video_info.chat_text), - "anon: does retroarch netplay have in-game chat?\nradius: I don't know \u2605"); -#endif - } - - video_driver_active = current_video->frame( - video_driver_data, data, width, height, - video_driver_frame_count, - (unsigned)pitch, video_driver_msg, &video_info); - - video_driver_frame_count++; - - /* Display the FPS, with a higher priority. */ - if (video_info.fps_show || video_info.framecount_show) - runloop_msg_queue_push(video_info.fps_text, 2, 1, true); - - /* trigger set resolution*/ - if (video_info.crt_switch_resolution) - { - video_driver_crt_switching_active = true; - - if (video_info.crt_switch_resolution_super == 2560) - width = 2560; - if (video_info.crt_switch_resolution_super == 3840) - width = 3840; - if (video_info.crt_switch_resolution_super == 1920) - width = 1920; - crt_switch_res_core(width, height, video_driver_core_hz, video_info.crt_switch_resolution, video_info.crt_switch_center_adjust, video_info.monitor_index); - } - else if (!video_info.crt_switch_resolution) - video_driver_crt_switching_active = false; - - /* trigger set resolution*/ -} - -void crt_switch_driver_reinit(void) -{ - video_driver_reinit(); -} - -void video_driver_display_type_set(enum rarch_display_type type) -{ - video_driver_display_type = type; -} - -uintptr_t video_driver_display_get(void) -{ - return video_driver_display; -} - -void video_driver_display_set(uintptr_t idx) -{ - video_driver_display = idx; -} - -enum rarch_display_type video_driver_display_type_get(void) -{ - return video_driver_display_type; -} - -void video_driver_window_set(uintptr_t idx) -{ - video_driver_window = idx; -} - -uintptr_t video_driver_window_get(void) -{ - return video_driver_window; -} - -bool video_driver_texture_load(void *data, - enum texture_filter_type filter_type, - uintptr_t *id) -{ - if (!id || !video_driver_poke || !video_driver_poke->load_texture) - return false; - - *id = video_driver_poke->load_texture(video_driver_data, data, - video_driver_is_threaded_internal(), - filter_type); - - return true; -} - -bool video_driver_texture_unload(uintptr_t *id) -{ - if (!video_driver_poke || !video_driver_poke->unload_texture) - return false; - - video_driver_poke->unload_texture(video_driver_data, *id); - *id = 0; - return true; -} - -static bool video_driver_cb_set_coords(void *handle_data, - void *shader_data, const struct video_coords *coords) -{ - video_shader_ctx_coords_t ctx_coords; - ctx_coords.handle_data = handle_data; - ctx_coords.data = coords; - - video_driver_set_coords(&ctx_coords); - return true; -} - -void video_driver_build_info(video_frame_info_t *video_info) -{ - bool is_perfcnt_enable = false; - bool is_paused = false; - bool is_idle = false; - bool is_slowmotion = false; - settings_t *settings = NULL; - video_viewport_t *custom_vp = NULL; - struct retro_hw_render_callback *hwr = - video_driver_get_hw_context(); -#ifdef HAVE_THREADS - bool is_threaded = video_driver_is_threaded_internal(); - video_driver_threaded_lock(is_threaded); -#endif - settings = config_get_ptr(); - custom_vp = &settings->video_viewport_custom; - video_info->refresh_rate = settings->floats.video_refresh_rate; - video_info->crt_switch_resolution = settings->uints.crt_switch_resolution; - video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super; - video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust; - video_info->black_frame_insertion = settings->bools.video_black_frame_insertion; - video_info->hard_sync = settings->bools.video_hard_sync; - video_info->hard_sync_frames = settings->uints.video_hard_sync_frames; - video_info->fps_show = settings->bools.video_fps_show; - video_info->statistics_show = settings->bools.video_statistics_show; - video_info->framecount_show = settings->bools.video_framecount_show; - video_info->scale_integer = settings->bools.video_scale_integer; - video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx; - video_info->post_filter_record = settings->bools.video_post_filter_record; - video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons; - video_info->max_swapchain_images = settings->uints.video_max_swapchain_images; - video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen; - video_info->fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); - video_info->monitor_index = settings->uints.video_monitor_index; - video_info->shared_context = settings->bools.video_shared_context; - - if (libretro_get_shared_context() && hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) - video_info->shared_context = true; - - video_info->font_enable = settings->bools.video_font_enable; - video_info->font_msg_pos_x = settings->floats.video_msg_pos_x; - video_info->font_msg_pos_y = settings->floats.video_msg_pos_y; - video_info->font_msg_color_r = settings->floats.video_msg_color_r; - video_info->font_msg_color_g = settings->floats.video_msg_color_g; - video_info->font_msg_color_b = settings->floats.video_msg_color_b; - video_info->custom_vp_x = custom_vp->x; - video_info->custom_vp_y = custom_vp->y; - video_info->custom_vp_width = custom_vp->width; - video_info->custom_vp_height = custom_vp->height; - video_info->custom_vp_full_width = custom_vp->full_width; - video_info->custom_vp_full_height = custom_vp->full_height; - - video_info->fps_text[0] = '\0'; - - video_info->width = video_driver_width; - video_info->height = video_driver_height; - - video_info->use_rgba = video_driver_use_rgba; - - video_info->libretro_running = false; - video_info->msg_bgcolor_enable = settings->bools.video_msg_bgcolor_enable; - -#ifdef HAVE_MENU - video_info->menu_is_alive = menu_driver_is_alive(); - video_info->menu_footer_opacity = settings->floats.menu_footer_opacity; - video_info->menu_header_opacity = settings->floats.menu_header_opacity; - video_info->materialui_color_theme = settings->uints.menu_materialui_color_theme; - video_info->ozone_color_theme = settings->uints.menu_ozone_color_theme; - video_info->menu_shader_pipeline = settings->uints.menu_xmb_shader_pipeline; - video_info->xmb_theme = settings->uints.menu_xmb_theme; - video_info->xmb_color_theme = settings->uints.menu_xmb_color_theme; - video_info->timedate_enable = settings->bools.menu_timedate_enable; - video_info->battery_level_enable = settings->bools.menu_battery_level_enable; - video_info->xmb_shadows_enable = settings->bools.menu_xmb_shadows_enable; - video_info->xmb_alpha_factor = settings->uints.menu_xmb_alpha_factor; - video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity; - video_info->menu_framebuffer_opacity = settings->floats.menu_framebuffer_opacity; - - video_info->libretro_running = core_is_game_loaded(); -#else - video_info->menu_is_alive = false; - video_info->menu_footer_opacity = 0.0f; - video_info->menu_header_opacity = 0.0f; - video_info->materialui_color_theme = 0; - video_info->menu_shader_pipeline = 0; - video_info->xmb_color_theme = 0; - video_info->xmb_theme = 0; - video_info->timedate_enable = false; - video_info->battery_level_enable = false; - video_info->xmb_shadows_enable = false; - video_info->xmb_alpha_factor = 0.0f; - video_info->menu_framebuffer_opacity = 0.0f; - video_info->menu_wallpaper_opacity = 0.0f; -#endif - - runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); - - video_info->is_perfcnt_enable = is_perfcnt_enable; - video_info->runloop_is_paused = is_paused; - video_info->runloop_is_idle = is_idle; - video_info->runloop_is_slowmotion = is_slowmotion; - - video_info->input_driver_nonblock_state = input_driver_is_nonblock_state(); - - video_info->context_data = video_context_data; - video_info->shader_driver = current_shader; - video_info->shader_data = current_shader_data; - - video_info->cb_update_window_title = current_video_context.update_window_title; - video_info->cb_swap_buffers = current_video_context.swap_buffers; - video_info->cb_get_metrics = current_video_context.get_metrics; - video_info->cb_set_resize = current_video_context.set_resize; - - video_info->cb_set_mvp = video_driver_cb_shader_set_mvp; - - video_info->userdata = video_driver_get_ptr(false); - -#ifdef HAVE_THREADS - video_driver_threaded_unlock(is_threaded); -#endif -} - -/** - * video_driver_translate_coord_viewport: - * @mouse_x : Pointer X coordinate. - * @mouse_y : Pointer Y coordinate. - * @res_x : Scaled X coordinate. - * @res_y : Scaled Y coordinate. - * @res_screen_x : Scaled screen X coordinate. - * @res_screen_y : Scaled screen Y coordinate. - * - * Translates pointer [X,Y] coordinates into scaled screen - * coordinates based on viewport info. - * - * Returns: true (1) if successful, false if video driver doesn't support - * viewport info. - **/ -bool video_driver_translate_coord_viewport( - struct video_viewport *vp, - int mouse_x, int mouse_y, - int16_t *res_x, int16_t *res_y, - int16_t *res_screen_x, int16_t *res_screen_y) -{ - int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y; - int norm_vp_width = (int)vp->width; - int norm_vp_height = (int)vp->height; - int norm_full_vp_width = (int)vp->full_width; - int norm_full_vp_height = (int)vp->full_height; - - if (norm_full_vp_width <= 0 || norm_full_vp_height <= 0) - return false; - - if (mouse_x >= 0 && mouse_x <= norm_full_vp_width) - scaled_screen_x = ((2 * mouse_x * 0x7fff) - / norm_full_vp_width) - 0x7fff; - else - scaled_screen_x = -0x8000; /* OOB */ - - if (mouse_y >= 0 && mouse_y <= norm_full_vp_height) - scaled_screen_y = ((2 * mouse_y * 0x7fff) - / norm_full_vp_height) - 0x7fff; - else - scaled_screen_y = -0x8000; /* OOB */ - - mouse_x -= vp->x; - mouse_y -= vp->y; - - if (mouse_x >= 0 && mouse_x <= norm_vp_width) - scaled_x = ((2 * mouse_x * 0x7fff) - / norm_vp_width) - 0x7fff; - else - scaled_x = -0x8000; /* OOB */ - - if (mouse_y >= 0 && mouse_y <= norm_vp_height) - scaled_y = ((2 * mouse_y * 0x7fff) - / norm_vp_height) - 0x7fff; - else - scaled_y = -0x8000; /* OOB */ - - *res_x = scaled_x; - *res_y = scaled_y; - *res_screen_x = scaled_screen_x; - *res_screen_y = scaled_screen_y; - - return true; -} - -void video_driver_get_window_title(char *buf, unsigned len) -{ - if (buf && video_driver_window_title_update) - { - strlcpy(buf, video_driver_window_title, len); - video_driver_window_title_update = false; - } -} - -void video_driver_get_status(uint64_t *frame_count, bool * is_alive, - bool *is_focused) -{ - *frame_count = video_driver_frame_count; - *is_alive = current_video ? - current_video->alive(video_driver_data) : true; - *is_focused = video_driver_cb_has_focus(); -} - -/** - * find_video_context_driver_driver_index: - * @ident : Identifier of resampler driver to find. - * - * Finds graphics context driver index by @ident name. - * - * Returns: graphics context driver index if driver was found, otherwise - * -1. - **/ -static int find_video_context_driver_index(const char *ident) -{ - unsigned i; - for (i = 0; gfx_ctx_drivers[i]; i++) - if (string_is_equal_noncase(ident, gfx_ctx_drivers[i]->ident)) - return i; - return -1; -} - -/** - * find_prev_context_driver: - * - * Finds previous driver in graphics context driver array. - **/ -bool video_context_driver_find_prev_driver(void) -{ - settings_t *settings = config_get_ptr(); - int i = find_video_context_driver_index( - settings->arrays.video_context_driver); - - if (i > 0) - { - strlcpy(settings->arrays.video_context_driver, - gfx_ctx_drivers[i - 1]->ident, - sizeof(settings->arrays.video_context_driver)); - return true; - } - - RARCH_WARN("Couldn't find any previous video context driver.\n"); - return false; -} - -/** - * find_next_context_driver: - * - * Finds next driver in graphics context driver array. - **/ -bool video_context_driver_find_next_driver(void) -{ - settings_t *settings = config_get_ptr(); - int i = find_video_context_driver_index( - settings->arrays.video_context_driver); - - if (i >= 0 && gfx_ctx_drivers[i + 1]) - { - strlcpy(settings->arrays.video_context_driver, - gfx_ctx_drivers[i + 1]->ident, - sizeof(settings->arrays.video_context_driver)); - return true; - } - - RARCH_WARN("Couldn't find any next video context driver.\n"); - return false; -} - -/** - * video_context_driver_init: - * @data : Input data. - * @ctx : Graphics context driver to initialize. - * @ident : Identifier of graphics context driver to find. - * @api : API of higher-level graphics API. - * @major : Major version number of higher-level graphics API. - * @minor : Minor version number of higher-level graphics API. - * @hw_render_ctx : Request a graphics context driver capable of - * hardware rendering? - * - * Initialize graphics context driver. - * - * Returns: graphics context driver if successfully initialized, - * otherwise NULL. - **/ -static const gfx_ctx_driver_t *video_context_driver_init( - void *data, - const gfx_ctx_driver_t *ctx, - const char *ident, - enum gfx_ctx_api api, unsigned major, - unsigned minor, bool hw_render_ctx, - void **ctx_data) -{ - video_frame_info_t video_info; - - if (!ctx->bind_api(data, api, major, minor)) - { - RARCH_WARN("Failed to bind API (#%u, version %u.%u)" - " on context driver \"%s\".\n", - (unsigned)api, major, minor, ctx->ident); - - return NULL; - } - - video_driver_build_info(&video_info); - - if (!(*ctx_data = ctx->init(&video_info, data))) - return NULL; - - if (ctx->bind_hw_render) - ctx->bind_hw_render(*ctx_data, - video_info.shared_context && hw_render_ctx); - - return ctx; -} - -/** - * video_context_driver_init_first: - * @data : Input data. - * @ident : Identifier of graphics context driver to find. - * @api : API of higher-level graphics API. - * @major : Major version number of higher-level graphics API. - * @minor : Minor version number of higher-level graphics API. - * @hw_render_ctx : Request a graphics context driver capable of - * hardware rendering? - * - * Finds first suitable graphics context driver and initializes. - * - * Returns: graphics context driver if found, otherwise NULL. - **/ -const gfx_ctx_driver_t *video_context_driver_init_first(void *data, - const char *ident, enum gfx_ctx_api api, unsigned major, - unsigned minor, bool hw_render_ctx, void **ctx_data) -{ - int i = find_video_context_driver_index(ident); - - if (i >= 0) - { - const gfx_ctx_driver_t *ctx = video_context_driver_init(data, gfx_ctx_drivers[i], ident, - api, major, minor, hw_render_ctx, ctx_data); - if (ctx) - { - video_context_data = *ctx_data; - return ctx; - } - } - - for (i = 0; gfx_ctx_drivers[i]; i++) - { - const gfx_ctx_driver_t *ctx = - video_context_driver_init(data, gfx_ctx_drivers[i], ident, - api, major, minor, hw_render_ctx, ctx_data); - - if (ctx) - { - video_context_data = *ctx_data; - return ctx; - } - } - - return NULL; -} - -bool video_context_driver_init_image_buffer(const video_info_t *data) -{ - if ( - current_video_context.image_buffer_init - && current_video_context.image_buffer_init( - video_context_data, data)) - return true; - return false; -} - -bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img) -{ - if ( - current_video_context.image_buffer_write - && current_video_context.image_buffer_write(video_context_data, - img->frame, img->width, img->height, img->pitch, - img->rgb32, img->index, img->handle)) - return true; - return false; -} - -bool video_context_driver_get_video_output_prev(void) -{ - if (!current_video_context.get_video_output_prev) - return false; - current_video_context.get_video_output_prev(video_context_data); - return true; -} - -bool video_context_driver_get_video_output_next(void) -{ - if (!current_video_context.get_video_output_next) - return false; - current_video_context.get_video_output_next(video_context_data); - return true; -} - -void video_context_driver_make_current(bool release) -{ - if (current_video_context.make_current) - current_video_context.make_current(release); -} - -bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect) -{ - if (!video_context_data || !aspect) - return false; - if (!current_video_context.translate_aspect) - return false; - *aspect->aspect = current_video_context.translate_aspect( - video_context_data, aspect->width, aspect->height); - return true; -} - -void video_context_driver_free(void) -{ - if (current_video_context.destroy) - current_video_context.destroy(video_context_data); - video_context_driver_destroy(); - video_context_data = NULL; -} - -bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data) -{ - if (!size_data) - return false; - if (!current_video_context.get_video_output_size) - return false; - current_video_context.get_video_output_size(video_context_data, - size_data->width, size_data->height); - return true; -} - -bool video_context_driver_swap_interval(int *interval) -{ - gfx_ctx_flags_t flags; - int current_interval = *interval; - settings_t *settings = config_get_ptr(); - bool adaptive_vsync_enabled = video_driver_get_all_flags(&flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && settings->bools.video_adaptive_vsync; - - if (!current_video_context.swap_interval) - return false; - if (adaptive_vsync_enabled && current_interval == 1) - current_interval = -1; - current_video_context.swap_interval(video_context_data, current_interval); - return true; -} - -bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc) -{ - if (!current_video_context.get_proc_address) - return false; - - proc->addr = current_video_context.get_proc_address(proc->sym); - - return true; -} - -bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics) -{ - if ( - current_video_context.get_metrics(video_context_data, - metrics->type, - metrics->value)) - return true; - return false; -} - -bool video_context_driver_get_refresh_rate(float *refresh_rate) -{ - float refresh_holder = 0; - - if (!current_video_context.get_refresh_rate || !refresh_rate) - return false; - if (!video_context_data) - return false; - - if (!video_driver_crt_switching_active) - if (refresh_rate) - *refresh_rate = - current_video_context.get_refresh_rate(video_context_data); - - if (video_driver_crt_switching_active) - { - if (refresh_rate) - refresh_holder = - current_video_context.get_refresh_rate(video_context_data); - if (refresh_holder != video_driver_core_hz) /* Fix for incorrect interlace detsction -- HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/ - *refresh_rate = video_driver_core_hz; - } - - return true; -} - -bool video_context_driver_input_driver(gfx_ctx_input_t *inp) -{ - settings_t *settings = config_get_ptr(); - const char *joypad_name = settings ? - settings->arrays.input_joypad_driver : NULL; - - if (!current_video_context.input_driver) - return false; - current_video_context.input_driver( - video_context_data, joypad_name, - inp->input, inp->input_data); - return true; -} - -bool video_context_driver_suppress_screensaver(bool *bool_data) -{ - if ( video_context_data - && current_video_context.suppress_screensaver( - video_context_data, *bool_data)) - return true; - return false; -} - -bool video_context_driver_get_ident(gfx_ctx_ident_t *ident) -{ - if (!ident) - return false; - ident->ident = current_video_context.ident; - return true; -} - -bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info) -{ - video_frame_info_t video_info; - - if (!current_video_context.set_video_mode) - return false; - - video_driver_build_info(&video_info); - - if (!current_video_context.set_video_mode( - video_context_data, &video_info, mode_info->width, - mode_info->height, mode_info->fullscreen)) - return false; - return true; -} - -bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info) -{ - if (!current_video_context.get_video_size) - return false; - current_video_context.get_video_size(video_context_data, - &mode_info->width, &mode_info->height); - return true; -} - -bool video_context_driver_show_mouse(bool *bool_data) -{ - if (!current_video_context.show_mouse) - return false; - current_video_context.show_mouse(video_context_data, *bool_data); - return true; -} - -static bool video_context_driver_get_flags(gfx_ctx_flags_t *flags) -{ - if (!current_video_context.get_flags) - return false; - - if (deferred_video_context_driver_set_flags) - { - flags->flags = deferred_flag_data.flags; - deferred_video_context_driver_set_flags = false; - return true; - } - - flags->flags = current_video_context.get_flags(video_context_data); - return true; -} - -static bool video_driver_get_flags(gfx_ctx_flags_t *flags) -{ - if (!video_driver_poke || !video_driver_poke->get_flags) - return false; - flags->flags = video_driver_poke->get_flags(video_driver_data); - return true; -} - -bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, enum display_flags flag) -{ - if (!flags) - return false; - - if (video_driver_get_flags(flags)) - if (BIT32_GET(flags->flags, flag)) - return true; - - flags->flags = 0; - - if (video_context_driver_get_flags(flags)) - if (BIT32_GET(flags->flags, flag)) - return true; - - return false; -} - -bool video_context_driver_set_flags(gfx_ctx_flags_t *flags) -{ - if (!flags) - return false; - if (!current_video_context.set_flags) - { - deferred_flag_data.flags = flags->flags; - deferred_video_context_driver_set_flags = true; - return false; - } - - current_video_context.set_flags(video_context_data, flags->flags); - return true; -} - -enum gfx_ctx_api video_context_driver_get_api(void) -{ - enum gfx_ctx_api ctx_api = video_context_data ? - current_video_context.get_api(video_context_data) : GFX_CTX_NONE; - - if (ctx_api == GFX_CTX_NONE) - { - const char *video_driver = video_driver_get_ident(); - if (string_is_equal(video_driver, "d3d9")) - return GFX_CTX_DIRECT3D9_API; - else if (string_is_equal(video_driver, "d3d10")) - return GFX_CTX_DIRECT3D10_API; - else if (string_is_equal(video_driver, "d3d11")) - return GFX_CTX_DIRECT3D11_API; - else if (string_is_equal(video_driver, "d3d12")) - return GFX_CTX_DIRECT3D12_API; - else if (string_is_equal(video_driver, "gx2")) - return GFX_CTX_GX2_API; - else if (string_is_equal(video_driver, "gx")) - return GFX_CTX_GX_API; - else if (string_is_equal(video_driver, "gl")) - return GFX_CTX_OPENGL_API; - else if (string_is_equal(video_driver, "vulkan")) - return GFX_CTX_VULKAN_API; - else if (string_is_equal(video_driver, "metal")) - return GFX_CTX_METAL_API; - - return GFX_CTX_NONE; - } - - return ctx_api; -} - -bool video_driver_has_windowed(void) -{ -#if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE)) - if (video_driver_data && current_video->has_windowed) - return current_video->has_windowed(video_driver_data); - else if (video_context_data && current_video_context.has_windowed) - return current_video_context.has_windowed(video_context_data); -#endif - return false; -} - -bool video_driver_cached_frame_has_valid_framebuffer(void) -{ - if (frame_cache_data) - return (frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID); - return false; -} - -static const shader_backend_t *video_shader_set_backend( - enum rarch_shader_type type) -{ - switch (type) - { - case RARCH_SHADER_CG: - { -#ifdef HAVE_CG - gfx_ctx_flags_t flags; - flags.flags = 0; - video_context_driver_get_flags(&flags); - - if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) - { - RARCH_ERR("[Shader driver]: Cg cannot be used with core" - " GL context. Trying to fall back to GLSL...\n"); - return video_shader_set_backend(RARCH_SHADER_GLSL); - } - - RARCH_LOG("[Shader driver]: Using Cg shader backend.\n"); - return &gl_cg_backend; -#else - break; -#endif - } - case RARCH_SHADER_GLSL: -#ifdef HAVE_GLSL - RARCH_LOG("[Shader driver]: Using GLSL shader backend.\n"); - return &gl_glsl_backend; -#else - break; -#endif - case RARCH_SHADER_HLSL: - case RARCH_SHADER_NONE: - default: - break; - } - - return NULL; -} - -bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident) -{ - if (!ident || !current_shader) - return false; - ident->ident = current_shader->ident; - return true; -} - -bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader) -{ - void *video_driver = video_driver_get_ptr(true); - const video_poke_interface_t *video_poke = video_driver_get_poke(); - - shader->data = NULL; - if (!video_poke || !video_driver || !video_poke->get_current_shader) - return false; - shader->data = video_poke->get_current_shader(video_driver); - return true; -} - -bool video_shader_driver_deinit(void) -{ - if (!current_shader) - return false; - - if (current_shader->deinit) - current_shader->deinit(current_shader_data); - - current_shader_data = NULL; - current_shader = NULL; - return true; -} - -static bool video_driver_cb_set_mvp(void *data, - void *shader_data, const void *mat_data) -{ - video_shader_ctx_mvp_t mvp; - mvp.data = data; - mvp.matrix = mat_data; - - video_driver_set_mvp(&mvp); - return true; -} - -static void video_shader_driver_scale_null(void *data, - unsigned idx, struct gfx_fbo_scale *scale) -{ - (void)idx; - (void)scale; -} - -static void video_shader_driver_reset_to_defaults(void) -{ - if (!current_shader) - return; - - if (current_shader->set_mvp) - video_driver_cb_shader_set_mvp = current_shader->set_mvp; - else - { - current_shader->set_mvp = video_driver_cb_set_mvp; - video_driver_cb_shader_set_mvp = video_driver_cb_set_mvp; - } - if (!current_shader->set_coords) - current_shader->set_coords = video_driver_cb_set_coords; - - if (!current_shader->shader_scale) - current_shader->shader_scale = video_shader_driver_scale_null; -} - -/* Finds first suitable shader context driver. */ -bool video_shader_driver_init_first(void) -{ - current_shader = (shader_backend_t*)shader_ctx_drivers[0]; - video_shader_driver_reset_to_defaults(); - return true; -} - -bool video_shader_driver_init(video_shader_ctx_init_t *init) -{ - void *tmp = NULL; - settings_t *settings = config_get_ptr(); - - if (!init->shader || !init->shader->init) - { - init->shader = video_shader_set_backend(init->shader_type); - - if (!init->shader) - return false; - } - - tmp = init->shader->init(init->data, init->path); - - if (!tmp) - return false; - - if (string_is_equal(settings->arrays.menu_driver, "xmb") - && init->shader->init_menu_shaders) - { - RARCH_LOG("Setting up menu pipeline shaders for XMB ... \n"); - init->shader->init_menu_shaders(tmp); - } - - init->shader_data = tmp; - current_shader_data = tmp; - - RARCH_LOG("Resetting shader to defaults ... \n"); - - current_shader = (shader_backend_t*)init->shader; - video_shader_driver_reset_to_defaults(); - - return true; -} - -bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler) -{ - if (!scaler || !scaler->scale) - return false; - - scaler->scale->valid = false; - - current_shader->shader_scale(current_shader_data, - scaler->idx, scaler->scale); - return true; -} - -bool video_shader_driver_info(video_shader_ctx_info_t *shader_info) -{ - if (!shader_info) - return false; - - shader_info->num = current_shader->num_shaders(current_shader_data); - - return true; -} - -void video_driver_set_coords(video_shader_ctx_coords_t *coords) -{ - if (current_shader && current_shader->set_coords) - current_shader->set_coords(coords->handle_data, - current_shader_data, - (const struct video_coords*)coords->data); - else - { - if (video_driver_poke && video_driver_poke->set_coords) - video_driver_poke->set_coords(coords->handle_data, - current_shader_data, - (const struct video_coords*)coords->data); - } -} - -void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp) -{ - if (!mvp || !mvp->matrix) - return; - - if (current_shader && current_shader->set_mvp) - current_shader->set_mvp(mvp->data, - current_shader_data, mvp->matrix); - else - { - if (video_driver_poke && video_driver_poke->set_mvp) - video_driver_poke->set_mvp(mvp->data, - current_shader_data, mvp->matrix); - } -} - -float video_driver_get_refresh_rate(void) -{ - if (video_driver_poke && video_driver_poke->get_refresh_rate) - return video_driver_poke->get_refresh_rate(video_driver_data); - - return 0.0f; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../audio/audio_driver.h" +#include "../menu/menu_shader.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#include "../dynamic.h" + +#ifdef HAVE_THREADS +#include +#endif + +#ifdef HAVE_MENU +#include "../menu/menu_driver.h" +#include "../menu/menu_setting.h" +#endif + +#include "video_thread_wrapper.h" +#include "video_driver.h" +#include "video_display_server.h" +#include "video_crt_switch.h" + +#include "../frontend/frontend_driver.h" +#include "../record/record_driver.h" +#include "../config.def.h" +#include "../configuration.h" +#include "../driver.h" +#include "../retroarch.h" +#include "../input/input_driver.h" +#include "../list_special.h" +#include "../core.h" +#include "../command.h" +#include "../msg_hash.h" +#include "../verbosity.h" + +#define MEASURE_FRAME_TIME_SAMPLES_COUNT (2 * 1024) + +#define TIME_TO_FPS(last_time, new_time, frames) ((1000000.0f * (frames)) / ((new_time) - (last_time))) + +#define FPS_UPDATE_INTERVAL 256 + +#ifdef HAVE_THREADS +#define video_driver_is_threaded_internal() ((!video_driver_is_hw_context() && video_driver_threaded) ? true : false) +#else +#define video_driver_is_threaded_internal() (false) +#endif + +#ifdef HAVE_THREADS +#define video_driver_lock() \ + if (display_lock) \ + slock_lock(display_lock) + +#define video_driver_unlock() \ + if (display_lock) \ + slock_unlock(display_lock) + +#define video_driver_context_lock() \ + if (context_lock) \ + slock_lock(context_lock) + +#define video_driver_context_unlock() \ + if (context_lock) \ + slock_unlock(context_lock) + +#define video_driver_lock_free() \ + slock_free(display_lock); \ + slock_free(context_lock); \ + display_lock = NULL; \ + context_lock = NULL + +#define video_driver_threaded_lock(is_threaded) \ + if (is_threaded) \ + video_driver_lock() + +#define video_driver_threaded_unlock(is_threaded) \ + if (is_threaded) \ + video_driver_unlock() +#else +#define video_driver_lock() ((void)0) +#define video_driver_unlock() ((void)0) +#define video_driver_lock_free() ((void)0) +#define video_driver_threaded_lock(is_threaded) ((void)0) +#define video_driver_threaded_unlock(is_threaded) ((void)0) +#define video_driver_context_lock() ((void)0) +#define video_driver_context_unlock() ((void)0) +#endif + +typedef struct video_pixel_scaler +{ + struct scaler_ctx *scaler; + void *scaler_out; +} video_pixel_scaler_t; + +static bool (*video_driver_cb_shader_set_mvp)(void *data, + void *shader_data, const void *mat_data); +bool (*video_driver_cb_has_focus)(void); + +/* Opaque handles to currently running window. + * Used by e.g. input drivers which bind to a window. + * Drivers are responsible for setting these if an input driver + * could potentially make use of this. */ +static uintptr_t video_driver_display = 0; +static uintptr_t video_driver_window = 0; + +static rarch_softfilter_t *video_driver_state_filter = NULL; +static void *video_driver_state_buffer = NULL; +static unsigned video_driver_state_scale = 0; +static unsigned video_driver_state_out_bpp = 0; +static bool video_driver_state_out_rgb32 = false; +static bool video_driver_crt_switching_active = false; + +static struct retro_system_av_info video_driver_av_info; + +static enum retro_pixel_format video_driver_pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555; + +static const void *frame_cache_data = NULL; +static unsigned frame_cache_width = 0; +static unsigned frame_cache_height = 0; +static size_t frame_cache_pitch = 0; +static bool video_driver_threaded = false; + +static float video_driver_core_hz = 0.0f; +static float video_driver_aspect_ratio = 0.0f; +static unsigned video_driver_width = 0; +static unsigned video_driver_height = 0; + +static enum rarch_display_type video_driver_display_type = RARCH_DISPLAY_NONE; +static char video_driver_title_buf[64] = {0}; +static char video_driver_window_title[512] = {0}; +static bool video_driver_window_title_update = true; + +static retro_time_t video_driver_frame_time_samples[MEASURE_FRAME_TIME_SAMPLES_COUNT]; +static uint64_t video_driver_frame_time_count = 0; +static uint64_t video_driver_frame_count = 0; + +static void *video_driver_data = NULL; +static video_driver_t *current_video = NULL; + +/* Interface for "poking". */ +static const video_poke_interface_t *video_driver_poke = NULL; + +/* Used for 15-bit -> 16-bit conversions that take place before + * being passed to video driver. */ +static video_pixel_scaler_t *video_driver_scaler_ptr = NULL; + +static struct retro_hw_render_callback hw_render; + +static const struct +retro_hw_render_context_negotiation_interface * +hw_render_context_negotiation = NULL; + +/* Graphics driver requires RGBA byte order data (ABGR on little-endian) + * for 32-bit. + * This takes effect for overlay and shader cores that wants to load + * data into graphics driver. Kinda hackish to place it here, it is only + * used for GLES. + * TODO: Refactor this better. */ +static bool video_driver_use_rgba = false; +static bool video_driver_data_own = false; +static bool video_driver_active = false; + +static video_driver_frame_t frame_bak = NULL; + +/* If set during context deinit, the driver should keep + * graphics context alive to avoid having to reset all + * context state. */ +static bool video_driver_cache_context = false; + +/* Set to true by driver if context caching succeeded. */ +static bool video_driver_cache_context_ack = false; +static uint8_t *video_driver_record_gpu_buffer = NULL; + +#ifdef HAVE_THREADS +static slock_t *display_lock = NULL; +static slock_t *context_lock = NULL; +#endif + +static gfx_ctx_driver_t current_video_context; + +static void *video_context_data = NULL; + +/** + * dynamic.c:dynamic_request_hw_context will try to set flag data when the context + * is in the middle of being rebuilt; in these cases we will save flag + * data and set this to true. + * When the context is reinit, it checks this, reads from + * deferred_flag_data and cleans it. + * + * TODO - Dirty hack, fix it better + */ +static bool deferred_video_context_driver_set_flags = false; +static gfx_ctx_flags_t deferred_flag_data = {0}; + +static bool video_started_fullscreen = false; + +static shader_backend_t *current_shader = NULL; +static void *current_shader_data = NULL; + +struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { + { "4:3", 1.3333f }, + { "16:9", 1.7778f }, + { "16:10", 1.6f }, + { "16:15", 16.0f / 15.0f }, + { "21:9", 21.0f / 9.0f }, + { "1:1", 1.0f }, + { "2:1", 2.0f }, + { "3:2", 1.5f }, + { "3:4", 0.75f }, + { "4:1", 4.0f }, + { "9:16", 0.5625f }, + { "5:4", 1.25f }, + { "6:5", 1.2f }, + { "7:9", 0.7777f }, + { "8:3", 2.6666f }, + { "8:7", 1.1428f }, + { "19:12", 1.5833f }, + { "19:14", 1.3571f }, + { "30:17", 1.7647f }, + { "32:9", 3.5555f }, + { "Config", 0.0f }, + { "Square pixel", 1.0f }, + { "Core provided", 1.0f }, + { "Custom", 0.0f } +}; + +static const video_driver_t *video_drivers[] = { +#ifdef HAVE_OPENGL + &video_gl, +#endif +#ifdef HAVE_VULKAN + &video_vulkan, +#endif +#ifdef HAVE_METAL + &video_metal, +#endif +#ifdef XENON + &video_xenon360, +#endif +#if defined(HAVE_D3D12) + &video_d3d12, +#endif +#if defined(HAVE_D3D11) + &video_d3d11, +#endif +#if defined(HAVE_D3D10) + &video_d3d10, +#endif +#if defined(HAVE_D3D9) + &video_d3d9, +#endif +#if defined(HAVE_D3D8) + &video_d3d8, +#endif +#ifdef HAVE_VITA2D + &video_vita2d, +#endif +#ifdef PSP + &video_psp1, +#endif +#ifdef PS2 + &video_ps2, +#endif +#ifdef _3DS + &video_ctr, +#endif +#ifdef SWITCH + &video_switch, +#endif +#ifdef HAVE_SDL + &video_sdl, +#endif +#ifdef HAVE_SDL2 + &video_sdl2, +#endif +#ifdef HAVE_XVIDEO + &video_xvideo, +#endif +#ifdef GEKKO + &video_gx, +#endif +#ifdef WIIU + &video_wiiu, +#endif +#ifdef HAVE_VG + &video_vg, +#endif +#ifdef HAVE_OMAP + &video_omap, +#endif +#ifdef HAVE_EXYNOS + &video_exynos, +#endif +#ifdef HAVE_DISPMANX + &video_dispmanx, +#endif +#ifdef HAVE_SUNXI + &video_sunxi, +#endif +#ifdef HAVE_PLAIN_DRM + &video_drm, +#endif +#ifdef HAVE_XSHM + &video_xshm, +#endif +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) + &video_gdi, +#endif +#ifdef DJGPP + &video_vga, +#endif +#ifdef HAVE_SIXEL + &video_sixel, +#endif +#ifdef HAVE_CACA + &video_caca, +#endif + &video_null, + NULL, +}; + +static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { +#if defined(ORBIS) + &orbis_ctx, +#endif +#if defined(HAVE_LIBNX) && defined(HAVE_OPENGL) + &switch_ctx, +#endif +#if defined(__CELLOS_LV2__) + &gfx_ctx_ps3, +#endif +#if defined(HAVE_VIDEOCORE) + &gfx_ctx_videocore, +#endif +#if defined(HAVE_MALI_FBDEV) + &gfx_ctx_mali_fbdev, +#endif +#if defined(HAVE_VIVANTE_FBDEV) + &gfx_ctx_vivante_fbdev, +#endif +#if defined(HAVE_OPENDINGUX_FBDEV) + &gfx_ctx_opendingux_fbdev, +#endif +#if defined(_WIN32) && (defined(HAVE_OPENGL) || defined(HAVE_VULKAN)) + &gfx_ctx_wgl, +#endif +#if defined(HAVE_WAYLAND) + &gfx_ctx_wayland, +#endif +#if defined(HAVE_X11) && !defined(HAVE_OPENGLES) +#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) + &gfx_ctx_x, +#endif +#endif +#if defined(HAVE_X11) && defined(HAVE_OPENGL) && defined(HAVE_EGL) + &gfx_ctx_x_egl, +#endif +#if defined(HAVE_KMS) + &gfx_ctx_drm, +#endif +#if defined(ANDROID) + &gfx_ctx_android, +#endif +#if defined(__QNX__) + &gfx_ctx_qnx, +#endif +#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) + &gfx_ctx_cocoagl, +#endif +#if defined(__APPLE__) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE) + &gfx_ctx_cgl, +#endif +#if (defined(HAVE_SDL) || defined(HAVE_SDL2)) && defined(HAVE_OPENGL) + &gfx_ctx_sdl_gl, +#endif +#ifdef HAVE_OSMESA + &gfx_ctx_osmesa, +#endif +#ifdef EMSCRIPTEN + &gfx_ctx_emscripten, +#endif +#if defined(HAVE_VULKAN) && defined(HAVE_VULKAN_DISPLAY) + &gfx_ctx_khr_display, +#endif +#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) + &gfx_ctx_gdi, +#endif +#ifdef HAVE_SIXEL + &gfx_ctx_sixel, +#endif + &gfx_ctx_null, + NULL +}; + +static const shader_backend_t *shader_ctx_drivers[] = { +#ifdef HAVE_GLSL + &gl_glsl_backend, +#endif +#ifdef HAVE_CG + &gl_cg_backend, +#endif + &shader_null_backend, + NULL +}; + +bool video_driver_started_fullscreen(void) +{ + return video_started_fullscreen; +} + +/* Stub functions */ + +static void update_window_title_null(void *data, void *data2) +{ +} + +static void swap_buffers_null(void *data, void *data2) +{ +} + +static bool get_metrics_null(void *data, enum display_metric_types type, + float *value) +{ + return false; +} + +static bool set_resize_null(void *a, unsigned b, unsigned c) +{ + return false; +} + +/** + * video_driver_find_handle: + * @idx : index of driver to get handle to. + * + * Returns: handle to video driver at index. Can be NULL + * if nothing found. + **/ +const void *video_driver_find_handle(int idx) +{ + const void *drv = video_drivers[idx]; + if (!drv) + return NULL; + return drv; +} + +/** + * video_driver_find_ident: + * @idx : index of driver to get handle to. + * + * Returns: Human-readable identifier of video driver at index. Can be NULL + * if nothing found. + **/ +const char *video_driver_find_ident(int idx) +{ + const video_driver_t *drv = video_drivers[idx]; + if (!drv) + return NULL; + return drv->ident; +} + +/** + * config_get_video_driver_options: + * + * Get an enumerated list of all video driver names, separated by '|'. + * + * Returns: string listing of all video driver names, separated by '|'. + **/ +const char* config_get_video_driver_options(void) +{ + return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL); +} + +bool video_driver_is_threaded(void) +{ + return video_driver_is_threaded_internal(); +} + +#ifdef HAVE_VULKAN +static bool hw_render_context_is_vulkan(enum retro_hw_context_type type) +{ + return type == RETRO_HW_CONTEXT_VULKAN; +} +#endif + +#if defined(HAVE_OPENGL) +static bool hw_render_context_is_gl(enum retro_hw_context_type type) +{ + switch (type) + { + case RETRO_HW_CONTEXT_OPENGL: + case RETRO_HW_CONTEXT_OPENGLES2: + case RETRO_HW_CONTEXT_OPENGL_CORE: + case RETRO_HW_CONTEXT_OPENGLES3: + case RETRO_HW_CONTEXT_OPENGLES_VERSION: + return true; + default: + break; + } + + return false; +} +#endif + +bool *video_driver_get_threaded(void) +{ + return &video_driver_threaded; +} + +void video_driver_set_threaded(bool val) +{ + video_driver_threaded = val; +} + +/** + * video_driver_get_ptr: + * + * Use this if you need the real video driver + * and driver data pointers. + * + * Returns: video driver's userdata. + **/ +void *video_driver_get_ptr(bool force_nonthreaded_data) +{ +#ifdef HAVE_THREADS + if (video_driver_is_threaded_internal() && !force_nonthreaded_data) + return video_thread_get_ptr(NULL); +#endif + + return video_driver_data; +} + +const char *video_driver_get_ident(void) +{ + return (current_video) ? current_video->ident : NULL; +} + +const video_poke_interface_t *video_driver_get_poke(void) +{ + return video_driver_poke; +} + +static bool video_context_has_focus(void) +{ + return current_video_context.has_focus && current_video_context.has_focus(video_context_data); +} + +static bool video_driver_has_focus(void) +{ + return current_video && current_video->focus && current_video->focus(video_driver_data); +} + +static bool null_driver_has_focus(void) +{ + return true; +} + +static void video_context_driver_reset(void) +{ + if (!current_video_context.get_metrics) + current_video_context.get_metrics = get_metrics_null; + + if (!current_video_context.update_window_title) + current_video_context.update_window_title = update_window_title_null; + + if (!current_video_context.set_resize) + current_video_context.set_resize = set_resize_null; + + if (!current_video_context.swap_buffers) + current_video_context.swap_buffers = swap_buffers_null; + + if (current_video_context.has_focus) + video_driver_cb_has_focus = video_context_has_focus; + +} + +bool video_context_driver_set(const gfx_ctx_driver_t *data) +{ + if (!data) + return false; + current_video_context = *data; + video_context_driver_reset(); + return true; +} + +void video_context_driver_destroy(void) +{ + current_video_context.init = NULL; + current_video_context.bind_api = NULL; + current_video_context.swap_interval = NULL; + current_video_context.set_video_mode = NULL; + current_video_context.get_video_size = NULL; + current_video_context.get_video_output_size = NULL; + current_video_context.get_video_output_prev = NULL; + current_video_context.get_video_output_next = NULL; + current_video_context.get_metrics = get_metrics_null; + current_video_context.translate_aspect = NULL; + current_video_context.update_window_title = update_window_title_null; + current_video_context.check_window = NULL; + current_video_context.set_resize = set_resize_null; + current_video_context.has_focus = NULL; + current_video_context.suppress_screensaver = NULL; + current_video_context.has_windowed = NULL; + current_video_context.swap_buffers = swap_buffers_null; + current_video_context.input_driver = NULL; + current_video_context.get_proc_address = NULL; + current_video_context.image_buffer_init = NULL; + current_video_context.image_buffer_write = NULL; + current_video_context.show_mouse = NULL; + current_video_context.ident = NULL; + current_video_context.get_flags = NULL; + current_video_context.set_flags = NULL; + current_video_context.bind_hw_render = NULL; + current_video_context.get_context_data = NULL; + current_video_context.make_current = NULL; +} + +/** + * video_driver_get_current_framebuffer: + * + * Gets pointer to current hardware renderer framebuffer object. + * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. + * + * Returns: pointer to hardware framebuffer object, otherwise 0. + **/ +uintptr_t video_driver_get_current_framebuffer(void) +{ + if (video_driver_poke && video_driver_poke->get_current_framebuffer) + return video_driver_poke->get_current_framebuffer(video_driver_data); + return 0; +} + +retro_proc_address_t video_driver_get_proc_address(const char *sym) +{ + if (video_driver_poke && video_driver_poke->get_proc_address) + return video_driver_poke->get_proc_address(video_driver_data, sym); + return NULL; +} + +bool video_driver_set_shader(enum rarch_shader_type type, + const char *path) +{ + if (current_video->set_shader) + return current_video->set_shader(video_driver_data, type, path); + return false; +} + +static void video_driver_filter_free(void) +{ + if (video_driver_state_filter) + rarch_softfilter_free(video_driver_state_filter); + video_driver_state_filter = NULL; + + if (video_driver_state_buffer) + { +#ifdef _3DS + linearFree(video_driver_state_buffer); +#else + free(video_driver_state_buffer); +#endif + } + video_driver_state_buffer = NULL; + + video_driver_state_scale = 0; + video_driver_state_out_bpp = 0; + video_driver_state_out_rgb32 = false; +} + +static void video_driver_init_filter(enum retro_pixel_format colfmt_int) +{ + unsigned pow2_x, pow2_y, maxsize; + void *buf = NULL; + settings_t *settings = config_get_ptr(); + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + unsigned width = geom->max_width; + unsigned height = geom->max_height; + /* Deprecated format. Gets pre-converted. */ + enum retro_pixel_format colfmt = + (colfmt_int == RETRO_PIXEL_FORMAT_0RGB1555) ? + RETRO_PIXEL_FORMAT_RGB565 : colfmt_int; + + if (video_driver_is_hw_context()) + { + RARCH_WARN("Cannot use CPU filters when hardware rendering is used.\n"); + return; + } + + video_driver_state_filter = rarch_softfilter_new( + settings->paths.path_softfilter_plugin, + RARCH_SOFTFILTER_THREADS_AUTO, colfmt, width, height); + + if (!video_driver_state_filter) + { + RARCH_ERR("[Video]: Failed to load filter.\n"); + return; + } + + rarch_softfilter_get_max_output_size(video_driver_state_filter, + &width, &height); + + pow2_x = next_pow2(width); + pow2_y = next_pow2(height); + maxsize = MAX(pow2_x, pow2_y); + video_driver_state_scale = maxsize / RARCH_SCALE_BASE; + video_driver_state_out_rgb32 = rarch_softfilter_get_output_format( + video_driver_state_filter) == + RETRO_PIXEL_FORMAT_XRGB8888; + + video_driver_state_out_bpp = video_driver_state_out_rgb32 ? + sizeof(uint32_t) : + sizeof(uint16_t); + + /* TODO: Aligned output. */ +#ifdef _3DS + buf = linearMemAlign( + width * height * video_driver_state_out_bpp, 0x80); +#else + buf = malloc( + width * height * video_driver_state_out_bpp); +#endif + if (!buf) + { + RARCH_ERR("[Video]: Softfilter initialization failed.\n"); + video_driver_filter_free(); + return; + } + + video_driver_state_buffer = buf; +} + +static void video_driver_init_input(const input_driver_t *tmp) +{ + const input_driver_t **input = input_get_double_ptr(); + if (*input) + return; + + /* Video driver didn't provide an input driver, + * so we use configured one. */ + RARCH_LOG("[Video]: Graphics driver did not initialize an input driver." + " Attempting to pick a suitable driver.\n"); + + if (tmp) + *input = tmp; + else + input_driver_find_driver(); + + /* This should never really happen as tmp (driver.input) is always + * found before this in find_driver_input(), or we have aborted + * in a similar fashion anyways. */ + if (!input_get_ptr()) + goto error; + + if (input_driver_init()) + return; + +error: + RARCH_ERR("[Video]: Cannot initialize input driver. Exiting ...\n"); + retroarch_fail(1, "video_driver_init_input()"); +} + +/** + * video_driver_monitor_compute_fps_statistics: + * + * Computes monitor FPS statistics. + **/ +static void video_driver_monitor_compute_fps_statistics(void) +{ + double avg_fps = 0.0; + double stddev = 0.0; + unsigned samples = 0; + + if (video_driver_frame_time_count < + (2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)) + { + RARCH_LOG( + "[Video]: Does not have enough samples for monitor refresh rate" + " estimation. Requires to run for at least %u frames.\n", + 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT); + return; + } + + if (video_monitor_fps_statistics(&avg_fps, &stddev, &samples)) + { + RARCH_LOG("[Video]: Average monitor Hz: %.6f Hz. (%.3f %% frame time" + " deviation, based on %u last samples).\n", + avg_fps, 100.0 * stddev, samples); + } +} + +static void video_driver_pixel_converter_free(void) +{ + if (!video_driver_scaler_ptr) + return; + + scaler_ctx_gen_reset(video_driver_scaler_ptr->scaler); + + if (video_driver_scaler_ptr->scaler) + free(video_driver_scaler_ptr->scaler); + video_driver_scaler_ptr->scaler = NULL; + + if (video_driver_scaler_ptr->scaler_out) + free(video_driver_scaler_ptr->scaler_out); + video_driver_scaler_ptr->scaler_out = NULL; + + if (video_driver_scaler_ptr) + free(video_driver_scaler_ptr); + video_driver_scaler_ptr = NULL; +} + +static void video_driver_free_internal(void) +{ +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); +#endif + + command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); + + if (!video_driver_is_video_cache_context()) + video_driver_free_hw_context(); + + if ( + !input_driver_owns_driver() && + !input_driver_is_data_ptr_same(video_driver_data) + ) + input_driver_deinit(); + + if ( + !video_driver_data_own + && video_driver_data + && current_video && current_video->free + ) + current_video->free(video_driver_data); + + video_driver_pixel_converter_free(); + video_driver_filter_free(); + + command_event(CMD_EVENT_SHADER_DIR_DEINIT, NULL); + +#ifdef HAVE_THREADS + if (is_threaded) + return; +#endif + + video_driver_monitor_compute_fps_statistics(); +} + +static bool video_driver_pixel_converter_init(unsigned size) +{ + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); + void *scalr_out = NULL; + video_pixel_scaler_t *scalr = NULL; + struct scaler_ctx *scalr_ctx = NULL; + + /* If pixel format is not 0RGB1555, we don't need to do + * any internal pixel conversion. */ + if (video_driver_pix_fmt != RETRO_PIXEL_FORMAT_0RGB1555) + return true; + + /* No need to perform pixel conversion for HW rendering contexts. */ + if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) + return true; + + RARCH_WARN("0RGB1555 pixel format is deprecated," + " and will be slower. For 15/16-bit, RGB565" + " format is preferred.\n"); + + scalr = (video_pixel_scaler_t*)calloc(1, sizeof(*scalr)); + + if (!scalr) + goto error; + + video_driver_scaler_ptr = scalr; + + scalr_ctx = (struct scaler_ctx*)calloc(1, sizeof(*scalr_ctx)); + + if (!scalr_ctx) + goto error; + + video_driver_scaler_ptr->scaler = scalr_ctx; + video_driver_scaler_ptr->scaler->scaler_type = SCALER_TYPE_POINT; + video_driver_scaler_ptr->scaler->in_fmt = SCALER_FMT_0RGB1555; + + /* TODO: Pick either ARGB8888 or RGB565 depending on driver. */ + video_driver_scaler_ptr->scaler->out_fmt = SCALER_FMT_RGB565; + + if (!scaler_ctx_gen_filter(scalr_ctx)) + goto error; + + scalr_out = calloc(sizeof(uint16_t), size * size); + + if (!scalr_out) + goto error; + + video_driver_scaler_ptr->scaler_out = scalr_out; + + return true; + +error: + video_driver_pixel_converter_free(); + video_driver_filter_free(); + + return false; +} + +static bool video_driver_init_internal(bool *video_is_threaded) +{ + video_info_t video; + unsigned max_dim, scale, width, height; + video_viewport_t *custom_vp = NULL; + const input_driver_t *tmp = NULL; + rarch_system_info_t *system = NULL; + static uint16_t dummy_pixels[32] = {0}; + settings_t *settings = config_get_ptr(); + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + + if (!string_is_empty(settings->paths.path_softfilter_plugin)) + video_driver_init_filter(video_driver_pix_fmt); + + max_dim = MAX(geom->max_width, geom->max_height); + scale = next_pow2(max_dim) / RARCH_SCALE_BASE; + scale = MAX(scale, 1); + + if (video_driver_state_filter) + scale = video_driver_state_scale; + + /* Update core-dependent aspect ratio values. */ + video_driver_set_viewport_square_pixel(); + video_driver_set_viewport_core(); + video_driver_set_viewport_config(); + + /* Update CUSTOM viewport. */ + custom_vp = video_viewport_get_custom(); + + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; + aspectratio_lut[ASPECT_RATIO_CUSTOM].value = + (custom_vp->width && custom_vp->height) ? + (float)custom_vp->width / custom_vp->height : default_aspect; + } + + video_driver_set_aspect_ratio_value( + aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); + + if (settings->bools.video_fullscreen|| retroarch_is_forced_fullscreen()) + { + width = settings->uints.video_fullscreen_x; + height = settings->uints.video_fullscreen_y; + } + else + { + /* To-Do: remove when the new window resizing core is hooked */ + if (settings->bools.video_window_save_positions && + (settings->uints.window_position_width || settings->uints.window_position_height)) + { + width = settings->uints.window_position_width; + height = settings->uints.window_position_height; + } + else + { + if (settings->bools.video_force_aspect) + { + /* Do rounding here to simplify integer scale correctness. */ + unsigned base_width = + roundf(geom->base_height * video_driver_get_aspect_ratio()); + width = roundf(base_width * settings->floats.video_scale); + } + else + width = roundf(geom->base_width * settings->floats.video_scale); + height = roundf(geom->base_height * settings->floats.video_scale); +} + } + + if (width && height) + RARCH_LOG("[Video]: Video @ %ux%u\n", width, height); + else + RARCH_LOG("[Video]: Video @ fullscreen\n"); + + video_driver_display_type_set(RARCH_DISPLAY_NONE); + video_driver_display_set(0); + video_driver_window_set(0); + + if (!video_driver_pixel_converter_init(RARCH_SCALE_BASE * scale)) + { + RARCH_ERR("[Video]: Failed to initialize pixel converter.\n"); + goto error; + } + + video.width = width; + video.height = height; + video.fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); + video.vsync = settings->bools.video_vsync && !rarch_ctl(RARCH_CTL_IS_NONBLOCK_FORCED, NULL); + video.force_aspect = settings->bools.video_force_aspect; + video.font_enable = settings->bools.video_font_enable; + video.swap_interval = settings->uints.video_swap_interval; +#ifdef GEKKO + video.viwidth = settings->uints.video_viwidth; + video.vfilter = settings->bools.video_vfilter; +#endif + video.smooth = settings->bools.video_smooth; + video.input_scale = scale; + video.rgb32 = video_driver_state_filter ? + video_driver_state_out_rgb32 : + (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); + video.parent = 0; + + video_started_fullscreen = video.fullscreen; + + /* Reset video frame count */ + video_driver_frame_count = 0; + + tmp = input_get_ptr(); + /* Need to grab the "real" video driver interface on a reinit. */ + video_driver_find_driver(); + +#ifdef HAVE_THREADS + video.is_threaded = video_driver_is_threaded_internal(); + *video_is_threaded = video.is_threaded; + + if (video.is_threaded) + { + /* Can't do hardware rendering with threaded driver currently. */ + RARCH_LOG("[Video]: Starting threaded video driver ...\n"); + + if (!video_init_thread((const video_driver_t**)¤t_video, + &video_driver_data, + input_get_double_ptr(), input_driver_get_data_ptr(), + current_video, video)) + { + RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n"); + goto error; + } + } + else +#endif + video_driver_data = current_video->init( + &video, input_get_double_ptr(), + input_driver_get_data_ptr()); + + if (!video_driver_data) + { + RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n"); + goto error; + } + + if (current_video->focus) + video_driver_cb_has_focus = video_driver_has_focus; + + video_driver_poke = NULL; + if (current_video->poke_interface) + current_video->poke_interface(video_driver_data, &video_driver_poke); + + if (current_video->viewport_info && + (!custom_vp->width || + !custom_vp->height)) + { + /* Force custom viewport to have sane parameters. */ + custom_vp->width = width; + custom_vp->height = height; + + video_driver_get_viewport_info(custom_vp); + } + + system = runloop_get_system_info(); + + video_driver_set_rotation( + (settings->uints.video_rotation + system->rotation) % 4); + + current_video->suppress_screensaver(video_driver_data, + settings->bools.ui_suspend_screensaver_enable); + + video_driver_init_input(tmp); + + command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); + command_event(CMD_EVENT_OVERLAY_INIT, NULL); + + if (!core_is_game_loaded()) + video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8); + +#if defined(PSP) + video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f); +#endif + + video_context_driver_reset(); + + video_display_server_init(); + + command_event(CMD_EVENT_SHADER_DIR_INIT, NULL); + + return true; + +error: + retroarch_fail(1, "init_video()"); + return false; +} + +bool video_driver_set_viewport(unsigned width, unsigned height, + bool force_fullscreen, bool allow_rotate) +{ + if (!current_video || !current_video->set_viewport) + return false; + current_video->set_viewport(video_driver_data, width, height, + force_fullscreen, allow_rotate); + return true; +} + +bool video_driver_set_rotation(unsigned rotation) +{ + if (!current_video || !current_video->set_rotation) + return false; + current_video->set_rotation(video_driver_data, rotation); + return true; +} + +bool video_driver_set_video_mode(unsigned width, + unsigned height, bool fullscreen) +{ + gfx_ctx_mode_t mode; + + if (video_driver_poke && video_driver_poke->set_video_mode) + { + video_driver_poke->set_video_mode(video_driver_data, + width, height, fullscreen); + return true; + } + + mode.width = width; + mode.height = height; + mode.fullscreen = fullscreen; + + return video_context_driver_set_video_mode(&mode); +} + +bool video_driver_get_video_output_size(unsigned *width, unsigned *height) +{ + if (!video_driver_poke || !video_driver_poke->get_video_output_size) + return false; + video_driver_poke->get_video_output_size(video_driver_data, + width, height); + return true; +} + +void video_driver_set_osd_msg(const char *msg, const void *data, void *font) +{ + video_frame_info_t video_info; + video_driver_build_info(&video_info); + if (video_driver_poke && video_driver_poke->set_osd_msg) + video_driver_poke->set_osd_msg(video_driver_data, &video_info, msg, data, font); +} + +void video_driver_set_texture_enable(bool enable, bool fullscreen) +{ + if (video_driver_poke && video_driver_poke->set_texture_enable) + video_driver_poke->set_texture_enable(video_driver_data, + enable, fullscreen); +} + +void video_driver_set_texture_frame(const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha) +{ + if (video_driver_poke && video_driver_poke->set_texture_frame) + video_driver_poke->set_texture_frame(video_driver_data, + frame, rgb32, width, height, alpha); +} + +#ifdef HAVE_OVERLAY +bool video_driver_overlay_interface(const video_overlay_interface_t **iface) +{ + if (!current_video || !current_video->overlay_interface) + return false; + current_video->overlay_interface(video_driver_data, iface); + return true; +} +#endif + +void *video_driver_read_frame_raw(unsigned *width, + unsigned *height, size_t *pitch) +{ + if (!current_video || !current_video->read_frame_raw) + return NULL; + return current_video->read_frame_raw(video_driver_data, width, + height, pitch); +} + +void video_driver_set_filtering(unsigned index, bool smooth) +{ + if (video_driver_poke && video_driver_poke->set_filtering) + video_driver_poke->set_filtering(video_driver_data, index, smooth); +} + +void video_driver_cached_frame_set(const void *data, unsigned width, + unsigned height, size_t pitch) +{ + if (data) + frame_cache_data = data; + frame_cache_width = width; + frame_cache_height = height; + frame_cache_pitch = pitch; +} + +void video_driver_cached_frame_get(const void **data, unsigned *width, + unsigned *height, size_t *pitch) +{ + if (data) + *data = frame_cache_data; + if (width) + *width = frame_cache_width; + if (height) + *height = frame_cache_height; + if (pitch) + *pitch = frame_cache_pitch; +} + +void video_driver_get_size(unsigned *width, unsigned *height) +{ +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); + video_driver_threaded_lock(is_threaded); +#endif + if (width) + *width = video_driver_width; + if (height) + *height = video_driver_height; +#ifdef HAVE_THREADS + video_driver_threaded_unlock(is_threaded); +#endif +} + +void video_driver_set_size(unsigned *width, unsigned *height) +{ +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); + video_driver_threaded_lock(is_threaded); +#endif + if (width) + video_driver_width = *width; + if (height) + video_driver_height = *height; +#ifdef HAVE_THREADS + video_driver_threaded_unlock(is_threaded); +#endif +} + +/** + * video_monitor_set_refresh_rate: + * @hz : New refresh rate for monitor. + * + * Sets monitor refresh rate to new value. + **/ +void video_monitor_set_refresh_rate(float hz) +{ + char msg[128]; + settings_t *settings = config_get_ptr(); + + snprintf(msg, sizeof(msg), + "Setting refresh rate to: %.3f Hz.", hz); + runloop_msg_queue_push(msg, 1, 180, false); + RARCH_LOG("%s\n", msg); + + configuration_set_float(settings, + settings->floats.video_refresh_rate, + hz); +} + +/** + * video_monitor_fps_statistics + * @refresh_rate : Monitor refresh rate. + * @deviation : Deviation from measured refresh rate. + * @sample_points : Amount of sampled points. + * + * Gets the monitor FPS statistics based on the current + * runtime. + * + * Returns: true (1) on success. + * false (0) if: + * a) threaded video mode is enabled + * b) less than 2 frame time samples. + * c) FPS monitor enable is off. + **/ +bool video_monitor_fps_statistics(double *refresh_rate, + double *deviation, unsigned *sample_points) +{ + unsigned i; + retro_time_t accum = 0; + retro_time_t avg = 0; + retro_time_t accum_var = 0; + unsigned samples = 0; + +#ifdef HAVE_THREADS + if (video_driver_is_threaded_internal()) + return false; +#endif + + samples = MIN(MEASURE_FRAME_TIME_SAMPLES_COUNT, + (unsigned)video_driver_frame_time_count); + + if (samples < 2) + return false; + + /* Measure statistics on frame time (microsecs), *not* FPS. */ + for (i = 0; i < samples; i++) + { + accum += video_driver_frame_time_samples[i]; +#if 0 + RARCH_LOG("[Video]: Interval #%u: %d usec / frame.\n", + i, (int)frame_time_samples[i]); +#endif + } + + avg = accum / samples; + + /* Drop first measurement. It is likely to be bad. */ + for (i = 0; i < samples; i++) + { + retro_time_t diff = video_driver_frame_time_samples[i] - avg; + accum_var += diff * diff; + } + + *deviation = sqrt((double)accum_var / (samples - 1)) / avg; + + if (refresh_rate) + *refresh_rate = 1000000.0 / avg; + + if (sample_points) + *sample_points = samples; + + return true; +} + +float video_driver_get_aspect_ratio(void) +{ + return video_driver_aspect_ratio; +} + +void video_driver_set_aspect_ratio_value(float value) +{ + video_driver_aspect_ratio = value; +} + +static bool video_driver_frame_filter( + const void *data, + video_frame_info_t *video_info, + unsigned width, unsigned height, + size_t pitch, + unsigned *output_width, unsigned *output_height, + unsigned *output_pitch) +{ + rarch_softfilter_get_output_size(video_driver_state_filter, + output_width, output_height, width, height); + + *output_pitch = (*output_width) * video_driver_state_out_bpp; + + rarch_softfilter_process(video_driver_state_filter, + video_driver_state_buffer, *output_pitch, + data, width, height, pitch); + + if (video_info->post_filter_record && recording_data) + recording_dump_frame(video_driver_state_buffer, + *output_width, *output_height, *output_pitch, + video_info->runloop_is_idle); + + return true; +} + +rarch_softfilter_t *video_driver_frame_filter_get_ptr(void) +{ + return video_driver_state_filter; +} + +enum retro_pixel_format video_driver_get_pixel_format(void) +{ + return video_driver_pix_fmt; +} + +void video_driver_set_pixel_format(enum retro_pixel_format fmt) +{ + video_driver_pix_fmt = fmt; +} + +/** + * video_driver_cached_frame: + * + * Renders the current video frame. + **/ +bool video_driver_cached_frame(void) +{ + void *recording = recording_driver_get_data_ptr(); + + recording_driver_lock(); + + /* Cannot allow recording when pushing duped frames. */ + recording_data = NULL; + + retro_ctx.frame_cb( + (frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID) + ? frame_cache_data : NULL, + frame_cache_width, + frame_cache_height, frame_cache_pitch); + + recording_data = recording; + + recording_driver_unlock(); + + return true; +} + +void video_driver_monitor_adjust_system_rates(void) +{ + float timing_skew = 0.0f; + settings_t *settings = config_get_ptr(); + float video_refresh_rate = settings->floats.video_refresh_rate; + float timing_skew_hz = video_refresh_rate; + const struct retro_system_timing *info = (const struct retro_system_timing*)&video_driver_av_info.timing; + + rarch_ctl(RARCH_CTL_UNSET_NONBLOCK_FORCED, NULL); + + if (!info || info->fps <= 0.0) + return; + + video_driver_core_hz = info->fps; + + if (video_driver_crt_switching_active) + timing_skew_hz = video_driver_core_hz; + timing_skew = fabs( + 1.0f - info->fps / timing_skew_hz); + + if (!settings->bools.vrr_runloop_enable) + { + /* We don't want to adjust pitch too much. If we have extreme cases, + * just don't readjust at all. */ + if (timing_skew <= settings->floats.audio_max_timing_skew) + return; + + RARCH_LOG("[Video]: Timings deviate too much. Will not adjust." + " (Display = %.2f Hz, Game = %.2f Hz)\n", + video_refresh_rate, + (float)info->fps); + } + + if (info->fps <= timing_skew_hz) + return; + + /* We won't be able to do VSync reliably when game FPS > monitor FPS. */ + rarch_ctl(RARCH_CTL_SET_NONBLOCK_FORCED, NULL); + RARCH_LOG("[Video]: Game FPS > Monitor FPS. Cannot rely on VSync.\n"); +} + +void video_driver_menu_settings(void **list_data, void *list_info_data, + void *group_data, void *subgroup_data, const char *parent_group) +{ +#ifdef HAVE_MENU + rarch_setting_t **list = (rarch_setting_t**)list_data; + rarch_setting_info_t *list_info = (rarch_setting_info_t*)list_info_data; + rarch_setting_group_info_t *group_info = (rarch_setting_group_info_t*)group_data; + rarch_setting_group_info_t *subgroup_info = (rarch_setting_group_info_t*)subgroup_data; + global_t *global = global_get_ptr(); + + (void)list; + (void)list_info; + (void)group_info; + (void)subgroup_info; + (void)global; + +#if defined(__CELLOS_LV2__) + CONFIG_BOOL( + list, list_info, + &global->console.screen.pal60_enable, + MENU_ENUM_LABEL_PAL60_ENABLE, + MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); +#endif +#if defined(GEKKO) || defined(_XBOX360) + CONFIG_UINT( + list, list_info, + &global->console.screen.gamma_correction, + MENU_ENUM_LABEL_VIDEO_GAMMA, + MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, + 0, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_cmd( + list, + list_info, + CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); + menu_settings_list_current_add_range( + list, + list_info, + 0, + MAX_GAMMA_SETTING, + 1, + true, + true); + settings_data_list_current_add_flags(list, list_info, + SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); +#endif +#if defined(_XBOX1) || defined(HW_RVL) + CONFIG_BOOL( + list, list_info, + &global->console.softfilter_enable, + MENU_ENUM_LABEL_VIDEO_SOFT_FILTER, + MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + menu_settings_list_current_add_cmd( + list, + list_info, + CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); +#endif +#ifdef _XBOX1 + CONFIG_UINT( + list, list_info, + &global->console.screen.flicker_filter_index, + MENU_ENUM_LABEL_VIDEO_FILTER_FLICKER, + MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, + 0, + group_info, + subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + menu_settings_list_current_add_range(list, list_info, + 0, 5, 1, true, true); +#endif +#endif +} + +static void video_driver_lock_new(void) +{ + video_driver_lock_free(); +#ifdef HAVE_THREADS + if (!display_lock) + display_lock = slock_new(); + retro_assert(display_lock); + + if (!context_lock) + context_lock = slock_new(); + retro_assert(context_lock); +#endif +} + +void video_driver_destroy(void) +{ + video_display_server_destroy(); + crt_video_restore(); + + video_driver_cb_has_focus = null_driver_has_focus; + video_driver_use_rgba = false; + video_driver_data_own = false; + video_driver_active = false; + video_driver_cache_context = false; + video_driver_cache_context_ack = false; + video_driver_record_gpu_buffer = NULL; + current_video = NULL; + video_driver_set_cached_frame_ptr(NULL); +} + +void video_driver_set_cached_frame_ptr(const void *data) +{ + if (data) + frame_cache_data = data; +} + +void video_driver_set_stub_frame(void) +{ + frame_bak = current_video->frame; + current_video->frame = video_null.frame; +} + +void video_driver_unset_stub_frame(void) +{ + if (frame_bak != NULL) + current_video->frame = frame_bak; + + frame_bak = NULL; +} + +bool video_driver_is_stub_frame(void) +{ + return current_video->frame == video_null.frame; +} + +bool video_driver_supports_recording(void) +{ + settings_t *settings = config_get_ptr(); + return settings->bools.video_gpu_record + && current_video->read_viewport; +} + +bool video_driver_supports_viewport_read(void) +{ + settings_t *settings = config_get_ptr(); + return (settings->bools.video_gpu_screenshot || + (video_driver_is_hw_context() && !current_video->read_frame_raw)) + && current_video->read_viewport && current_video->viewport_info; +} + +bool video_driver_supports_read_frame_raw(void) +{ + if (current_video->read_frame_raw) + return true; + return false; +} + +void video_driver_set_viewport_config(void) +{ + settings_t *settings = config_get_ptr(); + + if (settings->floats.video_aspect_ratio < 0.0f) + { + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + + if (geom->aspect_ratio > 0.0f && + settings->bools.video_aspect_ratio_auto) + aspectratio_lut[ASPECT_RATIO_CONFIG].value = geom->aspect_ratio; + else + { + unsigned base_width = geom->base_width; + unsigned base_height = geom->base_height; + + /* Get around division by zero errors */ + if (base_width == 0) + base_width = 1; + if (base_height == 0) + base_height = 1; + aspectratio_lut[ASPECT_RATIO_CONFIG].value = + (float)base_width / base_height; /* 1:1 PAR. */ + } + } + else + { + aspectratio_lut[ASPECT_RATIO_CONFIG].value = + settings->floats.video_aspect_ratio; + } +} + +void video_driver_set_viewport_square_pixel(void) +{ + unsigned len, highest, i, aspect_x, aspect_y; + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + unsigned width = geom->base_width; + unsigned height = geom->base_height; + + if (width == 0 || height == 0) + return; + + len = MIN(width, height); + highest = 1; + + for (i = 1; i < len; i++) + { + if ((width % i) == 0 && (height % i) == 0) + highest = i; + } + + aspect_x = width / highest; + aspect_y = height / highest; + + snprintf(aspectratio_lut[ASPECT_RATIO_SQUARE].name, + sizeof(aspectratio_lut[ASPECT_RATIO_SQUARE].name), + "1:1 PAR (%u:%u DAR)", aspect_x, aspect_y); + + aspectratio_lut[ASPECT_RATIO_SQUARE].value = (float)aspect_x / aspect_y; +} + +void video_driver_set_viewport_core(void) +{ + struct retro_game_geometry *geom = &video_driver_av_info.geometry; + + if (!geom || geom->base_width <= 0.0f || geom->base_height <= 0.0f) + return; + + /* Fallback to 1:1 pixel ratio if none provided */ + if (geom->aspect_ratio > 0.0f) + aspectratio_lut[ASPECT_RATIO_CORE].value = geom->aspect_ratio; + else + aspectratio_lut[ASPECT_RATIO_CORE].value = + (float)geom->base_width / geom->base_height; +} + +void video_driver_reset_custom_viewport(void) +{ + struct video_viewport *custom_vp = video_viewport_get_custom(); + + custom_vp->width = 0; + custom_vp->height = 0; + custom_vp->x = 0; + custom_vp->y = 0; +} + +void video_driver_set_rgba(void) +{ + video_driver_lock(); + video_driver_use_rgba = true; + video_driver_unlock(); +} + +void video_driver_unset_rgba(void) +{ + video_driver_lock(); + video_driver_use_rgba = false; + video_driver_unlock(); +} + +bool video_driver_supports_rgba(void) +{ + bool tmp; + video_driver_lock(); + tmp = video_driver_use_rgba; + video_driver_unlock(); + return tmp; +} + +bool video_driver_get_next_video_out(void) +{ + if (!video_driver_poke) + return false; + + if (!video_driver_poke->get_video_output_next) + return video_context_driver_get_video_output_next(); + video_driver_poke->get_video_output_next(video_driver_data); + return true; +} + +bool video_driver_get_prev_video_out(void) +{ + if (!video_driver_poke) + return false; + + if (!video_driver_poke->get_video_output_prev) + return video_context_driver_get_video_output_prev(); + video_driver_poke->get_video_output_prev(video_driver_data); + return true; +} + +bool video_driver_init(bool *video_is_threaded) +{ + video_driver_lock_new(); + video_driver_filter_free(); + video_driver_set_cached_frame_ptr(NULL); + return video_driver_init_internal(video_is_threaded); +} + +void video_driver_destroy_data(void) +{ + video_driver_data = NULL; +} + +void video_driver_free(void) +{ + video_driver_free_internal(); + video_driver_lock_free(); + video_driver_data = NULL; + video_driver_set_cached_frame_ptr(NULL); +} + +void video_driver_monitor_reset(void) +{ + video_driver_frame_time_count = 0; +} + +void video_driver_set_aspect_ratio(void) +{ + settings_t *settings = config_get_ptr(); + + switch (settings->uints.video_aspect_ratio_idx) + { + case ASPECT_RATIO_SQUARE: + video_driver_set_viewport_square_pixel(); + break; + + case ASPECT_RATIO_CORE: + video_driver_set_viewport_core(); + break; + + case ASPECT_RATIO_CONFIG: + video_driver_set_viewport_config(); + break; + + default: + break; + } + + video_driver_set_aspect_ratio_value( + aspectratio_lut[settings->uints.video_aspect_ratio_idx].value); + + if (!video_driver_poke || !video_driver_poke->set_aspect_ratio) + return; + video_driver_poke->set_aspect_ratio( + video_driver_data, settings->uints.video_aspect_ratio_idx); +} + +void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect) +{ + gfx_ctx_aspect_t aspect_data; + float device_aspect = (float)vp->full_width / vp->full_height; + settings_t* settings = config_get_ptr(); + + aspect_data.aspect = &device_aspect; + aspect_data.width = vp->full_width; + aspect_data.height = vp->full_height; + + video_context_driver_translate_aspect(&aspect_data); + + vp->x = 0; + vp->y = 0; + vp->width = vp->full_width; + vp->height = vp->full_height; + + if (settings->bools.video_scale_integer && !force_full) + { + video_viewport_get_scaled_integer( + vp, vp->full_width, vp->full_height, video_driver_get_aspect_ratio(), keep_aspect); + } + else if (keep_aspect && !force_full) + { + float desired_aspect = video_driver_get_aspect_ratio(); + +#if defined(HAVE_MENU) + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + const struct video_viewport* custom = video_viewport_get_custom(); + + vp->x = custom->x; + vp->y = custom->y; + vp->width = custom->width; + vp->height = custom->height; + } + else +#endif + { + float delta; + + if (fabsf(device_aspect - desired_aspect) < 0.0001f) + { + /* If the aspect ratios of screen and desired aspect + * ratio are sufficiently equal (floating point stuff), + * assume they are actually equal. + */ + } + else if (device_aspect > desired_aspect) + { + delta = (desired_aspect / device_aspect - 1.0f) + / 2.0f + 0.5f; + vp->x = (int)roundf(vp->full_width * (0.5f - delta)); + vp->width = (unsigned)roundf(2.0f * vp->full_width * delta); + vp->y = 0; + vp->height = vp->full_height; + } + else + { + vp->x = 0; + vp->width = vp->full_width; + delta = (device_aspect / desired_aspect - 1.0f) + / 2.0f + 0.5f; + vp->y = (int)roundf(vp->full_height * (0.5f - delta)); + vp->height = (unsigned)roundf(2.0f * vp->full_height * delta); + } + } + } + +#if defined(RARCH_MOBILE) + /* In portrait mode, we want viewport to gravitate to top of screen. */ + if (device_aspect < 1.0f) + vp->y = 0; +#endif +} + +void video_driver_show_mouse(void) +{ + if (video_driver_poke && video_driver_poke->show_mouse) + video_driver_poke->show_mouse(video_driver_data, true); +} + +void video_driver_hide_mouse(void) +{ + if (video_driver_poke && video_driver_poke->show_mouse) + video_driver_poke->show_mouse(video_driver_data, false); +} + +void video_driver_set_nonblock_state(bool toggle) +{ + if (current_video->set_nonblock_state) + current_video->set_nonblock_state(video_driver_data, toggle); +} + +bool video_driver_find_driver(void) +{ + int i; + driver_ctx_info_t drv; + settings_t *settings = config_get_ptr(); + + if (video_driver_is_hw_context()) + { + struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); + + current_video = NULL; + + (void)hwr; + +#if defined(HAVE_VULKAN) + if (hwr && hw_render_context_is_vulkan(hwr->context_type)) + { + RARCH_LOG("[Video]: Using HW render, Vulkan driver forced.\n"); + current_video = &video_vulkan; + } +#endif + +#if defined(HAVE_OPENGL) + if (hwr && hw_render_context_is_gl(hwr->context_type)) + { + RARCH_LOG("[Video]: Using HW render, OpenGL driver forced.\n"); + current_video = &video_gl; + } +#endif + + if (current_video) + return true; + } + + if (frontend_driver_has_get_video_driver_func()) + { + current_video = (video_driver_t*)frontend_driver_get_video_driver(); + + if (current_video) + return true; + RARCH_WARN("Frontend supports get_video_driver() but did not specify one.\n"); + } + + drv.label = "video_driver"; + drv.s = settings->arrays.video_driver; + + driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv); + + i = (int)drv.len; + + if (i >= 0) + current_video = (video_driver_t*)video_driver_find_handle(i); + else + { + if (verbosity_is_enabled()) + { + unsigned d; + RARCH_ERR("Couldn't find any video driver named \"%s\"\n", + settings->arrays.video_driver); + RARCH_LOG_OUTPUT("Available video drivers are:\n"); + for (d = 0; video_driver_find_handle(d); d++) + RARCH_LOG_OUTPUT("\t%s\n", video_driver_find_ident(d)); + RARCH_WARN("Going to default to first video driver...\n"); + } + + current_video = (video_driver_t*)video_driver_find_handle(0); + + if (!current_video) + retroarch_fail(1, "find_video_driver()"); + } + return true; +} + +void video_driver_apply_state_changes(void) +{ + if (video_driver_poke && + video_driver_poke->apply_state_changes) + video_driver_poke->apply_state_changes(video_driver_data); +} + +bool video_driver_read_viewport(uint8_t *buffer, bool is_idle) +{ + if ( current_video->read_viewport + && current_video->read_viewport( + video_driver_data, buffer, is_idle)) + return true; + return false; +} + +bool video_driver_frame_filter_alive(void) +{ + return !!video_driver_state_filter; +} + +bool video_driver_frame_filter_is_32bit(void) +{ + return video_driver_state_out_rgb32; +} + +void video_driver_default_settings(void) +{ + global_t *global = global_get_ptr(); + + if (!global) + return; + + global->console.screen.gamma_correction = DEFAULT_GAMMA; + global->console.flickerfilter_enable = false; + global->console.softfilter_enable = false; + + global->console.screen.resolutions.current.id = 0; +} + +void video_driver_load_settings(config_file_t *conf) +{ + bool tmp_bool = false; + global_t *global = global_get_ptr(); + + if (!conf) + return; + +#ifdef _XBOX + CONFIG_GET_BOOL_BASE(conf, global, + console.screen.gamma_correction, "gamma_correction"); +#else + CONFIG_GET_INT_BASE(conf, global, + console.screen.gamma_correction, "gamma_correction"); +#endif + + if (config_get_bool(conf, "flicker_filter_enable", + &tmp_bool)) + global->console.flickerfilter_enable = tmp_bool; + + if (config_get_bool(conf, "soft_filter_enable", + &tmp_bool)) + global->console.softfilter_enable = tmp_bool; + + CONFIG_GET_INT_BASE(conf, global, + console.screen.soft_filter_index, + "soft_filter_index"); + CONFIG_GET_INT_BASE(conf, global, + console.screen.resolutions.current.id, + "current_resolution_id"); + CONFIG_GET_INT_BASE(conf, global, + console.screen.flicker_filter_index, + "flicker_filter_index"); +} + +void video_driver_save_settings(config_file_t *conf) +{ + global_t *global = global_get_ptr(); + if (!conf) + return; + +#ifdef _XBOX + config_set_bool(conf, "gamma_correction", + global->console.screen.gamma_correction); +#else + config_set_int(conf, "gamma_correction", + global->console.screen.gamma_correction); +#endif + config_set_bool(conf, "flicker_filter_enable", + global->console.flickerfilter_enable); + config_set_bool(conf, "soft_filter_enable", + global->console.softfilter_enable); + + config_set_int(conf, "soft_filter_index", + global->console.screen.soft_filter_index); + config_set_int(conf, "current_resolution_id", + global->console.screen.resolutions.current.id); + config_set_int(conf, "flicker_filter_index", + global->console.screen.flicker_filter_index); +} + +void video_driver_reinit(void) +{ + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); + + if (hwr->cache_context) + video_driver_cache_context = true; + else + video_driver_cache_context = false; + + video_driver_cache_context_ack = false; + command_event(CMD_EVENT_RESET_CONTEXT, NULL); + video_driver_cache_context = false; +} + +void video_driver_set_own_driver(void) +{ + video_driver_data_own = true; +} + +void video_driver_unset_own_driver(void) +{ + video_driver_data_own = false; +} + +bool video_driver_owns_driver(void) +{ + return video_driver_data_own; +} + +bool video_driver_is_hw_context(void) +{ + bool is_hw_context = false; + + video_driver_context_lock(); + is_hw_context = (hw_render.context_type != RETRO_HW_CONTEXT_NONE); + video_driver_context_unlock(); + + return is_hw_context; +} + +void video_driver_free_hw_context(void) +{ + video_driver_context_lock(); + + if (hw_render.context_destroy) + hw_render.context_destroy(); + + memset(&hw_render, 0, sizeof(hw_render)); + + video_driver_context_unlock(); + + hw_render_context_negotiation = NULL; +} + +struct retro_hw_render_callback *video_driver_get_hw_context(void) +{ + return &hw_render; +} + +const struct retro_hw_render_context_negotiation_interface * + video_driver_get_context_negotiation_interface(void) +{ + return hw_render_context_negotiation; +} + +void video_driver_set_context_negotiation_interface( + const struct retro_hw_render_context_negotiation_interface *iface) +{ + hw_render_context_negotiation = iface; +} + +bool video_driver_is_video_cache_context(void) +{ + return video_driver_cache_context; +} + +void video_driver_set_video_cache_context_ack(void) +{ + video_driver_cache_context_ack = true; +} + +void video_driver_unset_video_cache_context_ack(void) +{ + video_driver_cache_context_ack = false; +} + +bool video_driver_is_video_cache_context_ack(void) +{ + return video_driver_cache_context_ack; +} + +void video_driver_set_active(void) +{ + video_driver_active = true; +} + +void video_driver_unset_active(void) +{ + video_driver_active = false; +} + +bool video_driver_is_active(void) +{ + return video_driver_active; +} + +void video_driver_get_record_status( + bool *has_gpu_record, + uint8_t **gpu_buf) +{ + *gpu_buf = video_driver_record_gpu_buffer; + *has_gpu_record = video_driver_record_gpu_buffer != NULL; +} + +bool video_driver_gpu_record_init(unsigned size) +{ + video_driver_record_gpu_buffer = (uint8_t*)malloc(size); + if (!video_driver_record_gpu_buffer) + return false; + return true; +} + +void video_driver_gpu_record_deinit(void) +{ + free(video_driver_record_gpu_buffer); + video_driver_record_gpu_buffer = NULL; +} + +bool video_driver_get_current_software_framebuffer( + struct retro_framebuffer *fb) +{ + if ( + video_driver_poke + && video_driver_poke->get_current_software_framebuffer + && video_driver_poke->get_current_software_framebuffer( + video_driver_data, fb)) + return true; + + return false; +} + +bool video_driver_get_hw_render_interface( + const struct retro_hw_render_interface **iface) +{ + if ( + video_driver_poke + && video_driver_poke->get_hw_render_interface + && video_driver_poke->get_hw_render_interface( + video_driver_data, iface)) + return true; + + return false; +} + +bool video_driver_get_viewport_info(struct video_viewport *viewport) +{ + if (!current_video || !current_video->viewport_info) + return false; + current_video->viewport_info(video_driver_data, viewport); + return true; +} + +void video_driver_set_title_buf(void) +{ + struct retro_system_info info; + core_get_system_info(&info); + + fill_pathname_join_concat_noext( + video_driver_title_buf, + msg_hash_to_str(MSG_PROGRAM), + " ", + info.library_name, + sizeof(video_driver_title_buf)); + strlcat(video_driver_title_buf, + " ", sizeof(video_driver_title_buf)); + strlcat(video_driver_title_buf, + info.library_version, + sizeof(video_driver_title_buf)); +} + +/** + * video_viewport_get_scaled_integer: + * @vp : Viewport handle + * @width : Width. + * @height : Height. + * @aspect_ratio : Aspect ratio (in float). + * @keep_aspect : Preserve aspect ratio? + * + * Gets viewport scaling dimensions based on + * scaled integer aspect ratio. + **/ +void video_viewport_get_scaled_integer(struct video_viewport *vp, + unsigned width, unsigned height, + float aspect_ratio, bool keep_aspect) +{ + int padding_x = 0; + int padding_y = 0; + settings_t *settings = config_get_ptr(); + + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + struct video_viewport *custom = video_viewport_get_custom(); + + if (custom) + { + padding_x = width - custom->width; + padding_y = height - custom->height; + width = custom->width; + height = custom->height; + } + } + else + { + unsigned base_width; + /* Use system reported sizes as these define the + * geometry for the "normal" case. */ + unsigned base_height = + video_driver_av_info.geometry.base_height; + + if (base_height == 0) + base_height = 1; + + /* Account for non-square pixels. + * This is sort of contradictory with the goal of integer scale, + * but it is desirable in some cases. + * + * If square pixels are used, base_height will be equal to + * system->av_info.base_height. */ + base_width = (unsigned)roundf(base_height * aspect_ratio); + + /* Make sure that we don't get 0x scale ... */ + if (width >= base_width && height >= base_height) + { + if (keep_aspect) + { + /* X/Y scale must be same. */ + unsigned max_scale = MIN(width / base_width, + height / base_height); + padding_x = width - base_width * max_scale; + padding_y = height - base_height * max_scale; + } + else + { + /* X/Y can be independent, each scaled as much as possible. */ + padding_x = width % base_width; + padding_y = height % base_height; + } + } + + width -= padding_x; + height -= padding_y; + } + + vp->width = width; + vp->height = height; + vp->x = padding_x / 2; + vp->y = padding_y / 2; +} + +struct retro_system_av_info *video_viewport_get_system_av_info(void) +{ + return &video_driver_av_info; +} + +struct video_viewport *video_viewport_get_custom(void) +{ + settings_t *settings = config_get_ptr(); + return &settings->video_viewport_custom; +} + +unsigned video_pixel_get_alignment(unsigned pitch) +{ + if (pitch & 1) + return 1; + if (pitch & 2) + return 2; + if (pitch & 4) + return 4; + return 8; +} + +/** + * video_driver_frame: + * @data : pointer to data of the video frame. + * @width : width of the video frame. + * @height : height of the video frame. + * @pitch : pitch of the video frame. + * + * Video frame render callback function. + **/ +void video_driver_frame(const void *data, unsigned width, + unsigned height, size_t pitch) +{ + static char video_driver_msg[256]; + static char title[256]; + video_frame_info_t video_info; + static retro_time_t curr_time; + static retro_time_t fps_time; + static float last_fps, frame_time; + unsigned output_width = 0; + unsigned output_height = 0; + unsigned output_pitch = 0; + const char *msg = NULL; + retro_time_t new_time = + cpu_features_get_time_usec(); + + if (!video_driver_active) + return; + + if (video_driver_scaler_ptr && data && + (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_0RGB1555) && + (data != RETRO_HW_FRAME_BUFFER_VALID)) + { + if (video_pixel_frame_scale( + video_driver_scaler_ptr->scaler, + video_driver_scaler_ptr->scaler_out, + data, width, height, pitch)) + { + data = video_driver_scaler_ptr->scaler_out; + pitch = video_driver_scaler_ptr->scaler->out_stride; + } + } + + if (data) + frame_cache_data = data; + frame_cache_width = width; + frame_cache_height = height; + frame_cache_pitch = pitch; + + video_driver_build_info(&video_info); + + /* Get the amount of frames per seconds. */ + if (video_driver_frame_count) + { + unsigned write_index = + video_driver_frame_time_count++ & + (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1); + frame_time = new_time - fps_time; + video_driver_frame_time_samples[write_index] = frame_time; + fps_time = new_time; + + if (video_driver_frame_count == 1) + strlcpy(title, video_driver_window_title, sizeof(title)); + + if ((video_driver_frame_count % FPS_UPDATE_INTERVAL) == 0) + { + char frames_text[64]; + last_fps = TIME_TO_FPS(curr_time, new_time, FPS_UPDATE_INTERVAL); + + if (video_info.fps_show || video_info.framecount_show) + { + if (video_info.fps_show) + { + snprintf(video_info.fps_text, sizeof(video_info.fps_text), + " || FPS: %6.1f ", last_fps); + } + if (video_info.framecount_show) + { + snprintf(frames_text, + sizeof(frames_text), + " || Frames: %" PRIu64, + (uint64_t)video_driver_frame_count); + } + snprintf(video_driver_window_title, sizeof(video_driver_window_title), + "%s%s%s", title, + video_info.fps_show ? video_info.fps_text : "", + video_info.framecount_show ? frames_text : ""); + } + else + { + if (!string_is_equal(video_driver_window_title, title)) + strlcpy(video_driver_window_title, title, sizeof(video_driver_window_title)); + } + + curr_time = new_time; + video_driver_window_title_update = true; + } + + if (video_info.fps_show) + { + if (video_info.framecount_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f || %s: %" PRIu64, + last_fps, + msg_hash_to_str(MSG_FRAMES), + (uint64_t)video_driver_frame_count); + else + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f", + last_fps); + } + + if (video_info.fps_show && video_info.framecount_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f || %s: %" PRIu64, + last_fps, + msg_hash_to_str(MSG_FRAMES), + (uint64_t)video_driver_frame_count); + else if (video_info.framecount_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "%s: %" PRIu64, + msg_hash_to_str(MSG_FRAMES), + (uint64_t)video_driver_frame_count); + else if (video_info.fps_show) + snprintf( + video_info.fps_text, + sizeof(video_info.fps_text), + "FPS: %6.1f", + last_fps); + } + else + { + + curr_time = fps_time = new_time; + + strlcpy(video_driver_window_title, + video_driver_title_buf, + sizeof(video_driver_window_title)); + + if (video_info.fps_show) + strlcpy(video_info.fps_text, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), + sizeof(video_info.fps_text)); + + video_driver_window_title_update = true; + } + + video_info.frame_rate = last_fps; + video_info.frame_time = frame_time / 1000.0f; + video_info.frame_count = (uint64_t) video_driver_frame_count; + + /* Slightly messy code, + * but we really need to do processing before blocking on VSync + * for best possible scheduling. + */ + if ( + ( + !video_driver_state_filter + || !video_info.post_filter_record + || !data + || video_driver_record_gpu_buffer + ) && recording_data + ) + recording_dump_frame(data, width, height, + pitch, video_info.runloop_is_idle); + + if (data && video_driver_state_filter && + video_driver_frame_filter(data, &video_info, width, height, pitch, + &output_width, &output_height, &output_pitch)) + { + data = video_driver_state_buffer; + width = output_width; + height = output_height; + pitch = output_pitch; + } + + video_driver_msg[0] = '\0'; + + if ( video_info.font_enable + && runloop_msg_queue_pull((const char**)&msg) + && msg) + { +#ifdef HAVE_THREADS + /* the msg pointer may point to data modified by another thread */ + runloop_msg_queue_lock(); +#endif + strlcpy(video_driver_msg, msg, sizeof(video_driver_msg)); +#ifdef HAVE_THREADS + runloop_msg_queue_unlock(); +#endif + } + + if (video_info.statistics_show) + { + audio_statistics_t audio_stats = {0.0f}; + double stddev = 0.0; + struct retro_system_av_info *av_info = &video_driver_av_info; + unsigned red = 255; + unsigned green = 255; + unsigned blue = 255; + unsigned alpha = 255; + + video_monitor_fps_statistics(NULL, &stddev, NULL); + + video_info.osd_stat_params.x = 0.010f; + video_info.osd_stat_params.y = 0.950f; + video_info.osd_stat_params.scale = 1.0f; + video_info.osd_stat_params.full_screen = true; + video_info.osd_stat_params.drop_x = -2; + video_info.osd_stat_params.drop_y = -2; + video_info.osd_stat_params.drop_mod = 0.3f; + video_info.osd_stat_params.drop_alpha = 1.0f; + video_info.osd_stat_params.color = COLOR_ABGR( + red, green, blue, alpha); + + compute_audio_buffer_statistics(&audio_stats); + + snprintf(video_info.stat_text, + sizeof(video_info.stat_text), + "Video Statistics:\n -Frame rate: %6.2f fps\n -Frame time: %6.2f ms\n -Frame time deviation: %.3f %%\n" + " -Frame count: %" PRIu64"\n -Viewport: %d x %d x %3.2f\n" + "Audio Statistics:\n -Average buffer saturation: %.2f %%\n -Standard deviation: %.2f %%\n -Time spent close to underrun: %.2f %%\n -Time spent close to blocking: %.2f %%\n -Sample count: %d\n" + "Core Geometry:\n -Size: %u x %u\n -Max Size: %u x %u\n -Aspect: %3.2f\nCore Timing:\n -FPS: %3.2f\n -Sample Rate: %6.2f\n", + video_info.frame_rate, + video_info.frame_time, + 100.0 * stddev, + video_info.frame_count, + video_info.width, + video_info.height, + video_info.refresh_rate, + audio_stats.average_buffer_saturation, + audio_stats.std_deviation_percentage, + audio_stats.close_to_underrun, + audio_stats.close_to_blocking, + audio_stats.samples, + av_info->geometry.base_width, + av_info->geometry.base_height, + av_info->geometry.max_width, + av_info->geometry.max_height, + av_info->geometry.aspect_ratio, + av_info->timing.fps, + av_info->timing.sample_rate); + + /* TODO/FIXME - add OSD chat text here */ +#if 0 + snprintf(video_info.chat_text, sizeof(video_info.chat_text), + "anon: does retroarch netplay have in-game chat?\nradius: I don't know \u2605"); +#endif + } + + video_driver_active = current_video->frame( + video_driver_data, data, width, height, + video_driver_frame_count, + (unsigned)pitch, video_driver_msg, &video_info); + + video_driver_frame_count++; + + /* Display the FPS, with a higher priority. */ + if (video_info.fps_show || video_info.framecount_show) + runloop_msg_queue_push(video_info.fps_text, 2, 1, true); + + /* trigger set resolution*/ + if (video_info.crt_switch_resolution) + { + video_driver_crt_switching_active = true; + + if (video_info.crt_switch_resolution_super == 2560) + width = 2560; + if (video_info.crt_switch_resolution_super == 3840) + width = 3840; + if (video_info.crt_switch_resolution_super == 1920) + width = 1920; + crt_switch_res_core(width, height, video_driver_core_hz, video_info.crt_switch_resolution, video_info.crt_switch_center_adjust, video_info.monitor_index); + } + else if (!video_info.crt_switch_resolution) + video_driver_crt_switching_active = false; + + /* trigger set resolution*/ +} + +void crt_switch_driver_reinit(void) +{ + video_driver_reinit(); +} + +void video_driver_display_type_set(enum rarch_display_type type) +{ + video_driver_display_type = type; +} + +uintptr_t video_driver_display_get(void) +{ + return video_driver_display; +} + +void video_driver_display_set(uintptr_t idx) +{ + video_driver_display = idx; +} + +enum rarch_display_type video_driver_display_type_get(void) +{ + return video_driver_display_type; +} + +void video_driver_window_set(uintptr_t idx) +{ + video_driver_window = idx; +} + +uintptr_t video_driver_window_get(void) +{ + return video_driver_window; +} + +bool video_driver_texture_load(void *data, + enum texture_filter_type filter_type, + uintptr_t *id) +{ + if (!id || !video_driver_poke || !video_driver_poke->load_texture) + return false; + + *id = video_driver_poke->load_texture(video_driver_data, data, + video_driver_is_threaded_internal(), + filter_type); + + return true; +} + +bool video_driver_texture_unload(uintptr_t *id) +{ + if (!video_driver_poke || !video_driver_poke->unload_texture) + return false; + + video_driver_poke->unload_texture(video_driver_data, *id); + *id = 0; + return true; +} + +static bool video_driver_cb_set_coords(void *handle_data, + void *shader_data, const struct video_coords *coords) +{ + video_shader_ctx_coords_t ctx_coords; + ctx_coords.handle_data = handle_data; + ctx_coords.data = coords; + + video_driver_set_coords(&ctx_coords); + return true; +} + +void video_driver_build_info(video_frame_info_t *video_info) +{ + bool is_perfcnt_enable = false; + bool is_paused = false; + bool is_idle = false; + bool is_slowmotion = false; + settings_t *settings = NULL; + video_viewport_t *custom_vp = NULL; + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); +#ifdef HAVE_THREADS + bool is_threaded = video_driver_is_threaded_internal(); + video_driver_threaded_lock(is_threaded); +#endif + settings = config_get_ptr(); + custom_vp = &settings->video_viewport_custom; + video_info->refresh_rate = settings->floats.video_refresh_rate; + video_info->crt_switch_resolution = settings->uints.crt_switch_resolution; + video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super; + video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust; + video_info->black_frame_insertion = settings->bools.video_black_frame_insertion; + video_info->hard_sync = settings->bools.video_hard_sync; + video_info->hard_sync_frames = settings->uints.video_hard_sync_frames; + video_info->fps_show = settings->bools.video_fps_show; + video_info->statistics_show = settings->bools.video_statistics_show; + video_info->framecount_show = settings->bools.video_framecount_show; + video_info->scale_integer = settings->bools.video_scale_integer; + video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx; + video_info->post_filter_record = settings->bools.video_post_filter_record; + video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons; + video_info->max_swapchain_images = settings->uints.video_max_swapchain_images; + video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen; + video_info->fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen(); + video_info->monitor_index = settings->uints.video_monitor_index; + video_info->shared_context = settings->bools.video_shared_context; + + if (libretro_get_shared_context() && hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) + video_info->shared_context = true; + + video_info->font_enable = settings->bools.video_font_enable; + video_info->font_msg_pos_x = settings->floats.video_msg_pos_x; + video_info->font_msg_pos_y = settings->floats.video_msg_pos_y; + video_info->font_msg_color_r = settings->floats.video_msg_color_r; + video_info->font_msg_color_g = settings->floats.video_msg_color_g; + video_info->font_msg_color_b = settings->floats.video_msg_color_b; + video_info->custom_vp_x = custom_vp->x; + video_info->custom_vp_y = custom_vp->y; + video_info->custom_vp_width = custom_vp->width; + video_info->custom_vp_height = custom_vp->height; + video_info->custom_vp_full_width = custom_vp->full_width; + video_info->custom_vp_full_height = custom_vp->full_height; + + video_info->fps_text[0] = '\0'; + + video_info->width = video_driver_width; + video_info->height = video_driver_height; + + video_info->use_rgba = video_driver_use_rgba; + + video_info->libretro_running = false; + video_info->msg_bgcolor_enable = settings->bools.video_msg_bgcolor_enable; + +#ifdef HAVE_MENU + video_info->menu_is_alive = menu_driver_is_alive(); + video_info->menu_footer_opacity = settings->floats.menu_footer_opacity; + video_info->menu_header_opacity = settings->floats.menu_header_opacity; + video_info->materialui_color_theme = settings->uints.menu_materialui_color_theme; + video_info->ozone_color_theme = settings->uints.menu_ozone_color_theme; + video_info->menu_shader_pipeline = settings->uints.menu_xmb_shader_pipeline; + video_info->xmb_theme = settings->uints.menu_xmb_theme; + video_info->xmb_color_theme = settings->uints.menu_xmb_color_theme; + video_info->timedate_enable = settings->bools.menu_timedate_enable; + video_info->battery_level_enable = settings->bools.menu_battery_level_enable; + video_info->xmb_shadows_enable = settings->bools.menu_xmb_shadows_enable; + video_info->xmb_alpha_factor = settings->uints.menu_xmb_alpha_factor; + video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity; + video_info->menu_framebuffer_opacity = settings->floats.menu_framebuffer_opacity; + + video_info->libretro_running = core_is_game_loaded(); +#else + video_info->menu_is_alive = false; + video_info->menu_footer_opacity = 0.0f; + video_info->menu_header_opacity = 0.0f; + video_info->materialui_color_theme = 0; + video_info->menu_shader_pipeline = 0; + video_info->xmb_color_theme = 0; + video_info->xmb_theme = 0; + video_info->timedate_enable = false; + video_info->battery_level_enable = false; + video_info->xmb_shadows_enable = false; + video_info->xmb_alpha_factor = 0.0f; + video_info->menu_framebuffer_opacity = 0.0f; + video_info->menu_wallpaper_opacity = 0.0f; +#endif + + runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); + + video_info->is_perfcnt_enable = is_perfcnt_enable; + video_info->runloop_is_paused = is_paused; + video_info->runloop_is_idle = is_idle; + video_info->runloop_is_slowmotion = is_slowmotion; + + video_info->input_driver_nonblock_state = input_driver_is_nonblock_state(); + + video_info->context_data = video_context_data; + video_info->shader_driver = current_shader; + video_info->shader_data = current_shader_data; + + video_info->cb_update_window_title = current_video_context.update_window_title; + video_info->cb_swap_buffers = current_video_context.swap_buffers; + video_info->cb_get_metrics = current_video_context.get_metrics; + video_info->cb_set_resize = current_video_context.set_resize; + + video_info->cb_set_mvp = video_driver_cb_shader_set_mvp; + + video_info->userdata = video_driver_get_ptr(false); + +#ifdef HAVE_THREADS + video_driver_threaded_unlock(is_threaded); +#endif +} + +/** + * video_driver_translate_coord_viewport: + * @mouse_x : Pointer X coordinate. + * @mouse_y : Pointer Y coordinate. + * @res_x : Scaled X coordinate. + * @res_y : Scaled Y coordinate. + * @res_screen_x : Scaled screen X coordinate. + * @res_screen_y : Scaled screen Y coordinate. + * + * Translates pointer [X,Y] coordinates into scaled screen + * coordinates based on viewport info. + * + * Returns: true (1) if successful, false if video driver doesn't support + * viewport info. + **/ +bool video_driver_translate_coord_viewport( + struct video_viewport *vp, + int mouse_x, int mouse_y, + int16_t *res_x, int16_t *res_y, + int16_t *res_screen_x, int16_t *res_screen_y) +{ + int scaled_screen_x, scaled_screen_y, scaled_x, scaled_y; + int norm_vp_width = (int)vp->width; + int norm_vp_height = (int)vp->height; + int norm_full_vp_width = (int)vp->full_width; + int norm_full_vp_height = (int)vp->full_height; + + if (norm_full_vp_width <= 0 || norm_full_vp_height <= 0) + return false; + + if (mouse_x >= 0 && mouse_x <= norm_full_vp_width) + scaled_screen_x = ((2 * mouse_x * 0x7fff) + / norm_full_vp_width) - 0x7fff; + else + scaled_screen_x = -0x8000; /* OOB */ + + if (mouse_y >= 0 && mouse_y <= norm_full_vp_height) + scaled_screen_y = ((2 * mouse_y * 0x7fff) + / norm_full_vp_height) - 0x7fff; + else + scaled_screen_y = -0x8000; /* OOB */ + + mouse_x -= vp->x; + mouse_y -= vp->y; + + if (mouse_x >= 0 && mouse_x <= norm_vp_width) + scaled_x = ((2 * mouse_x * 0x7fff) + / norm_vp_width) - 0x7fff; + else + scaled_x = -0x8000; /* OOB */ + + if (mouse_y >= 0 && mouse_y <= norm_vp_height) + scaled_y = ((2 * mouse_y * 0x7fff) + / norm_vp_height) - 0x7fff; + else + scaled_y = -0x8000; /* OOB */ + + *res_x = scaled_x; + *res_y = scaled_y; + *res_screen_x = scaled_screen_x; + *res_screen_y = scaled_screen_y; + + return true; +} + +void video_driver_get_window_title(char *buf, unsigned len) +{ + if (buf && video_driver_window_title_update) + { + strlcpy(buf, video_driver_window_title, len); + video_driver_window_title_update = false; + } +} + +void video_driver_get_status(uint64_t *frame_count, bool * is_alive, + bool *is_focused) +{ + *frame_count = video_driver_frame_count; + *is_alive = current_video ? + current_video->alive(video_driver_data) : true; + *is_focused = video_driver_cb_has_focus(); +} + +/** + * find_video_context_driver_driver_index: + * @ident : Identifier of resampler driver to find. + * + * Finds graphics context driver index by @ident name. + * + * Returns: graphics context driver index if driver was found, otherwise + * -1. + **/ +static int find_video_context_driver_index(const char *ident) +{ + unsigned i; + for (i = 0; gfx_ctx_drivers[i]; i++) + if (string_is_equal_noncase(ident, gfx_ctx_drivers[i]->ident)) + return i; + return -1; +} + +/** + * find_prev_context_driver: + * + * Finds previous driver in graphics context driver array. + **/ +bool video_context_driver_find_prev_driver(void) +{ + settings_t *settings = config_get_ptr(); + int i = find_video_context_driver_index( + settings->arrays.video_context_driver); + + if (i > 0) + { + strlcpy(settings->arrays.video_context_driver, + gfx_ctx_drivers[i - 1]->ident, + sizeof(settings->arrays.video_context_driver)); + return true; + } + + RARCH_WARN("Couldn't find any previous video context driver.\n"); + return false; +} + +/** + * find_next_context_driver: + * + * Finds next driver in graphics context driver array. + **/ +bool video_context_driver_find_next_driver(void) +{ + settings_t *settings = config_get_ptr(); + int i = find_video_context_driver_index( + settings->arrays.video_context_driver); + + if (i >= 0 && gfx_ctx_drivers[i + 1]) + { + strlcpy(settings->arrays.video_context_driver, + gfx_ctx_drivers[i + 1]->ident, + sizeof(settings->arrays.video_context_driver)); + return true; + } + + RARCH_WARN("Couldn't find any next video context driver.\n"); + return false; +} + +/** + * video_context_driver_init: + * @data : Input data. + * @ctx : Graphics context driver to initialize. + * @ident : Identifier of graphics context driver to find. + * @api : API of higher-level graphics API. + * @major : Major version number of higher-level graphics API. + * @minor : Minor version number of higher-level graphics API. + * @hw_render_ctx : Request a graphics context driver capable of + * hardware rendering? + * + * Initialize graphics context driver. + * + * Returns: graphics context driver if successfully initialized, + * otherwise NULL. + **/ +static const gfx_ctx_driver_t *video_context_driver_init( + void *data, + const gfx_ctx_driver_t *ctx, + const char *ident, + enum gfx_ctx_api api, unsigned major, + unsigned minor, bool hw_render_ctx, + void **ctx_data) +{ + video_frame_info_t video_info; + + if (!ctx->bind_api(data, api, major, minor)) + { + RARCH_WARN("Failed to bind API (#%u, version %u.%u)" + " on context driver \"%s\".\n", + (unsigned)api, major, minor, ctx->ident); + + return NULL; + } + + video_driver_build_info(&video_info); + + if (!(*ctx_data = ctx->init(&video_info, data))) + return NULL; + + if (ctx->bind_hw_render) + ctx->bind_hw_render(*ctx_data, + video_info.shared_context && hw_render_ctx); + + return ctx; +} + +/** + * video_context_driver_init_first: + * @data : Input data. + * @ident : Identifier of graphics context driver to find. + * @api : API of higher-level graphics API. + * @major : Major version number of higher-level graphics API. + * @minor : Minor version number of higher-level graphics API. + * @hw_render_ctx : Request a graphics context driver capable of + * hardware rendering? + * + * Finds first suitable graphics context driver and initializes. + * + * Returns: graphics context driver if found, otherwise NULL. + **/ +const gfx_ctx_driver_t *video_context_driver_init_first(void *data, + const char *ident, enum gfx_ctx_api api, unsigned major, + unsigned minor, bool hw_render_ctx, void **ctx_data) +{ + int i = find_video_context_driver_index(ident); + + if (i >= 0) + { + const gfx_ctx_driver_t *ctx = video_context_driver_init(data, gfx_ctx_drivers[i], ident, + api, major, minor, hw_render_ctx, ctx_data); + if (ctx) + { + video_context_data = *ctx_data; + return ctx; + } + } + + for (i = 0; gfx_ctx_drivers[i]; i++) + { + const gfx_ctx_driver_t *ctx = + video_context_driver_init(data, gfx_ctx_drivers[i], ident, + api, major, minor, hw_render_ctx, ctx_data); + + if (ctx) + { + video_context_data = *ctx_data; + return ctx; + } + } + + return NULL; +} + +bool video_context_driver_init_image_buffer(const video_info_t *data) +{ + if ( + current_video_context.image_buffer_init + && current_video_context.image_buffer_init( + video_context_data, data)) + return true; + return false; +} + +bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img) +{ + if ( + current_video_context.image_buffer_write + && current_video_context.image_buffer_write(video_context_data, + img->frame, img->width, img->height, img->pitch, + img->rgb32, img->index, img->handle)) + return true; + return false; +} + +bool video_context_driver_get_video_output_prev(void) +{ + if (!current_video_context.get_video_output_prev) + return false; + current_video_context.get_video_output_prev(video_context_data); + return true; +} + +bool video_context_driver_get_video_output_next(void) +{ + if (!current_video_context.get_video_output_next) + return false; + current_video_context.get_video_output_next(video_context_data); + return true; +} + +void video_context_driver_make_current(bool release) +{ + if (current_video_context.make_current) + current_video_context.make_current(release); +} + +bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect) +{ + if (!video_context_data || !aspect) + return false; + if (!current_video_context.translate_aspect) + return false; + *aspect->aspect = current_video_context.translate_aspect( + video_context_data, aspect->width, aspect->height); + return true; +} + +void video_context_driver_free(void) +{ + if (current_video_context.destroy) + current_video_context.destroy(video_context_data); + video_context_driver_destroy(); + video_context_data = NULL; +} + +bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data) +{ + if (!size_data) + return false; + if (!current_video_context.get_video_output_size) + return false; + current_video_context.get_video_output_size(video_context_data, + size_data->width, size_data->height); + return true; +} + +bool video_context_driver_swap_interval(int *interval) +{ + gfx_ctx_flags_t flags; + int current_interval = *interval; + settings_t *settings = config_get_ptr(); + bool adaptive_vsync_enabled = video_driver_get_all_flags(&flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC) && settings->bools.video_adaptive_vsync; + + if (!current_video_context.swap_interval) + return false; + if (adaptive_vsync_enabled && current_interval == 1) + current_interval = -1; + current_video_context.swap_interval(video_context_data, current_interval); + return true; +} + +bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc) +{ + if (!current_video_context.get_proc_address) + return false; + + proc->addr = current_video_context.get_proc_address(proc->sym); + + return true; +} + +bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics) +{ + if ( + current_video_context.get_metrics(video_context_data, + metrics->type, + metrics->value)) + return true; + return false; +} + +bool video_context_driver_get_refresh_rate(float *refresh_rate) +{ + float refresh_holder = 0; + + if (!current_video_context.get_refresh_rate || !refresh_rate) + return false; + if (!video_context_data) + return false; + + if (!video_driver_crt_switching_active) + if (refresh_rate) + *refresh_rate = + current_video_context.get_refresh_rate(video_context_data); + + if (video_driver_crt_switching_active) + { + if (refresh_rate) + refresh_holder = + current_video_context.get_refresh_rate(video_context_data); + if (refresh_holder != video_driver_core_hz) /* Fix for incorrect interlace detsction -- HARD SET VSNC TO REQUIRED REFRESH FOR CRT*/ + *refresh_rate = video_driver_core_hz; + } + + return true; +} + +bool video_context_driver_input_driver(gfx_ctx_input_t *inp) +{ + settings_t *settings = config_get_ptr(); + const char *joypad_name = settings ? + settings->arrays.input_joypad_driver : NULL; + + if (!current_video_context.input_driver) + return false; + current_video_context.input_driver( + video_context_data, joypad_name, + inp->input, inp->input_data); + return true; +} + +bool video_context_driver_suppress_screensaver(bool *bool_data) +{ + if ( video_context_data + && current_video_context.suppress_screensaver( + video_context_data, *bool_data)) + return true; + return false; +} + +bool video_context_driver_get_ident(gfx_ctx_ident_t *ident) +{ + if (!ident) + return false; + ident->ident = current_video_context.ident; + return true; +} + +bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info) +{ + video_frame_info_t video_info; + + if (!current_video_context.set_video_mode) + return false; + + video_driver_build_info(&video_info); + + if (!current_video_context.set_video_mode( + video_context_data, &video_info, mode_info->width, + mode_info->height, mode_info->fullscreen)) + return false; + return true; +} + +bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info) +{ + if (!current_video_context.get_video_size) + return false; + current_video_context.get_video_size(video_context_data, + &mode_info->width, &mode_info->height); + return true; +} + +bool video_context_driver_show_mouse(bool *bool_data) +{ + if (!current_video_context.show_mouse) + return false; + current_video_context.show_mouse(video_context_data, *bool_data); + return true; +} + +static bool video_context_driver_get_flags(gfx_ctx_flags_t *flags) +{ + if (!current_video_context.get_flags) + return false; + + if (deferred_video_context_driver_set_flags) + { + flags->flags = deferred_flag_data.flags; + deferred_video_context_driver_set_flags = false; + return true; + } + + flags->flags = current_video_context.get_flags(video_context_data); + return true; +} + +static bool video_driver_get_flags(gfx_ctx_flags_t *flags) +{ + if (!video_driver_poke || !video_driver_poke->get_flags) + return false; + flags->flags = video_driver_poke->get_flags(video_driver_data); + return true; +} + +bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, enum display_flags flag) +{ + if (!flags) + return false; + + if (video_driver_get_flags(flags)) + if (BIT32_GET(flags->flags, flag)) + return true; + + flags->flags = 0; + + if (video_context_driver_get_flags(flags)) + if (BIT32_GET(flags->flags, flag)) + return true; + + return false; +} + +bool video_context_driver_set_flags(gfx_ctx_flags_t *flags) +{ + if (!flags) + return false; + if (!current_video_context.set_flags) + { + deferred_flag_data.flags = flags->flags; + deferred_video_context_driver_set_flags = true; + return false; + } + + current_video_context.set_flags(video_context_data, flags->flags); + return true; +} + +enum gfx_ctx_api video_context_driver_get_api(void) +{ + enum gfx_ctx_api ctx_api = video_context_data ? + current_video_context.get_api(video_context_data) : GFX_CTX_NONE; + + if (ctx_api == GFX_CTX_NONE) + { + const char *video_driver = video_driver_get_ident(); + if (string_is_equal(video_driver, "d3d9")) + return GFX_CTX_DIRECT3D9_API; + else if (string_is_equal(video_driver, "d3d10")) + return GFX_CTX_DIRECT3D10_API; + else if (string_is_equal(video_driver, "d3d11")) + return GFX_CTX_DIRECT3D11_API; + else if (string_is_equal(video_driver, "d3d12")) + return GFX_CTX_DIRECT3D12_API; + else if (string_is_equal(video_driver, "gx2")) + return GFX_CTX_GX2_API; + else if (string_is_equal(video_driver, "gx")) + return GFX_CTX_GX_API; + else if (string_is_equal(video_driver, "gl")) + return GFX_CTX_OPENGL_API; + else if (string_is_equal(video_driver, "vulkan")) + return GFX_CTX_VULKAN_API; + else if (string_is_equal(video_driver, "metal")) + return GFX_CTX_METAL_API; + + return GFX_CTX_NONE; + } + + return ctx_api; +} + +bool video_driver_has_windowed(void) +{ +#if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE)) + if (video_driver_data && current_video->has_windowed) + return current_video->has_windowed(video_driver_data); + else if (video_context_data && current_video_context.has_windowed) + return current_video_context.has_windowed(video_context_data); +#endif + return false; +} + +bool video_driver_cached_frame_has_valid_framebuffer(void) +{ + if (frame_cache_data) + return (frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID); + return false; +} + +static const shader_backend_t *video_shader_set_backend( + enum rarch_shader_type type) +{ + switch (type) + { + case RARCH_SHADER_CG: + { +#ifdef HAVE_CG + gfx_ctx_flags_t flags; + flags.flags = 0; + video_context_driver_get_flags(&flags); + + if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) + { + RARCH_ERR("[Shader driver]: Cg cannot be used with core" + " GL context. Trying to fall back to GLSL...\n"); + return video_shader_set_backend(RARCH_SHADER_GLSL); + } + + RARCH_LOG("[Shader driver]: Using Cg shader backend.\n"); + return &gl_cg_backend; +#else + break; +#endif + } + case RARCH_SHADER_GLSL: +#ifdef HAVE_GLSL + RARCH_LOG("[Shader driver]: Using GLSL shader backend.\n"); + return &gl_glsl_backend; +#else + break; +#endif + case RARCH_SHADER_HLSL: + case RARCH_SHADER_NONE: + default: + break; + } + + return NULL; +} + +bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident) +{ + if (!ident || !current_shader) + return false; + ident->ident = current_shader->ident; + return true; +} + +bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader) +{ + void *video_driver = video_driver_get_ptr(true); + const video_poke_interface_t *video_poke = video_driver_get_poke(); + + shader->data = NULL; + if (!video_poke || !video_driver || !video_poke->get_current_shader) + return false; + shader->data = video_poke->get_current_shader(video_driver); + return true; +} + +bool video_shader_driver_deinit(void) +{ + if (!current_shader) + return false; + + if (current_shader->deinit) + current_shader->deinit(current_shader_data); + + current_shader_data = NULL; + current_shader = NULL; + return true; +} + +static bool video_driver_cb_set_mvp(void *data, + void *shader_data, const void *mat_data) +{ + video_shader_ctx_mvp_t mvp; + mvp.data = data; + mvp.matrix = mat_data; + + video_driver_set_mvp(&mvp); + return true; +} + +static void video_shader_driver_scale_null(void *data, + unsigned idx, struct gfx_fbo_scale *scale) +{ + (void)idx; + (void)scale; +} + +static void video_shader_driver_reset_to_defaults(void) +{ + if (!current_shader) + return; + + if (current_shader->set_mvp) + video_driver_cb_shader_set_mvp = current_shader->set_mvp; + else + { + current_shader->set_mvp = video_driver_cb_set_mvp; + video_driver_cb_shader_set_mvp = video_driver_cb_set_mvp; + } + if (!current_shader->set_coords) + current_shader->set_coords = video_driver_cb_set_coords; + + if (!current_shader->shader_scale) + current_shader->shader_scale = video_shader_driver_scale_null; +} + +/* Finds first suitable shader context driver. */ +bool video_shader_driver_init_first(void) +{ + current_shader = (shader_backend_t*)shader_ctx_drivers[0]; + video_shader_driver_reset_to_defaults(); + return true; +} + +bool video_shader_driver_init(video_shader_ctx_init_t *init) +{ + void *tmp = NULL; + settings_t *settings = config_get_ptr(); + + if (!init->shader || !init->shader->init) + { + init->shader = video_shader_set_backend(init->shader_type); + + if (!init->shader) + return false; + } + + tmp = init->shader->init(init->data, init->path); + + if (!tmp) + return false; + + if (string_is_equal(settings->arrays.menu_driver, "xmb") + && init->shader->init_menu_shaders) + { + RARCH_LOG("Setting up menu pipeline shaders for XMB ... \n"); + init->shader->init_menu_shaders(tmp); + } + + init->shader_data = tmp; + current_shader_data = tmp; + + RARCH_LOG("Resetting shader to defaults ... \n"); + + current_shader = (shader_backend_t*)init->shader; + video_shader_driver_reset_to_defaults(); + + return true; +} + +bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler) +{ + if (!scaler || !scaler->scale) + return false; + + scaler->scale->valid = false; + + current_shader->shader_scale(current_shader_data, + scaler->idx, scaler->scale); + return true; +} + +bool video_shader_driver_info(video_shader_ctx_info_t *shader_info) +{ + if (!shader_info) + return false; + + shader_info->num = current_shader->num_shaders(current_shader_data); + + return true; +} + +void video_driver_set_coords(video_shader_ctx_coords_t *coords) +{ + if (current_shader && current_shader->set_coords) + current_shader->set_coords(coords->handle_data, + current_shader_data, + (const struct video_coords*)coords->data); + else + { + if (video_driver_poke && video_driver_poke->set_coords) + video_driver_poke->set_coords(coords->handle_data, + current_shader_data, + (const struct video_coords*)coords->data); + } +} + +void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp) +{ + if (!mvp || !mvp->matrix) + return; + + if (current_shader && current_shader->set_mvp) + current_shader->set_mvp(mvp->data, + current_shader_data, mvp->matrix); + else + { + if (video_driver_poke && video_driver_poke->set_mvp) + video_driver_poke->set_mvp(mvp->data, + current_shader_data, mvp->matrix); + } +} + +float video_driver_get_refresh_rate(void) +{ + if (video_driver_poke && video_driver_poke->get_refresh_rate) + return video_driver_poke->get_refresh_rate(video_driver_data); + + return 0.0f; +} diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 0221aabb6d..17e6718b5c 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -1,1274 +1,1274 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef __VIDEO_DRIVER__H -#define __VIDEO_DRIVER__H - -#include -#include -#include - -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#ifdef HAVE_OVERLAY -#include "../input/input_overlay.h" -#endif - -#include "video_defines.h" -#include "video_coord_array.h" -#include "video_filter.h" -#include "video_shader_parse.h" - -#include "../input/input_types.h" - -#define RARCH_SCALE_BASE 256 - -#include "video_shader_parse.h" - -#define VIDEO_SHADER_STOCK_BLEND (GFX_MAX_SHADERS - 1) -#define VIDEO_SHADER_MENU (GFX_MAX_SHADERS - 2) -#define VIDEO_SHADER_MENU_2 (GFX_MAX_SHADERS - 3) -#define VIDEO_SHADER_MENU_3 (GFX_MAX_SHADERS - 4) -#define VIDEO_SHADER_MENU_4 (GFX_MAX_SHADERS - 5) -#define VIDEO_SHADER_MENU_5 (GFX_MAX_SHADERS - 6) -#define VIDEO_SHADER_MENU_6 (GFX_MAX_SHADERS - 7) - -#if defined(_XBOX360) -#define DEFAULT_SHADER_TYPE RARCH_SHADER_HLSL -#elif defined(__PSL1GHT__) || defined(HAVE_OPENGLES2) || defined(HAVE_GLSL) -#define DEFAULT_SHADER_TYPE RARCH_SHADER_GLSL -#elif defined(__CELLOS_LV2__) || defined(HAVE_CG) -#define DEFAULT_SHADER_TYPE RARCH_SHADER_CG -#else -#define DEFAULT_SHADER_TYPE RARCH_SHADER_NONE -#endif - -RETRO_BEGIN_DECLS - -#ifndef MAX_EGLIMAGE_TEXTURES -#define MAX_EGLIMAGE_TEXTURES 32 -#endif - -#define MAX_VARIABLES 64 - -enum -{ - TEXTURES = 8, - TEXTURESMASK = TEXTURES - 1 -}; - -struct LinkInfo -{ - unsigned tex_w, tex_h; - struct video_shader_pass *pass; -}; - -enum gfx_ctx_api -{ - GFX_CTX_NONE = 0, - GFX_CTX_OPENGL_API, - GFX_CTX_OPENGL_ES_API, - GFX_CTX_DIRECT3D8_API, - GFX_CTX_DIRECT3D9_API, - GFX_CTX_DIRECT3D10_API, - GFX_CTX_DIRECT3D11_API, - GFX_CTX_DIRECT3D12_API, - GFX_CTX_OPENVG_API, - GFX_CTX_VULKAN_API, - GFX_CTX_SIXEL_API, - GFX_CTX_METAL_API, - GFX_CTX_GDI_API, - GFX_CTX_GX_API, - GFX_CTX_GX2_API -}; - -enum display_metric_types -{ - DISPLAY_METRIC_NONE = 0, - DISPLAY_METRIC_MM_WIDTH, - DISPLAY_METRIC_MM_HEIGHT, - DISPLAY_METRIC_DPI -}; - -enum display_flags -{ - GFX_CTX_FLAGS_NONE = 0, - GFX_CTX_FLAGS_GL_CORE_CONTEXT, - GFX_CTX_FLAGS_MULTISAMPLING, - GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES, - GFX_CTX_FLAGS_HARD_SYNC, - GFX_CTX_FLAGS_BLACK_FRAME_INSERTION, - GFX_CTX_FLAGS_MENU_FRAME_FILTERING, - GFX_CTX_FLAGS_ADAPTIVE_VSYNC -}; - -enum shader_uniform_type -{ - UNIFORM_1F = 0, - UNIFORM_2F, - UNIFORM_3F, - UNIFORM_4F, - UNIFORM_1FV, - UNIFORM_2FV, - UNIFORM_3FV, - UNIFORM_4FV, - UNIFORM_1I -}; - -enum shader_program_type -{ - SHADER_PROGRAM_VERTEX = 0, - SHADER_PROGRAM_FRAGMENT, - SHADER_PROGRAM_COMBINED -}; - -struct shader_program_info -{ - bool is_file; - const char *vertex; - const char *fragment; - const char *combined; - unsigned idx; - void *data; -}; - -struct uniform_info -{ - bool enabled; - - int32_t location; - int32_t count; - unsigned type; /* shader uniform type */ - - struct - { - enum shader_program_type type; - const char *ident; - uint32_t idx; - bool add_prefix; - bool enable; - } lookup; - - struct - { - struct - { - intptr_t v0; - intptr_t v1; - intptr_t v2; - intptr_t v3; - } integer; - - intptr_t *integerv; - - struct - { - uintptr_t v0; - uintptr_t v1; - uintptr_t v2; - uintptr_t v3; - } unsigned_integer; - - uintptr_t *unsigned_integerv; - - struct - { - float v0; - float v1; - float v2; - float v3; - } f; - - float *floatv; - } result; -}; - -typedef struct shader_backend -{ - void *(*init)(void *data, const char *path); - void (*init_menu_shaders)(void *data); - void (*deinit)(void *data); - - /* Set shader parameters. */ - void (*set_params)(void *data, void *shader_data); - - void (*set_uniform_parameter)(void *data, struct uniform_info *param, - void *uniform_data); - - /* Compile a shader program. */ - bool (*compile_program)(void *data, unsigned idx, - void *program_data, struct shader_program_info *program_info); - - /* Use a shader program specified by variable 'index'. */ - void (*use)(void *data, void *shader_data, unsigned index, bool set_active); - - /* Returns the number of currently loaded shaders. */ - unsigned (*num_shaders)(void *data); - - bool (*filter_type)(void *data, unsigned index, bool *smooth); - enum gfx_wrap_type (*wrap_type)(void *data, unsigned index); - void (*shader_scale)(void *data, - unsigned index, struct gfx_fbo_scale *scale); - bool (*set_coords)(void *handle_data, - void *shader_data, const struct video_coords *coords); - bool (*set_mvp)(void *data, void *shader_data, - const void *mat_data); - unsigned (*get_prev_textures)(void *data); - bool (*get_feedback_pass)(void *data, unsigned *pass); - bool (*mipmap_input)(void *data, unsigned index); - - struct video_shader *(*get_current_shader)(void *data); - - enum rarch_shader_type type; - - /* Human readable string. */ - const char *ident; -} shader_backend_t; - -typedef struct video_shader_ctx_init -{ - enum rarch_shader_type shader_type; - const char *path; - const shader_backend_t *shader; - void *data; - void *shader_data; - struct - { - bool core_context_enabled; - } gl; -} video_shader_ctx_init_t; - -typedef struct video_shader_ctx_params -{ - unsigned width; - unsigned height; - unsigned tex_width; - unsigned tex_height; - unsigned out_width; - unsigned out_height; - unsigned frame_counter; - unsigned fbo_info_cnt; - void *data; - const void *info; - const void *prev_info; - const void *feedback_info; - const void *fbo_info; -} video_shader_ctx_params_t; - -typedef struct video_shader_ctx_coords -{ - void *handle_data; - const void *data; -} video_shader_ctx_coords_t; - -typedef struct video_shader_ctx_scale -{ - unsigned idx; - struct gfx_fbo_scale *scale; -} video_shader_ctx_scale_t; - -typedef struct video_shader_ctx_info -{ - bool set_active; - unsigned num; - unsigned idx; - void *data; -} video_shader_ctx_info_t; - -typedef struct video_shader_ctx_mvp -{ - void *data; - const void *matrix; -} video_shader_ctx_mvp_t; - -typedef struct video_shader_ctx_filter -{ - unsigned index; - bool *smooth; -} video_shader_ctx_filter_t; - -typedef struct video_shader_ctx -{ - struct video_shader *data; -} video_shader_ctx_t; - -typedef struct video_shader_ctx_ident -{ - const char *ident; -} video_shader_ctx_ident_t; - -typedef struct video_shader_ctx_texture -{ - unsigned id; -} video_shader_ctx_texture_t; - -typedef void (*gfx_ctx_proc_t)(void); - -typedef struct video_info -{ - /* Launch in fullscreen mode instead of windowed mode. */ - bool fullscreen; - - /* Start with V-Sync enabled. */ - bool vsync; - - /* If true, the output image should have the aspect ratio - * as set in aspect_ratio. */ - bool force_aspect; - - bool font_enable; - - /* Width of window. - * If fullscreen mode is requested, - * a width of 0 means the resolution of the - * desktop should be used. */ - unsigned width; - - /* Height of window. - * If fullscreen mode is requested, - * a height of 0 means the resolutiof the desktop should be used. - */ - unsigned height; - - int swap_interval; - -#ifdef GEKKO - bool vfilter; -#endif - - /* If true, applies bilinear filtering to the image, - * otherwise nearest filtering. */ - bool smooth; - - bool is_threaded; - - /* Use 32bit RGBA rather than native RGB565/XBGR1555. - * - * XRGB1555 format is 16-bit and has byte ordering: 0RRRRRGGGGGBBBBB, - * in native endian. - * - * ARGB8888 is AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB, native endian. - * Alpha channel should be disregarded. - * */ - bool rgb32; - -#ifdef GEKKO - /* TODO - we can't really have driver system-specific - * variables in here. There should be some - * kind of publicly accessible driver implementation - * video struct for specific things like this. - */ - - /* Wii-specific settings. Ignored for everything else. */ - unsigned viwidth; -#endif - - /* - * input_scale defines the maximum size of the picture that will - * ever be used with the frame callback. - * - * The maximum resolution is a multiple of 256x256 size (RARCH_SCALE_BASE), - * so an input scale of 2 means you should allocate a texture or of 512x512. - * - * Maximum input size: RARCH_SCALE_BASE * input_scale - */ - unsigned input_scale; - - uintptr_t parent; -} video_info_t; - -typedef struct video_frame_info -{ - bool input_menu_swap_ok_cancel_buttons; - bool input_driver_nonblock_state; - bool shared_context; - bool black_frame_insertion; - bool hard_sync; - bool fps_show; - bool statistics_show; - bool framecount_show; - bool scale_integer; - bool post_filter_record; - bool windowed_fullscreen; - bool fullscreen; - bool font_enable; - bool use_rgba; - bool libretro_running; - bool xmb_shadows_enable; - bool battery_level_enable; - bool timedate_enable; - bool runloop_is_slowmotion; - bool runloop_is_idle; - bool runloop_is_paused; - bool is_perfcnt_enable; - bool menu_is_alive; - bool msg_bgcolor_enable; - - int custom_vp_x; - int custom_vp_y; - int crt_switch_center_adjust; - - unsigned hard_sync_frames; - unsigned aspect_ratio_idx; - unsigned max_swapchain_images; - unsigned monitor_index; - unsigned crt_switch_resolution; - unsigned crt_switch_resolution_super; - unsigned width; - unsigned height; - unsigned xmb_theme; - unsigned xmb_color_theme; - unsigned menu_shader_pipeline; - unsigned materialui_color_theme; - unsigned ozone_color_theme; - unsigned custom_vp_width; - unsigned custom_vp_height; - unsigned custom_vp_full_width; - unsigned custom_vp_full_height; - - float menu_wallpaper_opacity; - float menu_framebuffer_opacity; - float menu_header_opacity; - float menu_footer_opacity; - float refresh_rate; - float font_msg_pos_x; - float font_msg_pos_y; - float font_msg_color_r; - float font_msg_color_g; - float font_msg_color_b; - float xmb_alpha_factor; - - char fps_text[128]; - char stat_text[512]; - char chat_text[256]; - - uint64_t frame_count; - float frame_time; - float frame_rate; - - struct - { - float x; - float y; - float scale; - /* Drop shadow color multiplier. */ - float drop_mod; - /* Drop shadow offset. - * If both are 0, no drop shadow will be rendered. */ - int drop_x, drop_y; - /* Drop shadow alpha */ - float drop_alpha; - /* ABGR. Use the macros. */ - uint32_t color; - bool full_screen; - enum text_alignment text_align; - } osd_stat_params; - - void (*cb_update_window_title)(void*, void *); - void (*cb_swap_buffers)(void*, void *); - bool (*cb_get_metrics)(void *data, enum display_metric_types type, - float *value); - bool (*cb_set_resize)(void*, unsigned, unsigned); - - bool (*cb_set_mvp)(void *data, void *shader_data, - const void *mat_data); - - void *context_data; - void *shader_data; - void *userdata; - const shader_backend_t *shader_driver; -} video_frame_info_t; - -typedef void (*update_window_title_cb)(void*, void*); -typedef bool (*get_metrics_cb)(void *data, enum display_metric_types type, - float *value); -typedef bool (*set_resize_cb)(void*, unsigned, unsigned); - -typedef struct gfx_ctx_driver -{ - /* The opaque pointer is the underlying video driver data (e.g. gl_t for - * OpenGL contexts). Although not advised, the context driver is allowed - * to hold a pointer to it as the context never outlives the video driver. - * - * The context driver is responsible for it's own data.*/ - void* (*init)(video_frame_info_t *video_info, void *video_driver); - void (*destroy)(void *data); - - enum gfx_ctx_api (*get_api)(void *data); - - /* Which API to bind to. */ - bool (*bind_api)(void *video_driver, enum gfx_ctx_api, - unsigned major, unsigned minor); - - /* Sets the swap interval. */ - void (*swap_interval)(void *data, int); - - /* Sets video mode. Creates a window, etc. */ - bool (*set_video_mode)(void*, video_frame_info_t *video_info, unsigned, unsigned, bool); - - /* Gets current window size. - * If not initialized yet, it returns current screen size. */ - void (*get_video_size)(void*, unsigned*, unsigned*); - - float (*get_refresh_rate)(void*); - - void (*get_video_output_size)(void*, unsigned*, unsigned*); - - void (*get_video_output_prev)(void*); - - void (*get_video_output_next)(void*); - - get_metrics_cb get_metrics; - - /* Translates a window size to an aspect ratio. - * In most cases this will be just width / height, but - * some contexts will better know which actual aspect ratio is used. - * This can be NULL to assume the default behavior. - */ - float (*translate_aspect)(void*, unsigned, unsigned); - - /* Asks driver to update window title (FPS, etc). */ - update_window_title_cb update_window_title; - - /* Queries for resize and quit events. - * Also processes events. */ - void (*check_window)(void*, bool*, bool*, - unsigned*, unsigned*, bool); - - /* Acknowledge a resize event. This is needed for some APIs. - * Most backends will ignore this. */ - set_resize_cb set_resize; - - /* Checks if window has input focus. */ - bool (*has_focus)(void*); - - /* Should the screensaver be suppressed? */ - bool (*suppress_screensaver)(void *data, bool enable); - - /* Checks if context driver has windowed support. */ - bool (*has_windowed)(void*); - - /* Swaps buffers. VBlank sync depends on - * earlier calls to swap_interval. */ - void (*swap_buffers)(void*, void *); - - /* Most video backends will want to use a certain input driver. - * Checks for it here. */ - void (*input_driver)(void*, const char *, const input_driver_t**, void**); - - /* Wraps whatever gl_proc_address() there is. - * Does not take opaque, to avoid lots of ugly wrapper code. */ - gfx_ctx_proc_t (*get_proc_address)(const char*); - - /* Returns true if this context supports EGLImage buffers for - * screen drawing and was initalized correctly. */ - bool (*image_buffer_init)(void*, const video_info_t*); - - /* Writes the frame to the EGLImage and sets image_handle to it. - * Returns true if a new image handle is created. - * Always returns true the first time it's called for a new index. - * The graphics core must handle a change in the handle correctly. */ - bool (*image_buffer_write)(void*, const void *frame, unsigned width, - unsigned height, unsigned pitch, bool rgb32, - unsigned index, void **image_handle); - - /* Shows or hides mouse. Can be NULL if context doesn't - * have a concept of mouse pointer. */ - void (*show_mouse)(void *data, bool state); - - /* Human readable string. */ - const char *ident; - - uint32_t (*get_flags)(void *data); - - void (*set_flags)(void *data, uint32_t flags); - - /* Optional. Binds HW-render offscreen context. */ - void (*bind_hw_render)(void *data, bool enable); - - /* Optional. Gets base data for the context which is used by the driver. - * This is mostly relevant for graphics APIs such as Vulkan - * which do not have global context state. */ - void *(*get_context_data)(void *data); - - /* Optional. Makes driver context (only GLX right now) - * active for this thread. */ - void (*make_current)(bool release); -} gfx_ctx_driver_t; - -typedef struct gfx_ctx_flags -{ - uint32_t flags; -} gfx_ctx_flags_t; - -typedef struct gfx_ctx_size -{ - bool *quit; - bool *resize; - unsigned *width; - unsigned *height; -} gfx_ctx_size_t; - -typedef struct gfx_ctx_mode -{ - unsigned width; - unsigned height; - bool fullscreen; -} gfx_ctx_mode_t; - -typedef struct gfx_ctx_metrics -{ - enum display_metric_types type; - float *value; -} gfx_ctx_metrics_t; - -typedef struct gfx_ctx_aspect -{ - float *aspect; - unsigned width; - unsigned height; -} gfx_ctx_aspect_t; - -typedef struct gfx_ctx_image -{ - const void *frame; - unsigned width; - unsigned height; - unsigned pitch; - unsigned index; - bool rgb32; - void **handle; -} gfx_ctx_image_t; - -typedef struct gfx_ctx_input -{ - const input_driver_t **input; - void **input_data; -} gfx_ctx_input_t; - -typedef struct gfx_ctx_proc_address -{ - const char *sym; - retro_proc_address_t addr; -} gfx_ctx_proc_address_t; - -typedef struct gfx_ctx_ident -{ - const char *ident; -} gfx_ctx_ident_t; - -struct aspect_ratio_elem -{ - char name[64]; - float value; -}; - -/* Optionally implemented interface to poke more - * deeply into video driver. */ - -typedef struct video_poke_interface -{ - uint32_t (*get_flags)(void *data); - void (*set_coords)(void *handle_data, void *shader_data, - const struct video_coords *coords); - void (*set_mvp)(void *data, void *shader_data, - const void *mat_data); - uintptr_t (*load_texture)(void *video_data, void *data, - bool threaded, enum texture_filter_type filter_type); - void (*unload_texture)(void *data, uintptr_t id); - void (*set_video_mode)(void *data, unsigned width, - unsigned height, bool fullscreen); - float (*get_refresh_rate)(void *data); - void (*set_filtering)(void *data, unsigned index, bool smooth); - void (*get_video_output_size)(void *data, - unsigned *width, unsigned *height); - - /* Move index to previous resolution */ - void (*get_video_output_prev)(void *data); - - /* Move index to next resolution */ - void (*get_video_output_next)(void *data); - - uintptr_t (*get_current_framebuffer)(void *data); - retro_proc_address_t (*get_proc_address)(void *data, const char *sym); - void (*set_aspect_ratio)(void *data, unsigned aspectratio_index); - void (*apply_state_changes)(void *data); - - /* Update texture. */ - void (*set_texture_frame)(void *data, const void *frame, bool rgb32, - unsigned width, unsigned height, float alpha); - /* Enable or disable rendering. */ - void (*set_texture_enable)(void *data, bool enable, bool full_screen); - void (*set_osd_msg)(void *data, video_frame_info_t *video_info, - const char *msg, - const void *params, void *font); - - void (*show_mouse)(void *data, bool state); - void (*grab_mouse_toggle)(void *data); - - struct video_shader *(*get_current_shader)(void *data); - bool (*get_current_software_framebuffer)(void *data, - struct retro_framebuffer *framebuffer); - bool (*get_hw_render_interface)(void *data, - const struct retro_hw_render_interface **iface); -} video_poke_interface_t; - -/* msg is for showing a message on the screen - * along with the video frame. */ -typedef bool (*video_driver_frame_t)(void *data, - const void *frame, unsigned width, - unsigned height, uint64_t frame_count, - unsigned pitch, const char *msg, video_frame_info_t *video_info); - -typedef struct video_driver -{ - /* Should the video driver act as an input driver as well? - * The video initialization might preinitialize an input driver - * to override the settings in case the video driver relies on - * input driver for event handling. */ - void *(*init)(const video_info_t *video, - const input_driver_t **input, - void **input_data); - - /* Updates frame on the screen. - * Frame can be either XRGB1555, RGB565 or ARGB32 format - * depending on rgb32 setting in video_info_t. - * Pitch is the distance in bytes between two scanlines in memory. - * - * When msg is non-NULL, - * it's a message that should be displayed to the user. */ - video_driver_frame_t frame; - - /* Should we care about syncing to vblank? Fast forwarding. - * - * Requests nonblocking operation. - * - * True = VSync is turned off. - * False = VSync is turned on. - * */ - void (*set_nonblock_state)(void *data, bool toggle); - - /* Is the window still active? */ - bool (*alive)(void *data); - - /* Does the window have focus? */ - bool (*focus)(void *data); - - /* Should the screensaver be suppressed? */ - bool (*suppress_screensaver)(void *data, bool enable); - - /* Does the graphics context support windowed mode? */ - bool (*has_windowed)(void *data); - - /* Sets shader. Might not be implemented. Will be moved to - * poke_interface later. */ - bool (*set_shader)(void *data, enum rarch_shader_type type, - const char *path); - - /* Frees driver. */ - void (*free)(void *data); - - /* Human-readable identifier. */ - const char *ident; - - void (*set_viewport)(void *data, unsigned width, unsigned height, - bool force_full, bool allow_rotate); - - void (*set_rotation)(void *data, unsigned rotation); - void (*viewport_info)(void *data, struct video_viewport *vp); - - /* Reads out in BGR byte order (24bpp). */ - bool (*read_viewport)(void *data, uint8_t *buffer, bool is_idle); - - /* Returns a pointer to a newly allocated buffer that can - * (and must) be passed to free() by the caller, containing a - * copy of the current raw frame in the active pixel format - * and sets width, height and pitch to the correct values. */ - void* (*read_frame_raw)(void *data, unsigned *width, - unsigned *height, size_t *pitch); - -#ifdef HAVE_OVERLAY - void (*overlay_interface)(void *data, - const video_overlay_interface_t **iface); -#endif - void (*poke_interface)(void *data, const video_poke_interface_t **iface); - unsigned (*wrap_type_to_enum)(enum gfx_wrap_type type); -} video_driver_t; - -extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END]; - -bool video_driver_has_windowed(void); - -bool video_driver_cached_frame_has_valid_framebuffer(void); - -void video_driver_destroy(void); -void video_driver_set_cached_frame_ptr(const void *data); -void video_driver_set_stub_frame(void); -void video_driver_unset_stub_frame(void); -bool video_driver_is_stub_frame(void); -bool video_driver_supports_recording(void); -bool video_driver_supports_viewport_read(void); -bool video_driver_supports_read_frame_raw(void); -void video_driver_set_viewport_config(void); -void video_driver_set_viewport_square_pixel(void); -void video_driver_set_viewport_core(void); -void video_driver_reset_custom_viewport(void); -void video_driver_set_rgba(void); -void video_driver_unset_rgba(void); -bool video_driver_supports_rgba(void); -bool video_driver_get_next_video_out(void); -bool video_driver_get_prev_video_out(void); -bool video_driver_init(bool *video_is_threaded); -void video_driver_destroy_data(void); -void video_driver_free(void); -void video_driver_free_hw_context(void); -void video_driver_monitor_reset(void); -void video_driver_set_aspect_ratio(void); -void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect); -void video_driver_show_mouse(void); -void video_driver_hide_mouse(void); -void video_driver_set_nonblock_state(bool toggle); -bool video_driver_find_driver(void); -void video_driver_apply_state_changes(void); -bool video_driver_read_viewport(uint8_t *buffer, bool is_idle); -bool video_driver_cached_frame(void); -bool video_driver_frame_filter_alive(void); -bool video_driver_frame_filter_is_32bit(void); -void video_driver_default_settings(void); -void video_driver_load_settings(config_file_t *conf); -void video_driver_save_settings(config_file_t *conf); -void video_driver_set_own_driver(void); -void video_driver_unset_own_driver(void); -bool video_driver_owns_driver(void); -bool video_driver_is_hw_context(void); -struct retro_hw_render_callback *video_driver_get_hw_context(void); -const struct retro_hw_render_context_negotiation_interface -*video_driver_get_context_negotiation_interface(void); -void video_driver_set_context_negotiation_interface(const struct - retro_hw_render_context_negotiation_interface *iface); -bool video_driver_is_video_cache_context(void); -void video_driver_set_video_cache_context_ack(void); -bool video_driver_is_video_cache_context_ack(void); -void video_driver_set_active(void); -void video_driver_unset_active(void); -bool video_driver_is_active(void); -bool video_driver_gpu_record_init(unsigned size); -void video_driver_gpu_record_deinit(void); -bool video_driver_get_current_software_framebuffer(struct - retro_framebuffer *fb); -bool video_driver_get_hw_render_interface(const struct - retro_hw_render_interface **iface); -bool video_driver_get_viewport_info(struct video_viewport *viewport); -void video_driver_set_title_buf(void); -void video_driver_monitor_adjust_system_rates(void); - -/** - * video_driver_find_handle: - * @index : index of driver to get handle to. - * - * Returns: handle to video driver at index. Can be NULL - * if nothing found. - **/ -const void *video_driver_find_handle(int index); - -/** - * video_driver_find_ident: - * @index : index of driver to get handle to. - * - * Returns: Human-readable identifier of video driver at index. - * Can be NULL if nothing found. - **/ -const char *video_driver_find_ident(int index); - -/** - * config_get_video_driver_options: - * - * Get an enumerated list of all video driver names, separated by '|'. - * - * Returns: string listing of all video driver names, separated by '|'. - **/ -const char* config_get_video_driver_options(void); - -/** - * video_driver_get_ptr: - * - * Use this if you need the real video driver - * and driver data pointers. - * - * Returns: video driver's userdata. - **/ -void *video_driver_get_ptr(bool force_nonthreaded_data); - -/** - * video_driver_get_current_framebuffer: - * - * Gets pointer to current hardware renderer framebuffer object. - * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. - * - * Returns: pointer to hardware framebuffer object, otherwise 0. - **/ -uintptr_t video_driver_get_current_framebuffer(void); - -retro_proc_address_t video_driver_get_proc_address(const char *sym); - -bool video_driver_set_shader(enum rarch_shader_type type, - const char *shader); - -bool video_driver_set_rotation(unsigned rotation); - -bool video_driver_set_video_mode(unsigned width, - unsigned height, bool fullscreen); - -bool video_driver_get_video_output_size( - unsigned *width, unsigned *height); - -void video_driver_set_osd_msg(const char *msg, - const void *params, void *font); - -void video_driver_set_texture_enable(bool enable, bool full_screen); - -void video_driver_set_texture_frame(const void *frame, bool rgb32, - unsigned width, unsigned height, float alpha); - -#ifdef HAVE_OVERLAY -bool video_driver_overlay_interface( - const video_overlay_interface_t **iface); -#endif - -void * video_driver_read_frame_raw(unsigned *width, - unsigned *height, size_t *pitch); - -void video_driver_set_filtering(unsigned index, bool smooth); - -const char *video_driver_get_ident(void); - -bool video_driver_set_viewport(unsigned width, unsigned height, - bool force_fullscreen, bool allow_rotate); - -void video_driver_get_size(unsigned *width, unsigned *height); - -void video_driver_set_size(unsigned *width, unsigned *height); - -void video_driver_unset_video_cache_context_ack(void); - -float video_driver_get_aspect_ratio(void); - -void video_driver_set_aspect_ratio_value(float value); - -rarch_softfilter_t *video_driver_frame_filter_get_ptr(void); - -enum retro_pixel_format video_driver_get_pixel_format(void); - -void video_driver_set_pixel_format(enum retro_pixel_format fmt); - -void video_driver_cached_frame_set(const void *data, unsigned width, - unsigned height, size_t pitch); - -void video_driver_cached_frame_get(const void **data, unsigned *width, - unsigned *height, size_t *pitch); - -void video_driver_menu_settings(void **list_data, void *list_info_data, - void *group_data, void *subgroup_data, const char *parent_group); - -/** - * video_viewport_get_scaled_integer: - * @vp : Viewport handle - * @width : Width. - * @height : Height. - * @aspect_ratio : Aspect ratio (in float). - * @keep_aspect : Preserve aspect ratio? - * - * Gets viewport scaling dimensions based on - * scaled integer aspect ratio. - **/ -void video_viewport_get_scaled_integer(struct video_viewport *vp, - unsigned width, unsigned height, - float aspect_ratio, bool keep_aspect); - -struct retro_system_av_info *video_viewport_get_system_av_info(void); - -struct video_viewport *video_viewport_get_custom(void); - -/** - * video_monitor_set_refresh_rate: - * @hz : New refresh rate for monitor. - * - * Sets monitor refresh rate to new value. - **/ -void video_monitor_set_refresh_rate(float hz); - -/** - * video_monitor_fps_statistics - * @refresh_rate : Monitor refresh rate. - * @deviation : Deviation from measured refresh rate. - * @sample_points : Amount of sampled points. - * - * Gets the monitor FPS statistics based on the current - * runtime. - * - * Returns: true (1) on success. - * false (0) if: - * a) threaded video mode is enabled - * b) less than 2 frame time samples. - * c) FPS monitor enable is off. - **/ -bool video_monitor_fps_statistics(double *refresh_rate, - double *deviation, unsigned *sample_points); - -unsigned video_pixel_get_alignment(unsigned pitch); - -const video_poke_interface_t *video_driver_get_poke(void); - -/** - * video_driver_frame: - * @data : pointer to data of the video frame. - * @width : width of the video frame. - * @height : height of the video frame. - * @pitch : pitch of the video frame. - * - * Video frame render callback function. - **/ -void video_driver_frame(const void *data, unsigned width, - unsigned height, size_t pitch); - -void crt_switch_driver_reinit(void); - -#define video_driver_translate_coord_viewport_wrap(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) \ - (video_driver_get_viewport_info(vp) ? video_driver_translate_coord_viewport(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) : false) - -/** - * video_driver_translate_coord_viewport: - * @mouse_x : Pointer X coordinate. - * @mouse_y : Pointer Y coordinate. - * @res_x : Scaled X coordinate. - * @res_y : Scaled Y coordinate. - * @res_screen_x : Scaled screen X coordinate. - * @res_screen_y : Scaled screen Y coordinate. - * - * Translates pointer [X,Y] coordinates into scaled screen - * coordinates based on viewport info. - * - * Returns: true (1) if successful, false if video driver doesn't support - * viewport info. - **/ -bool video_driver_translate_coord_viewport( - struct video_viewport *vp, - int mouse_x, int mouse_y, - int16_t *res_x, int16_t *res_y, int16_t *res_screen_x, - int16_t *res_screen_y); - -uintptr_t video_driver_display_get(void); - -enum rarch_display_type video_driver_display_type_get(void); - -uintptr_t video_driver_window_get(void); - -void video_driver_display_type_set(enum rarch_display_type type); - -void video_driver_display_set(uintptr_t idx); - -void video_driver_window_set(uintptr_t idx); - -bool video_driver_texture_load(void *data, - enum texture_filter_type filter_type, - uintptr_t *id); - -bool video_driver_texture_unload(uintptr_t *id); - -void video_driver_build_info(video_frame_info_t *video_info); - -void video_driver_reinit(void); - -void video_driver_get_window_title(char *buf, unsigned len); - -void video_driver_get_record_status( - bool *has_gpu_record, - uint8_t **gpu_buf); - -bool *video_driver_get_threaded(void); - -void video_driver_set_threaded(bool val); - -void video_driver_get_status(uint64_t *frame_count, bool * is_alive, - bool *is_focused); - -/** - * video_context_driver_init_first: - * @data : Input data. - * @ident : Identifier of graphics context driver to find. - * @api : API of higher-level graphics API. - * @major : Major version number of higher-level graphics API. - * @minor : Minor version number of higher-level graphics API. - * @hw_render_ctx : Request a graphics context driver capable of - * hardware rendering? - * - * Finds first suitable graphics context driver and initializes. - * - * Returns: graphics context driver if found, otherwise NULL. - **/ -const gfx_ctx_driver_t *video_context_driver_init_first( - void *data, const char *ident, - enum gfx_ctx_api api, unsigned major, unsigned minor, - bool hw_render_ctx, void **ctx_data); - -bool video_context_driver_find_prev_driver(void); - -bool video_context_driver_find_next_driver(void); - -bool video_context_driver_init_image_buffer(const video_info_t *data); - -bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img); - -bool video_context_driver_get_video_output_prev(void); - -bool video_context_driver_get_video_output_next(void); - -bool video_context_driver_bind_hw_render(bool *enable); - -void video_context_driver_make_current(bool restore); - -bool video_context_driver_set(const gfx_ctx_driver_t *data); - -void video_context_driver_destroy(void); - -bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data); - -bool video_context_driver_swap_interval(int *interval); - -bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc); - -bool video_context_driver_suppress_screensaver(bool *bool_data); - -bool video_context_driver_get_ident(gfx_ctx_ident_t *ident); - -bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info); - -bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info); - -bool video_context_driver_get_refresh_rate(float *refresh_rate); - -bool video_context_driver_show_mouse(bool *bool_data); - -bool video_context_driver_set_flags(gfx_ctx_flags_t *flags); - -bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics); - -bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect); - -bool video_context_driver_input_driver(gfx_ctx_input_t *inp); - -enum gfx_ctx_api video_context_driver_get_api(void); - -void video_context_driver_free(void); - -bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident); - -bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader); - -bool video_shader_driver_deinit(void); - -bool video_shader_driver_init_first(void); - -bool video_shader_driver_init(video_shader_ctx_init_t *init); - -void video_driver_set_coords(video_shader_ctx_coords_t *coords); - -bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler); - -bool video_shader_driver_info(video_shader_ctx_info_t *shader_info); - -void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp); - -float video_driver_get_refresh_rate(void); - -extern bool (*video_driver_cb_has_focus)(void); - -bool video_driver_started_fullscreen(void); - -bool video_driver_is_threaded(void); - -bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, - enum display_flags flag); - -extern video_driver_t video_gl; -extern video_driver_t video_vulkan; -extern video_driver_t video_metal; -extern video_driver_t video_psp1; -extern video_driver_t video_vita2d; -extern video_driver_t video_ps2; -extern video_driver_t video_ctr; -extern video_driver_t video_switch; -extern video_driver_t video_d3d8; -extern video_driver_t video_d3d9; -extern video_driver_t video_d3d10; -extern video_driver_t video_d3d11; -extern video_driver_t video_d3d12; -extern video_driver_t video_gx; -extern video_driver_t video_wiiu; -extern video_driver_t video_xenon360; -extern video_driver_t video_xvideo; -extern video_driver_t video_sdl; -extern video_driver_t video_sdl2; -extern video_driver_t video_vg; -extern video_driver_t video_omap; -extern video_driver_t video_exynos; -extern video_driver_t video_dispmanx; -extern video_driver_t video_sunxi; -extern video_driver_t video_drm; -extern video_driver_t video_xshm; -extern video_driver_t video_caca; -extern video_driver_t video_gdi; -extern video_driver_t video_vga; -extern video_driver_t video_sixel; -extern video_driver_t video_null; - -extern const gfx_ctx_driver_t gfx_ctx_osmesa; -extern const gfx_ctx_driver_t gfx_ctx_sdl_gl; -extern const gfx_ctx_driver_t gfx_ctx_x_egl; -extern const gfx_ctx_driver_t gfx_ctx_wayland; -extern const gfx_ctx_driver_t gfx_ctx_x; -extern const gfx_ctx_driver_t gfx_ctx_drm; -extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev; -extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev; -extern const gfx_ctx_driver_t gfx_ctx_android; -extern const gfx_ctx_driver_t gfx_ctx_ps3; -extern const gfx_ctx_driver_t gfx_ctx_wgl; -extern const gfx_ctx_driver_t gfx_ctx_videocore; -extern const gfx_ctx_driver_t gfx_ctx_qnx; -extern const gfx_ctx_driver_t gfx_ctx_cgl; -extern const gfx_ctx_driver_t gfx_ctx_cocoagl; -extern const gfx_ctx_driver_t gfx_ctx_emscripten; -extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; -extern const gfx_ctx_driver_t gfx_ctx_khr_display; -extern const gfx_ctx_driver_t gfx_ctx_gdi; -extern const gfx_ctx_driver_t gfx_ctx_sixel; -extern const gfx_ctx_driver_t switch_ctx; -extern const gfx_ctx_driver_t orbis_ctx; -extern const gfx_ctx_driver_t gfx_ctx_null; - -extern const shader_backend_t gl_glsl_backend; -extern const shader_backend_t gl_cg_backend; -extern const shader_backend_t shader_null_backend; - -RETRO_END_DECLS - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __VIDEO_DRIVER__H +#define __VIDEO_DRIVER__H + +#include +#include +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#ifdef HAVE_OVERLAY +#include "../input/input_overlay.h" +#endif + +#include "video_defines.h" +#include "video_coord_array.h" +#include "video_filter.h" +#include "video_shader_parse.h" + +#include "../input/input_types.h" + +#define RARCH_SCALE_BASE 256 + +#include "video_shader_parse.h" + +#define VIDEO_SHADER_STOCK_BLEND (GFX_MAX_SHADERS - 1) +#define VIDEO_SHADER_MENU (GFX_MAX_SHADERS - 2) +#define VIDEO_SHADER_MENU_2 (GFX_MAX_SHADERS - 3) +#define VIDEO_SHADER_MENU_3 (GFX_MAX_SHADERS - 4) +#define VIDEO_SHADER_MENU_4 (GFX_MAX_SHADERS - 5) +#define VIDEO_SHADER_MENU_5 (GFX_MAX_SHADERS - 6) +#define VIDEO_SHADER_MENU_6 (GFX_MAX_SHADERS - 7) + +#if defined(_XBOX360) +#define DEFAULT_SHADER_TYPE RARCH_SHADER_HLSL +#elif defined(__PSL1GHT__) || defined(HAVE_OPENGLES2) || defined(HAVE_GLSL) +#define DEFAULT_SHADER_TYPE RARCH_SHADER_GLSL +#elif defined(__CELLOS_LV2__) || defined(HAVE_CG) +#define DEFAULT_SHADER_TYPE RARCH_SHADER_CG +#else +#define DEFAULT_SHADER_TYPE RARCH_SHADER_NONE +#endif + +RETRO_BEGIN_DECLS + +#ifndef MAX_EGLIMAGE_TEXTURES +#define MAX_EGLIMAGE_TEXTURES 32 +#endif + +#define MAX_VARIABLES 64 + +enum +{ + TEXTURES = 8, + TEXTURESMASK = TEXTURES - 1 +}; + +struct LinkInfo +{ + unsigned tex_w, tex_h; + struct video_shader_pass *pass; +}; + +enum gfx_ctx_api +{ + GFX_CTX_NONE = 0, + GFX_CTX_OPENGL_API, + GFX_CTX_OPENGL_ES_API, + GFX_CTX_DIRECT3D8_API, + GFX_CTX_DIRECT3D9_API, + GFX_CTX_DIRECT3D10_API, + GFX_CTX_DIRECT3D11_API, + GFX_CTX_DIRECT3D12_API, + GFX_CTX_OPENVG_API, + GFX_CTX_VULKAN_API, + GFX_CTX_SIXEL_API, + GFX_CTX_METAL_API, + GFX_CTX_GDI_API, + GFX_CTX_GX_API, + GFX_CTX_GX2_API +}; + +enum display_metric_types +{ + DISPLAY_METRIC_NONE = 0, + DISPLAY_METRIC_MM_WIDTH, + DISPLAY_METRIC_MM_HEIGHT, + DISPLAY_METRIC_DPI +}; + +enum display_flags +{ + GFX_CTX_FLAGS_NONE = 0, + GFX_CTX_FLAGS_GL_CORE_CONTEXT, + GFX_CTX_FLAGS_MULTISAMPLING, + GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES, + GFX_CTX_FLAGS_HARD_SYNC, + GFX_CTX_FLAGS_BLACK_FRAME_INSERTION, + GFX_CTX_FLAGS_MENU_FRAME_FILTERING, + GFX_CTX_FLAGS_ADAPTIVE_VSYNC +}; + +enum shader_uniform_type +{ + UNIFORM_1F = 0, + UNIFORM_2F, + UNIFORM_3F, + UNIFORM_4F, + UNIFORM_1FV, + UNIFORM_2FV, + UNIFORM_3FV, + UNIFORM_4FV, + UNIFORM_1I +}; + +enum shader_program_type +{ + SHADER_PROGRAM_VERTEX = 0, + SHADER_PROGRAM_FRAGMENT, + SHADER_PROGRAM_COMBINED +}; + +struct shader_program_info +{ + bool is_file; + const char *vertex; + const char *fragment; + const char *combined; + unsigned idx; + void *data; +}; + +struct uniform_info +{ + bool enabled; + + int32_t location; + int32_t count; + unsigned type; /* shader uniform type */ + + struct + { + enum shader_program_type type; + const char *ident; + uint32_t idx; + bool add_prefix; + bool enable; + } lookup; + + struct + { + struct + { + intptr_t v0; + intptr_t v1; + intptr_t v2; + intptr_t v3; + } integer; + + intptr_t *integerv; + + struct + { + uintptr_t v0; + uintptr_t v1; + uintptr_t v2; + uintptr_t v3; + } unsigned_integer; + + uintptr_t *unsigned_integerv; + + struct + { + float v0; + float v1; + float v2; + float v3; + } f; + + float *floatv; + } result; +}; + +typedef struct shader_backend +{ + void *(*init)(void *data, const char *path); + void (*init_menu_shaders)(void *data); + void (*deinit)(void *data); + + /* Set shader parameters. */ + void (*set_params)(void *data, void *shader_data); + + void (*set_uniform_parameter)(void *data, struct uniform_info *param, + void *uniform_data); + + /* Compile a shader program. */ + bool (*compile_program)(void *data, unsigned idx, + void *program_data, struct shader_program_info *program_info); + + /* Use a shader program specified by variable 'index'. */ + void (*use)(void *data, void *shader_data, unsigned index, bool set_active); + + /* Returns the number of currently loaded shaders. */ + unsigned (*num_shaders)(void *data); + + bool (*filter_type)(void *data, unsigned index, bool *smooth); + enum gfx_wrap_type (*wrap_type)(void *data, unsigned index); + void (*shader_scale)(void *data, + unsigned index, struct gfx_fbo_scale *scale); + bool (*set_coords)(void *handle_data, + void *shader_data, const struct video_coords *coords); + bool (*set_mvp)(void *data, void *shader_data, + const void *mat_data); + unsigned (*get_prev_textures)(void *data); + bool (*get_feedback_pass)(void *data, unsigned *pass); + bool (*mipmap_input)(void *data, unsigned index); + + struct video_shader *(*get_current_shader)(void *data); + + enum rarch_shader_type type; + + /* Human readable string. */ + const char *ident; +} shader_backend_t; + +typedef struct video_shader_ctx_init +{ + enum rarch_shader_type shader_type; + const char *path; + const shader_backend_t *shader; + void *data; + void *shader_data; + struct + { + bool core_context_enabled; + } gl; +} video_shader_ctx_init_t; + +typedef struct video_shader_ctx_params +{ + unsigned width; + unsigned height; + unsigned tex_width; + unsigned tex_height; + unsigned out_width; + unsigned out_height; + unsigned frame_counter; + unsigned fbo_info_cnt; + void *data; + const void *info; + const void *prev_info; + const void *feedback_info; + const void *fbo_info; +} video_shader_ctx_params_t; + +typedef struct video_shader_ctx_coords +{ + void *handle_data; + const void *data; +} video_shader_ctx_coords_t; + +typedef struct video_shader_ctx_scale +{ + unsigned idx; + struct gfx_fbo_scale *scale; +} video_shader_ctx_scale_t; + +typedef struct video_shader_ctx_info +{ + bool set_active; + unsigned num; + unsigned idx; + void *data; +} video_shader_ctx_info_t; + +typedef struct video_shader_ctx_mvp +{ + void *data; + const void *matrix; +} video_shader_ctx_mvp_t; + +typedef struct video_shader_ctx_filter +{ + unsigned index; + bool *smooth; +} video_shader_ctx_filter_t; + +typedef struct video_shader_ctx +{ + struct video_shader *data; +} video_shader_ctx_t; + +typedef struct video_shader_ctx_ident +{ + const char *ident; +} video_shader_ctx_ident_t; + +typedef struct video_shader_ctx_texture +{ + unsigned id; +} video_shader_ctx_texture_t; + +typedef void (*gfx_ctx_proc_t)(void); + +typedef struct video_info +{ + /* Launch in fullscreen mode instead of windowed mode. */ + bool fullscreen; + + /* Start with V-Sync enabled. */ + bool vsync; + + /* If true, the output image should have the aspect ratio + * as set in aspect_ratio. */ + bool force_aspect; + + bool font_enable; + + /* Width of window. + * If fullscreen mode is requested, + * a width of 0 means the resolution of the + * desktop should be used. */ + unsigned width; + + /* Height of window. + * If fullscreen mode is requested, + * a height of 0 means the resolutiof the desktop should be used. + */ + unsigned height; + + int swap_interval; + +#ifdef GEKKO + bool vfilter; +#endif + + /* If true, applies bilinear filtering to the image, + * otherwise nearest filtering. */ + bool smooth; + + bool is_threaded; + + /* Use 32bit RGBA rather than native RGB565/XBGR1555. + * + * XRGB1555 format is 16-bit and has byte ordering: 0RRRRRGGGGGBBBBB, + * in native endian. + * + * ARGB8888 is AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB, native endian. + * Alpha channel should be disregarded. + * */ + bool rgb32; + +#ifdef GEKKO + /* TODO - we can't really have driver system-specific + * variables in here. There should be some + * kind of publicly accessible driver implementation + * video struct for specific things like this. + */ + + /* Wii-specific settings. Ignored for everything else. */ + unsigned viwidth; +#endif + + /* + * input_scale defines the maximum size of the picture that will + * ever be used with the frame callback. + * + * The maximum resolution is a multiple of 256x256 size (RARCH_SCALE_BASE), + * so an input scale of 2 means you should allocate a texture or of 512x512. + * + * Maximum input size: RARCH_SCALE_BASE * input_scale + */ + unsigned input_scale; + + uintptr_t parent; +} video_info_t; + +typedef struct video_frame_info +{ + bool input_menu_swap_ok_cancel_buttons; + bool input_driver_nonblock_state; + bool shared_context; + bool black_frame_insertion; + bool hard_sync; + bool fps_show; + bool statistics_show; + bool framecount_show; + bool scale_integer; + bool post_filter_record; + bool windowed_fullscreen; + bool fullscreen; + bool font_enable; + bool use_rgba; + bool libretro_running; + bool xmb_shadows_enable; + bool battery_level_enable; + bool timedate_enable; + bool runloop_is_slowmotion; + bool runloop_is_idle; + bool runloop_is_paused; + bool is_perfcnt_enable; + bool menu_is_alive; + bool msg_bgcolor_enable; + + int custom_vp_x; + int custom_vp_y; + int crt_switch_center_adjust; + + unsigned hard_sync_frames; + unsigned aspect_ratio_idx; + unsigned max_swapchain_images; + unsigned monitor_index; + unsigned crt_switch_resolution; + unsigned crt_switch_resolution_super; + unsigned width; + unsigned height; + unsigned xmb_theme; + unsigned xmb_color_theme; + unsigned menu_shader_pipeline; + unsigned materialui_color_theme; + unsigned ozone_color_theme; + unsigned custom_vp_width; + unsigned custom_vp_height; + unsigned custom_vp_full_width; + unsigned custom_vp_full_height; + + float menu_wallpaper_opacity; + float menu_framebuffer_opacity; + float menu_header_opacity; + float menu_footer_opacity; + float refresh_rate; + float font_msg_pos_x; + float font_msg_pos_y; + float font_msg_color_r; + float font_msg_color_g; + float font_msg_color_b; + float xmb_alpha_factor; + + char fps_text[128]; + char stat_text[512]; + char chat_text[256]; + + uint64_t frame_count; + float frame_time; + float frame_rate; + + struct + { + float x; + float y; + float scale; + /* Drop shadow color multiplier. */ + float drop_mod; + /* Drop shadow offset. + * If both are 0, no drop shadow will be rendered. */ + int drop_x, drop_y; + /* Drop shadow alpha */ + float drop_alpha; + /* ABGR. Use the macros. */ + uint32_t color; + bool full_screen; + enum text_alignment text_align; + } osd_stat_params; + + void (*cb_update_window_title)(void*, void *); + void (*cb_swap_buffers)(void*, void *); + bool (*cb_get_metrics)(void *data, enum display_metric_types type, + float *value); + bool (*cb_set_resize)(void*, unsigned, unsigned); + + bool (*cb_set_mvp)(void *data, void *shader_data, + const void *mat_data); + + void *context_data; + void *shader_data; + void *userdata; + const shader_backend_t *shader_driver; +} video_frame_info_t; + +typedef void (*update_window_title_cb)(void*, void*); +typedef bool (*get_metrics_cb)(void *data, enum display_metric_types type, + float *value); +typedef bool (*set_resize_cb)(void*, unsigned, unsigned); + +typedef struct gfx_ctx_driver +{ + /* The opaque pointer is the underlying video driver data (e.g. gl_t for + * OpenGL contexts). Although not advised, the context driver is allowed + * to hold a pointer to it as the context never outlives the video driver. + * + * The context driver is responsible for it's own data.*/ + void* (*init)(video_frame_info_t *video_info, void *video_driver); + void (*destroy)(void *data); + + enum gfx_ctx_api (*get_api)(void *data); + + /* Which API to bind to. */ + bool (*bind_api)(void *video_driver, enum gfx_ctx_api, + unsigned major, unsigned minor); + + /* Sets the swap interval. */ + void (*swap_interval)(void *data, int); + + /* Sets video mode. Creates a window, etc. */ + bool (*set_video_mode)(void*, video_frame_info_t *video_info, unsigned, unsigned, bool); + + /* Gets current window size. + * If not initialized yet, it returns current screen size. */ + void (*get_video_size)(void*, unsigned*, unsigned*); + + float (*get_refresh_rate)(void*); + + void (*get_video_output_size)(void*, unsigned*, unsigned*); + + void (*get_video_output_prev)(void*); + + void (*get_video_output_next)(void*); + + get_metrics_cb get_metrics; + + /* Translates a window size to an aspect ratio. + * In most cases this will be just width / height, but + * some contexts will better know which actual aspect ratio is used. + * This can be NULL to assume the default behavior. + */ + float (*translate_aspect)(void*, unsigned, unsigned); + + /* Asks driver to update window title (FPS, etc). */ + update_window_title_cb update_window_title; + + /* Queries for resize and quit events. + * Also processes events. */ + void (*check_window)(void*, bool*, bool*, + unsigned*, unsigned*, bool); + + /* Acknowledge a resize event. This is needed for some APIs. + * Most backends will ignore this. */ + set_resize_cb set_resize; + + /* Checks if window has input focus. */ + bool (*has_focus)(void*); + + /* Should the screensaver be suppressed? */ + bool (*suppress_screensaver)(void *data, bool enable); + + /* Checks if context driver has windowed support. */ + bool (*has_windowed)(void*); + + /* Swaps buffers. VBlank sync depends on + * earlier calls to swap_interval. */ + void (*swap_buffers)(void*, void *); + + /* Most video backends will want to use a certain input driver. + * Checks for it here. */ + void (*input_driver)(void*, const char *, const input_driver_t**, void**); + + /* Wraps whatever gl_proc_address() there is. + * Does not take opaque, to avoid lots of ugly wrapper code. */ + gfx_ctx_proc_t (*get_proc_address)(const char*); + + /* Returns true if this context supports EGLImage buffers for + * screen drawing and was initalized correctly. */ + bool (*image_buffer_init)(void*, const video_info_t*); + + /* Writes the frame to the EGLImage and sets image_handle to it. + * Returns true if a new image handle is created. + * Always returns true the first time it's called for a new index. + * The graphics core must handle a change in the handle correctly. */ + bool (*image_buffer_write)(void*, const void *frame, unsigned width, + unsigned height, unsigned pitch, bool rgb32, + unsigned index, void **image_handle); + + /* Shows or hides mouse. Can be NULL if context doesn't + * have a concept of mouse pointer. */ + void (*show_mouse)(void *data, bool state); + + /* Human readable string. */ + const char *ident; + + uint32_t (*get_flags)(void *data); + + void (*set_flags)(void *data, uint32_t flags); + + /* Optional. Binds HW-render offscreen context. */ + void (*bind_hw_render)(void *data, bool enable); + + /* Optional. Gets base data for the context which is used by the driver. + * This is mostly relevant for graphics APIs such as Vulkan + * which do not have global context state. */ + void *(*get_context_data)(void *data); + + /* Optional. Makes driver context (only GLX right now) + * active for this thread. */ + void (*make_current)(bool release); +} gfx_ctx_driver_t; + +typedef struct gfx_ctx_flags +{ + uint32_t flags; +} gfx_ctx_flags_t; + +typedef struct gfx_ctx_size +{ + bool *quit; + bool *resize; + unsigned *width; + unsigned *height; +} gfx_ctx_size_t; + +typedef struct gfx_ctx_mode +{ + unsigned width; + unsigned height; + bool fullscreen; +} gfx_ctx_mode_t; + +typedef struct gfx_ctx_metrics +{ + enum display_metric_types type; + float *value; +} gfx_ctx_metrics_t; + +typedef struct gfx_ctx_aspect +{ + float *aspect; + unsigned width; + unsigned height; +} gfx_ctx_aspect_t; + +typedef struct gfx_ctx_image +{ + const void *frame; + unsigned width; + unsigned height; + unsigned pitch; + unsigned index; + bool rgb32; + void **handle; +} gfx_ctx_image_t; + +typedef struct gfx_ctx_input +{ + const input_driver_t **input; + void **input_data; +} gfx_ctx_input_t; + +typedef struct gfx_ctx_proc_address +{ + const char *sym; + retro_proc_address_t addr; +} gfx_ctx_proc_address_t; + +typedef struct gfx_ctx_ident +{ + const char *ident; +} gfx_ctx_ident_t; + +struct aspect_ratio_elem +{ + char name[64]; + float value; +}; + +/* Optionally implemented interface to poke more + * deeply into video driver. */ + +typedef struct video_poke_interface +{ + uint32_t (*get_flags)(void *data); + void (*set_coords)(void *handle_data, void *shader_data, + const struct video_coords *coords); + void (*set_mvp)(void *data, void *shader_data, + const void *mat_data); + uintptr_t (*load_texture)(void *video_data, void *data, + bool threaded, enum texture_filter_type filter_type); + void (*unload_texture)(void *data, uintptr_t id); + void (*set_video_mode)(void *data, unsigned width, + unsigned height, bool fullscreen); + float (*get_refresh_rate)(void *data); + void (*set_filtering)(void *data, unsigned index, bool smooth); + void (*get_video_output_size)(void *data, + unsigned *width, unsigned *height); + + /* Move index to previous resolution */ + void (*get_video_output_prev)(void *data); + + /* Move index to next resolution */ + void (*get_video_output_next)(void *data); + + uintptr_t (*get_current_framebuffer)(void *data); + retro_proc_address_t (*get_proc_address)(void *data, const char *sym); + void (*set_aspect_ratio)(void *data, unsigned aspectratio_index); + void (*apply_state_changes)(void *data); + + /* Update texture. */ + void (*set_texture_frame)(void *data, const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha); + /* Enable or disable rendering. */ + void (*set_texture_enable)(void *data, bool enable, bool full_screen); + void (*set_osd_msg)(void *data, video_frame_info_t *video_info, + const char *msg, + const void *params, void *font); + + void (*show_mouse)(void *data, bool state); + void (*grab_mouse_toggle)(void *data); + + struct video_shader *(*get_current_shader)(void *data); + bool (*get_current_software_framebuffer)(void *data, + struct retro_framebuffer *framebuffer); + bool (*get_hw_render_interface)(void *data, + const struct retro_hw_render_interface **iface); +} video_poke_interface_t; + +/* msg is for showing a message on the screen + * along with the video frame. */ +typedef bool (*video_driver_frame_t)(void *data, + const void *frame, unsigned width, + unsigned height, uint64_t frame_count, + unsigned pitch, const char *msg, video_frame_info_t *video_info); + +typedef struct video_driver +{ + /* Should the video driver act as an input driver as well? + * The video initialization might preinitialize an input driver + * to override the settings in case the video driver relies on + * input driver for event handling. */ + void *(*init)(const video_info_t *video, + const input_driver_t **input, + void **input_data); + + /* Updates frame on the screen. + * Frame can be either XRGB1555, RGB565 or ARGB32 format + * depending on rgb32 setting in video_info_t. + * Pitch is the distance in bytes between two scanlines in memory. + * + * When msg is non-NULL, + * it's a message that should be displayed to the user. */ + video_driver_frame_t frame; + + /* Should we care about syncing to vblank? Fast forwarding. + * + * Requests nonblocking operation. + * + * True = VSync is turned off. + * False = VSync is turned on. + * */ + void (*set_nonblock_state)(void *data, bool toggle); + + /* Is the window still active? */ + bool (*alive)(void *data); + + /* Does the window have focus? */ + bool (*focus)(void *data); + + /* Should the screensaver be suppressed? */ + bool (*suppress_screensaver)(void *data, bool enable); + + /* Does the graphics context support windowed mode? */ + bool (*has_windowed)(void *data); + + /* Sets shader. Might not be implemented. Will be moved to + * poke_interface later. */ + bool (*set_shader)(void *data, enum rarch_shader_type type, + const char *path); + + /* Frees driver. */ + void (*free)(void *data); + + /* Human-readable identifier. */ + const char *ident; + + void (*set_viewport)(void *data, unsigned width, unsigned height, + bool force_full, bool allow_rotate); + + void (*set_rotation)(void *data, unsigned rotation); + void (*viewport_info)(void *data, struct video_viewport *vp); + + /* Reads out in BGR byte order (24bpp). */ + bool (*read_viewport)(void *data, uint8_t *buffer, bool is_idle); + + /* Returns a pointer to a newly allocated buffer that can + * (and must) be passed to free() by the caller, containing a + * copy of the current raw frame in the active pixel format + * and sets width, height and pitch to the correct values. */ + void* (*read_frame_raw)(void *data, unsigned *width, + unsigned *height, size_t *pitch); + +#ifdef HAVE_OVERLAY + void (*overlay_interface)(void *data, + const video_overlay_interface_t **iface); +#endif + void (*poke_interface)(void *data, const video_poke_interface_t **iface); + unsigned (*wrap_type_to_enum)(enum gfx_wrap_type type); +} video_driver_t; + +extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END]; + +bool video_driver_has_windowed(void); + +bool video_driver_cached_frame_has_valid_framebuffer(void); + +void video_driver_destroy(void); +void video_driver_set_cached_frame_ptr(const void *data); +void video_driver_set_stub_frame(void); +void video_driver_unset_stub_frame(void); +bool video_driver_is_stub_frame(void); +bool video_driver_supports_recording(void); +bool video_driver_supports_viewport_read(void); +bool video_driver_supports_read_frame_raw(void); +void video_driver_set_viewport_config(void); +void video_driver_set_viewport_square_pixel(void); +void video_driver_set_viewport_core(void); +void video_driver_reset_custom_viewport(void); +void video_driver_set_rgba(void); +void video_driver_unset_rgba(void); +bool video_driver_supports_rgba(void); +bool video_driver_get_next_video_out(void); +bool video_driver_get_prev_video_out(void); +bool video_driver_init(bool *video_is_threaded); +void video_driver_destroy_data(void); +void video_driver_free(void); +void video_driver_free_hw_context(void); +void video_driver_monitor_reset(void); +void video_driver_set_aspect_ratio(void); +void video_driver_update_viewport(struct video_viewport* vp, bool force_full, bool keep_aspect); +void video_driver_show_mouse(void); +void video_driver_hide_mouse(void); +void video_driver_set_nonblock_state(bool toggle); +bool video_driver_find_driver(void); +void video_driver_apply_state_changes(void); +bool video_driver_read_viewport(uint8_t *buffer, bool is_idle); +bool video_driver_cached_frame(void); +bool video_driver_frame_filter_alive(void); +bool video_driver_frame_filter_is_32bit(void); +void video_driver_default_settings(void); +void video_driver_load_settings(config_file_t *conf); +void video_driver_save_settings(config_file_t *conf); +void video_driver_set_own_driver(void); +void video_driver_unset_own_driver(void); +bool video_driver_owns_driver(void); +bool video_driver_is_hw_context(void); +struct retro_hw_render_callback *video_driver_get_hw_context(void); +const struct retro_hw_render_context_negotiation_interface +*video_driver_get_context_negotiation_interface(void); +void video_driver_set_context_negotiation_interface(const struct + retro_hw_render_context_negotiation_interface *iface); +bool video_driver_is_video_cache_context(void); +void video_driver_set_video_cache_context_ack(void); +bool video_driver_is_video_cache_context_ack(void); +void video_driver_set_active(void); +void video_driver_unset_active(void); +bool video_driver_is_active(void); +bool video_driver_gpu_record_init(unsigned size); +void video_driver_gpu_record_deinit(void); +bool video_driver_get_current_software_framebuffer(struct + retro_framebuffer *fb); +bool video_driver_get_hw_render_interface(const struct + retro_hw_render_interface **iface); +bool video_driver_get_viewport_info(struct video_viewport *viewport); +void video_driver_set_title_buf(void); +void video_driver_monitor_adjust_system_rates(void); + +/** + * video_driver_find_handle: + * @index : index of driver to get handle to. + * + * Returns: handle to video driver at index. Can be NULL + * if nothing found. + **/ +const void *video_driver_find_handle(int index); + +/** + * video_driver_find_ident: + * @index : index of driver to get handle to. + * + * Returns: Human-readable identifier of video driver at index. + * Can be NULL if nothing found. + **/ +const char *video_driver_find_ident(int index); + +/** + * config_get_video_driver_options: + * + * Get an enumerated list of all video driver names, separated by '|'. + * + * Returns: string listing of all video driver names, separated by '|'. + **/ +const char* config_get_video_driver_options(void); + +/** + * video_driver_get_ptr: + * + * Use this if you need the real video driver + * and driver data pointers. + * + * Returns: video driver's userdata. + **/ +void *video_driver_get_ptr(bool force_nonthreaded_data); + +/** + * video_driver_get_current_framebuffer: + * + * Gets pointer to current hardware renderer framebuffer object. + * Used by RETRO_ENVIRONMENT_SET_HW_RENDER. + * + * Returns: pointer to hardware framebuffer object, otherwise 0. + **/ +uintptr_t video_driver_get_current_framebuffer(void); + +retro_proc_address_t video_driver_get_proc_address(const char *sym); + +bool video_driver_set_shader(enum rarch_shader_type type, + const char *shader); + +bool video_driver_set_rotation(unsigned rotation); + +bool video_driver_set_video_mode(unsigned width, + unsigned height, bool fullscreen); + +bool video_driver_get_video_output_size( + unsigned *width, unsigned *height); + +void video_driver_set_osd_msg(const char *msg, + const void *params, void *font); + +void video_driver_set_texture_enable(bool enable, bool full_screen); + +void video_driver_set_texture_frame(const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha); + +#ifdef HAVE_OVERLAY +bool video_driver_overlay_interface( + const video_overlay_interface_t **iface); +#endif + +void * video_driver_read_frame_raw(unsigned *width, + unsigned *height, size_t *pitch); + +void video_driver_set_filtering(unsigned index, bool smooth); + +const char *video_driver_get_ident(void); + +bool video_driver_set_viewport(unsigned width, unsigned height, + bool force_fullscreen, bool allow_rotate); + +void video_driver_get_size(unsigned *width, unsigned *height); + +void video_driver_set_size(unsigned *width, unsigned *height); + +void video_driver_unset_video_cache_context_ack(void); + +float video_driver_get_aspect_ratio(void); + +void video_driver_set_aspect_ratio_value(float value); + +rarch_softfilter_t *video_driver_frame_filter_get_ptr(void); + +enum retro_pixel_format video_driver_get_pixel_format(void); + +void video_driver_set_pixel_format(enum retro_pixel_format fmt); + +void video_driver_cached_frame_set(const void *data, unsigned width, + unsigned height, size_t pitch); + +void video_driver_cached_frame_get(const void **data, unsigned *width, + unsigned *height, size_t *pitch); + +void video_driver_menu_settings(void **list_data, void *list_info_data, + void *group_data, void *subgroup_data, const char *parent_group); + +/** + * video_viewport_get_scaled_integer: + * @vp : Viewport handle + * @width : Width. + * @height : Height. + * @aspect_ratio : Aspect ratio (in float). + * @keep_aspect : Preserve aspect ratio? + * + * Gets viewport scaling dimensions based on + * scaled integer aspect ratio. + **/ +void video_viewport_get_scaled_integer(struct video_viewport *vp, + unsigned width, unsigned height, + float aspect_ratio, bool keep_aspect); + +struct retro_system_av_info *video_viewport_get_system_av_info(void); + +struct video_viewport *video_viewport_get_custom(void); + +/** + * video_monitor_set_refresh_rate: + * @hz : New refresh rate for monitor. + * + * Sets monitor refresh rate to new value. + **/ +void video_monitor_set_refresh_rate(float hz); + +/** + * video_monitor_fps_statistics + * @refresh_rate : Monitor refresh rate. + * @deviation : Deviation from measured refresh rate. + * @sample_points : Amount of sampled points. + * + * Gets the monitor FPS statistics based on the current + * runtime. + * + * Returns: true (1) on success. + * false (0) if: + * a) threaded video mode is enabled + * b) less than 2 frame time samples. + * c) FPS monitor enable is off. + **/ +bool video_monitor_fps_statistics(double *refresh_rate, + double *deviation, unsigned *sample_points); + +unsigned video_pixel_get_alignment(unsigned pitch); + +const video_poke_interface_t *video_driver_get_poke(void); + +/** + * video_driver_frame: + * @data : pointer to data of the video frame. + * @width : width of the video frame. + * @height : height of the video frame. + * @pitch : pitch of the video frame. + * + * Video frame render callback function. + **/ +void video_driver_frame(const void *data, unsigned width, + unsigned height, size_t pitch); + +void crt_switch_driver_reinit(void); + +#define video_driver_translate_coord_viewport_wrap(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) \ + (video_driver_get_viewport_info(vp) ? video_driver_translate_coord_viewport(vp, mouse_x, mouse_y, res_x, res_y, res_screen_x, res_screen_y) : false) + +/** + * video_driver_translate_coord_viewport: + * @mouse_x : Pointer X coordinate. + * @mouse_y : Pointer Y coordinate. + * @res_x : Scaled X coordinate. + * @res_y : Scaled Y coordinate. + * @res_screen_x : Scaled screen X coordinate. + * @res_screen_y : Scaled screen Y coordinate. + * + * Translates pointer [X,Y] coordinates into scaled screen + * coordinates based on viewport info. + * + * Returns: true (1) if successful, false if video driver doesn't support + * viewport info. + **/ +bool video_driver_translate_coord_viewport( + struct video_viewport *vp, + int mouse_x, int mouse_y, + int16_t *res_x, int16_t *res_y, int16_t *res_screen_x, + int16_t *res_screen_y); + +uintptr_t video_driver_display_get(void); + +enum rarch_display_type video_driver_display_type_get(void); + +uintptr_t video_driver_window_get(void); + +void video_driver_display_type_set(enum rarch_display_type type); + +void video_driver_display_set(uintptr_t idx); + +void video_driver_window_set(uintptr_t idx); + +bool video_driver_texture_load(void *data, + enum texture_filter_type filter_type, + uintptr_t *id); + +bool video_driver_texture_unload(uintptr_t *id); + +void video_driver_build_info(video_frame_info_t *video_info); + +void video_driver_reinit(void); + +void video_driver_get_window_title(char *buf, unsigned len); + +void video_driver_get_record_status( + bool *has_gpu_record, + uint8_t **gpu_buf); + +bool *video_driver_get_threaded(void); + +void video_driver_set_threaded(bool val); + +void video_driver_get_status(uint64_t *frame_count, bool * is_alive, + bool *is_focused); + +/** + * video_context_driver_init_first: + * @data : Input data. + * @ident : Identifier of graphics context driver to find. + * @api : API of higher-level graphics API. + * @major : Major version number of higher-level graphics API. + * @minor : Minor version number of higher-level graphics API. + * @hw_render_ctx : Request a graphics context driver capable of + * hardware rendering? + * + * Finds first suitable graphics context driver and initializes. + * + * Returns: graphics context driver if found, otherwise NULL. + **/ +const gfx_ctx_driver_t *video_context_driver_init_first( + void *data, const char *ident, + enum gfx_ctx_api api, unsigned major, unsigned minor, + bool hw_render_ctx, void **ctx_data); + +bool video_context_driver_find_prev_driver(void); + +bool video_context_driver_find_next_driver(void); + +bool video_context_driver_init_image_buffer(const video_info_t *data); + +bool video_context_driver_write_to_image_buffer(gfx_ctx_image_t *img); + +bool video_context_driver_get_video_output_prev(void); + +bool video_context_driver_get_video_output_next(void); + +bool video_context_driver_bind_hw_render(bool *enable); + +void video_context_driver_make_current(bool restore); + +bool video_context_driver_set(const gfx_ctx_driver_t *data); + +void video_context_driver_destroy(void); + +bool video_context_driver_get_video_output_size(gfx_ctx_size_t *size_data); + +bool video_context_driver_swap_interval(int *interval); + +bool video_context_driver_get_proc_address(gfx_ctx_proc_address_t *proc); + +bool video_context_driver_suppress_screensaver(bool *bool_data); + +bool video_context_driver_get_ident(gfx_ctx_ident_t *ident); + +bool video_context_driver_set_video_mode(gfx_ctx_mode_t *mode_info); + +bool video_context_driver_get_video_size(gfx_ctx_mode_t *mode_info); + +bool video_context_driver_get_refresh_rate(float *refresh_rate); + +bool video_context_driver_show_mouse(bool *bool_data); + +bool video_context_driver_set_flags(gfx_ctx_flags_t *flags); + +bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics); + +bool video_context_driver_translate_aspect(gfx_ctx_aspect_t *aspect); + +bool video_context_driver_input_driver(gfx_ctx_input_t *inp); + +enum gfx_ctx_api video_context_driver_get_api(void); + +void video_context_driver_free(void); + +bool video_shader_driver_get_ident(video_shader_ctx_ident_t *ident); + +bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader); + +bool video_shader_driver_deinit(void); + +bool video_shader_driver_init_first(void); + +bool video_shader_driver_init(video_shader_ctx_init_t *init); + +void video_driver_set_coords(video_shader_ctx_coords_t *coords); + +bool video_shader_driver_scale(video_shader_ctx_scale_t *scaler); + +bool video_shader_driver_info(video_shader_ctx_info_t *shader_info); + +void video_driver_set_mvp(video_shader_ctx_mvp_t *mvp); + +float video_driver_get_refresh_rate(void); + +extern bool (*video_driver_cb_has_focus)(void); + +bool video_driver_started_fullscreen(void); + +bool video_driver_is_threaded(void); + +bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, + enum display_flags flag); + +extern video_driver_t video_gl; +extern video_driver_t video_vulkan; +extern video_driver_t video_metal; +extern video_driver_t video_psp1; +extern video_driver_t video_vita2d; +extern video_driver_t video_ps2; +extern video_driver_t video_ctr; +extern video_driver_t video_switch; +extern video_driver_t video_d3d8; +extern video_driver_t video_d3d9; +extern video_driver_t video_d3d10; +extern video_driver_t video_d3d11; +extern video_driver_t video_d3d12; +extern video_driver_t video_gx; +extern video_driver_t video_wiiu; +extern video_driver_t video_xenon360; +extern video_driver_t video_xvideo; +extern video_driver_t video_sdl; +extern video_driver_t video_sdl2; +extern video_driver_t video_vg; +extern video_driver_t video_omap; +extern video_driver_t video_exynos; +extern video_driver_t video_dispmanx; +extern video_driver_t video_sunxi; +extern video_driver_t video_drm; +extern video_driver_t video_xshm; +extern video_driver_t video_caca; +extern video_driver_t video_gdi; +extern video_driver_t video_vga; +extern video_driver_t video_sixel; +extern video_driver_t video_null; + +extern const gfx_ctx_driver_t gfx_ctx_osmesa; +extern const gfx_ctx_driver_t gfx_ctx_sdl_gl; +extern const gfx_ctx_driver_t gfx_ctx_x_egl; +extern const gfx_ctx_driver_t gfx_ctx_wayland; +extern const gfx_ctx_driver_t gfx_ctx_x; +extern const gfx_ctx_driver_t gfx_ctx_drm; +extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_android; +extern const gfx_ctx_driver_t gfx_ctx_ps3; +extern const gfx_ctx_driver_t gfx_ctx_wgl; +extern const gfx_ctx_driver_t gfx_ctx_videocore; +extern const gfx_ctx_driver_t gfx_ctx_qnx; +extern const gfx_ctx_driver_t gfx_ctx_cgl; +extern const gfx_ctx_driver_t gfx_ctx_cocoagl; +extern const gfx_ctx_driver_t gfx_ctx_emscripten; +extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_khr_display; +extern const gfx_ctx_driver_t gfx_ctx_gdi; +extern const gfx_ctx_driver_t gfx_ctx_sixel; +extern const gfx_ctx_driver_t switch_ctx; +extern const gfx_ctx_driver_t orbis_ctx; +extern const gfx_ctx_driver_t gfx_ctx_null; + +extern const shader_backend_t gl_glsl_backend; +extern const shader_backend_t gl_cg_backend; +extern const shader_backend_t shader_null_backend; + +RETRO_END_DECLS + +#endif diff --git a/gfx/video_filters/Normal2x.filt b/gfx/video_filters/Normal2x.filt index 500574af11..5ebb1da547 100644 --- a/gfx/video_filters/Normal2x.filt +++ b/gfx/video_filters/Normal2x.filt @@ -1 +1 @@ -filter = normal2x +filter = normal2x diff --git a/griffin/griffin_glslang.cpp b/griffin/griffin_glslang.cpp index 98dd96f55a..2cdc37f22d 100644 --- a/griffin/griffin_glslang.cpp +++ b/griffin/griffin_glslang.cpp @@ -1,68 +1,68 @@ -ï»ż -#ifdef WANT_GLSLANG - -#ifdef _MSC_VER -#include -#ifdef strtoull -#undef strtoull -#endif -#endif - -#include "../deps/glslang/glslang.cpp" -#include "../deps/glslang/glslang/SPIRV/disassemble.cpp" -#include "../deps/glslang/glslang/SPIRV/doc.cpp" -#include "../deps/glslang/glslang/SPIRV/GlslangToSpv.cpp" -#include "../deps/glslang/glslang/SPIRV/InReadableOrder.cpp" -#include "../deps/glslang/glslang/SPIRV/Logger.cpp" -#include "../deps/glslang/glslang/SPIRV/SpvBuilder.cpp" -#include "../deps/glslang/glslang/SPIRV/SPVRemapper.cpp" - -#include "../deps/glslang/glslang/glslang/GenericCodeGen/CodeGen.cpp" -#include "../deps/glslang/glslang/glslang/GenericCodeGen/Link.cpp" - -#include "../deps/glslang/glslang/OGLCompilersDLL/InitializeDll.cpp" - -#include "../deps/glslang/glslang/glslang/MachineIndependent/attribute.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/Constant.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/glslang_tab.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/InfoSink.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/Initialize.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/Intermediate.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/intermOut.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/IntermTraverse.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/iomapper.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/limits.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/linkValidate.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/parseConst.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/ParseContextBase.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/ParseHelper.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/PoolAlloc.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/propagateNoContraction.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/reflection.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/RemoveTree.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/Scan.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/ShaderLang.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/SymbolTable.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/Versions.cpp" - -#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp" -#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp" - -#ifdef __APPLE__ -#include "../deps/glslang/glslang/glslang/OSDependent/Unix/ossource.cpp" -#endif - -#if defined(ENABLE_HLSL) -#include "../deps/glslang/glslang/hlsl/hlslAttributes.cpp" -#include "../deps/glslang/glslang/hlsl/hlslGrammar.cpp" -#include "../deps/glslang/glslang/hlsl/hlslOpMap.cpp" -#include "../deps/glslang/glslang/hlsl/hlslParseables.cpp" -#include "../deps/glslang/glslang/hlsl/hlslParseHelper.cpp" -#include "../deps/glslang/glslang/hlsl/hlslScanContext.cpp" -#include "../deps/glslang/glslang/hlsl/hlslTokenStream.cpp" -#endif - -#endif +ï»ż +#ifdef WANT_GLSLANG + +#ifdef _MSC_VER +#include +#ifdef strtoull +#undef strtoull +#endif +#endif + +#include "../deps/glslang/glslang.cpp" +#include "../deps/glslang/glslang/SPIRV/disassemble.cpp" +#include "../deps/glslang/glslang/SPIRV/doc.cpp" +#include "../deps/glslang/glslang/SPIRV/GlslangToSpv.cpp" +#include "../deps/glslang/glslang/SPIRV/InReadableOrder.cpp" +#include "../deps/glslang/glslang/SPIRV/Logger.cpp" +#include "../deps/glslang/glslang/SPIRV/SpvBuilder.cpp" +#include "../deps/glslang/glslang/SPIRV/SPVRemapper.cpp" + +#include "../deps/glslang/glslang/glslang/GenericCodeGen/CodeGen.cpp" +#include "../deps/glslang/glslang/glslang/GenericCodeGen/Link.cpp" + +#include "../deps/glslang/glslang/OGLCompilersDLL/InitializeDll.cpp" + +#include "../deps/glslang/glslang/glslang/MachineIndependent/attribute.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/Constant.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/glslang_tab.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/InfoSink.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/Initialize.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/Intermediate.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/intermOut.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/IntermTraverse.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/iomapper.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/limits.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/linkValidate.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/parseConst.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/ParseContextBase.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/ParseHelper.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/PoolAlloc.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/propagateNoContraction.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/reflection.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/RemoveTree.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/Scan.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/ShaderLang.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/SymbolTable.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/Versions.cpp" + +#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp" +#include "../deps/glslang/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp" + +#ifdef __APPLE__ +#include "../deps/glslang/glslang/glslang/OSDependent/Unix/ossource.cpp" +#endif + +#if defined(ENABLE_HLSL) +#include "../deps/glslang/glslang/hlsl/hlslAttributes.cpp" +#include "../deps/glslang/glslang/hlsl/hlslGrammar.cpp" +#include "../deps/glslang/glslang/hlsl/hlslOpMap.cpp" +#include "../deps/glslang/glslang/hlsl/hlslParseables.cpp" +#include "../deps/glslang/glslang/hlsl/hlslParseHelper.cpp" +#include "../deps/glslang/glslang/hlsl/hlslScanContext.cpp" +#include "../deps/glslang/glslang/hlsl/hlslTokenStream.cpp" +#endif + +#endif diff --git a/libretro-common/formats/libchdr/libchdr_flac_codec.c b/libretro-common/formats/libchdr/libchdr_flac_codec.c index 83abadd3f2..3a6e669268 100644 --- a/libretro-common/formats/libchdr/libchdr_flac_codec.c +++ b/libretro-common/formats/libchdr/libchdr_flac_codec.c @@ -1,163 +1,163 @@ -/*************************************************************************** - - libchdr_flac_codec.c - - MAME Compressed Hunks of Data file format - -**************************************************************************** - - Copyright Aaron Giles - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name 'MAME' nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TRUE 1 -#define FALSE 0 - -/*************************************************************************** - * CD FLAC DECOMPRESSOR - *************************************************************************** - */ - -/*------------------------------------------------------ - * cdfl_codec_blocksize - return the optimal block size - *------------------------------------------------------ - */ - -static uint32_t cdfl_codec_blocksize(uint32_t bytes) -{ - /* determine FLAC block size, which must be 16-65535 - * clamp to 2k since that's supposed to be the sweet spot */ - uint32_t hunkbytes = bytes / 4; - while (hunkbytes > 2048) - hunkbytes /= 2; - return hunkbytes; -} - -chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) -{ -#ifdef WANT_SUBCODE - chd_error ret; -#endif - uint16_t native_endian = 0; - cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; - - /* make sure the CHD's hunk size is an even multiple of the frame size */ - if (hunkbytes % CD_FRAME_SIZE != 0) - return CHDERR_CODEC_ERROR; - - cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); - if (cdfl->buffer == NULL) - return CHDERR_OUT_OF_MEMORY; - - /* determine whether we want native or swapped samples */ - *(uint8_t *)(&native_endian) = 1; - cdfl->swap_endian = (native_endian & 1); - -#ifdef WANT_SUBCODE - /* init zlib inflater */ - ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); - if (ret != CHDERR_NONE) - return ret; -#endif - - /* flac decoder init */ - flac_decoder_init(&cdfl->decoder); - if (cdfl->decoder.decoder == NULL) - return CHDERR_OUT_OF_MEMORY; - - return CHDERR_NONE; -} - -void cdfl_codec_free(void *codec) -{ - cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; - flac_decoder_free(&cdfl->decoder); -#ifdef WANT_SUBCODE - zlib_codec_free(&cdfl->subcode_decompressor); -#endif - if (cdfl->buffer) - free(cdfl->buffer); -} - -chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) -{ - uint32_t framenum; - uint8_t *buffer; -#ifdef WANT_SUBCODE - uint32_t offset; - chd_error ret; -#endif - cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; - - /* reset and decode */ - uint32_t frames = destlen / CD_FRAME_SIZE; - - if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) - return CHDERR_DECOMPRESSION_ERROR; - buffer = &cdfl->buffer[0]; - if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) - return CHDERR_DECOMPRESSION_ERROR; - -#ifdef WANT_SUBCODE - /* inflate the subcode data */ - offset = flac_decoder_finish(&cdfl->decoder); - ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); - if (ret != CHDERR_NONE) - return ret; -#else - flac_decoder_finish(&cdfl->decoder); -#endif - - /* reassemble the data */ - for (framenum = 0; framenum < frames; framenum++) - { - memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); -#ifdef WANT_SUBCODE - memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); -#endif - } - - return CHDERR_NONE; -} +/*************************************************************************** + + libchdr_flac_codec.c + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/*************************************************************************** + * CD FLAC DECOMPRESSOR + *************************************************************************** + */ + +/*------------------------------------------------------ + * cdfl_codec_blocksize - return the optimal block size + *------------------------------------------------------ + */ + +static uint32_t cdfl_codec_blocksize(uint32_t bytes) +{ + /* determine FLAC block size, which must be 16-65535 + * clamp to 2k since that's supposed to be the sweet spot */ + uint32_t hunkbytes = bytes / 4; + while (hunkbytes > 2048) + hunkbytes /= 2; + return hunkbytes; +} + +chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) +{ +#ifdef WANT_SUBCODE + chd_error ret; +#endif + uint16_t native_endian = 0; + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + + /* make sure the CHD's hunk size is an even multiple of the frame size */ + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (cdfl->buffer == NULL) + return CHDERR_OUT_OF_MEMORY; + + /* determine whether we want native or swapped samples */ + *(uint8_t *)(&native_endian) = 1; + cdfl->swap_endian = (native_endian & 1); + +#ifdef WANT_SUBCODE + /* init zlib inflater */ + ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; +#endif + + /* flac decoder init */ + flac_decoder_init(&cdfl->decoder); + if (cdfl->decoder.decoder == NULL) + return CHDERR_OUT_OF_MEMORY; + + return CHDERR_NONE; +} + +void cdfl_codec_free(void *codec) +{ + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + flac_decoder_free(&cdfl->decoder); +#ifdef WANT_SUBCODE + zlib_codec_free(&cdfl->subcode_decompressor); +#endif + if (cdfl->buffer) + free(cdfl->buffer); +} + +chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + uint8_t *buffer; +#ifdef WANT_SUBCODE + uint32_t offset; + chd_error ret; +#endif + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + + /* reset and decode */ + uint32_t frames = destlen / CD_FRAME_SIZE; + + if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) + return CHDERR_DECOMPRESSION_ERROR; + buffer = &cdfl->buffer[0]; + if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) + return CHDERR_DECOMPRESSION_ERROR; + +#ifdef WANT_SUBCODE + /* inflate the subcode data */ + offset = flac_decoder_finish(&cdfl->decoder); + ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + if (ret != CHDERR_NONE) + return ret; +#else + flac_decoder_finish(&cdfl->decoder); +#endif + + /* reassemble the data */ + for (framenum = 0; framenum < frames; framenum++) + { + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); +#endif + } + + return CHDERR_NONE; +} diff --git a/libretro-common/formats/libchdr/libchdr_lzma.c b/libretro-common/formats/libchdr/libchdr_lzma.c index 69bafbbff8..f3b9eb6fee 100644 --- a/libretro-common/formats/libchdr/libchdr_lzma.c +++ b/libretro-common/formats/libchdr/libchdr_lzma.c @@ -1,354 +1,354 @@ -/*************************************************************************** - - libchdr_lzma_codec.c - - MAME Compressed Hunks of Data file format - -**************************************************************************** - - Copyright Aaron Giles - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name 'MAME' nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TRUE 1 -#define FALSE 0 - -/*************************************************************************** - * LZMA ALLOCATOR HELPER - *************************************************************************** - */ - -/*------------------------------------------------- - * lzma_fast_alloc - fast malloc for lzma, which - * allocates and frees memory frequently - *------------------------------------------------- - */ - -static void *lzma_fast_alloc(void *p, size_t size) -{ - int scan; - uint32_t *addr = NULL; - lzma_allocator *codec = (lzma_allocator *)(p); - - /* compute the size, rounding to the nearest 1k */ - size = (size + 0x3ff) & ~0x3ff; - - /* reuse a hunk if we can */ - for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) - { - uint32_t *ptr = codec->allocptr[scan]; - if (ptr != NULL && size == *ptr) - { - /* set the low bit of the size so we don't match next time */ - *ptr |= 1; - return ptr + 1; - } - } - - /* alloc a new one and put it into the list */ - addr = (uint32_t *)malloc(sizeof(uint32_t) * (size + sizeof(uint32_t))); - if (!addr) - return NULL; - - for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) - { - if (codec->allocptr[scan] == NULL) - { - codec->allocptr[scan] = addr; - break; - } - } - - /* set the low bit of the size so we don't match next time */ - *addr = size | 1; - return addr + 1; -} - -/*------------------------------------------------- - * lzma_fast_free - fast free for lzma, which - * allocates and frees memory frequently - *------------------------------------------------- - */ -static void lzma_fast_free(void *p, void *address) -{ - int scan; - uint32_t *ptr; - lzma_allocator *codec; - if (address == NULL) - return; - - codec = (lzma_allocator *)(p); - - /* find the hunk */ - ptr = (uint32_t *)(address) - 1; - for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) - { - if (ptr == codec->allocptr[scan]) - { - /* clear the low bit of the size to allow matches */ - *ptr &= ~1; - return; - } - } -} - - -/*------------------------------------------------- - * lzma_allocator_init - *------------------------------------------------- - */ - -void lzma_allocator_init(void* p) -{ - lzma_allocator *codec = (lzma_allocator *)(p); - - /* reset pointer list */ - memset(codec->allocptr, 0, sizeof(codec->allocptr)); - codec->Alloc = lzma_fast_alloc; - codec->Free = lzma_fast_free; -} - -/*------------------------------------------------- - * lzma_allocator_free - *------------------------------------------------- - */ - -void lzma_allocator_free(void* p ) -{ - lzma_allocator *codec = (lzma_allocator *)(p); - - /* free our memory */ - int i; - for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) - { - if (codec->allocptr[i] != NULL) - free(codec->allocptr[i]); - } -} - - - -/*************************************************************************** - * LZMA DECOMPRESSOR - *************************************************************************** - */ - -/*------------------------------------------------- - * lzma_codec_init - constructor - *------------------------------------------------- - */ - -chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) -{ - CLzmaEncProps encoder_props; - CLzmaEncHandle enc; - uint8_t decoder_props[LZMA_PROPS_SIZE]; - lzma_allocator* alloc; - size_t props_size; - lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; - - /* construct the decoder */ - LzmaDec_Construct(&lzma_codec->decoder); - - /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK - * This code assumes that the current version of the encoder imposes the same requirements on the - * decoder as the encoder used to produce the file. This is not necessarily true. The format - * needs to be changed so the encoder properties are written to the file. - - * configure the properties like the compressor did */ - LzmaEncProps_Init(&encoder_props); - encoder_props.level = 9; - encoder_props.reduceSize = hunkbytes; - LzmaEncProps_Normalize(&encoder_props); - - /* convert to decoder properties */ - alloc = &lzma_codec->allocator; - lzma_allocator_init(alloc); - enc = LzmaEnc_Create((ISzAlloc*)alloc); - if (!enc) - return CHDERR_DECOMPRESSION_ERROR; - if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) - { - LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc); - return CHDERR_DECOMPRESSION_ERROR; - } - props_size = sizeof(decoder_props); - if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) - { - LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); - return CHDERR_DECOMPRESSION_ERROR; - } - LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); - - /* do memory allocations */ - if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) - return CHDERR_DECOMPRESSION_ERROR; - - /* Okay */ - return CHDERR_NONE; -} - -/*------------------------------------------------- - * lzma_codec_free - *------------------------------------------------- - */ - -void lzma_codec_free(void* codec) -{ - lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; - lzma_allocator* alloc = &lzma_codec->allocator; - - /* free memory */ - lzma_allocator_free(alloc); - LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator); -} - -/*------------------------------------------------- - * decompress - decompress data using the LZMA - * codec - *------------------------------------------------- - */ - -chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) -{ - ELzmaStatus status; - SRes res; - size_t consumedlen, decodedlen; - /* initialize */ - lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; - LzmaDec_Init(&lzma_codec->decoder); - - /* decode */ - consumedlen = complen; - decodedlen = destlen; - res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); - if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) - return CHDERR_DECOMPRESSION_ERROR; - return CHDERR_NONE; -} - -/* cdlz */ -chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) -{ - chd_error ret; - cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; - - /* allocate buffer */ - cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); - if (cdlz->buffer == NULL) - return CHDERR_OUT_OF_MEMORY; - - ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); - if (ret != CHDERR_NONE) - return ret; - -#ifdef WANT_SUBCODE - ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); - if (ret != CHDERR_NONE) - return ret; -#endif - - return CHDERR_NONE; -} - -void cdlz_codec_free(void* codec) -{ - cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; - - lzma_codec_free(&cdlz->base_decompressor); -#ifdef WANT_SUBCODE - zlib_codec_free(&cdlz->subcode_decompressor); -#endif - if (cdlz->buffer) - free(cdlz->buffer); -} - -chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) -{ -#ifdef WANT_RAW_DATA_SECTOR - uint8_t *sector; -#endif - uint32_t framenum; - cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; - - /* determine header bytes */ - uint32_t frames = destlen / CD_FRAME_SIZE; - uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; - uint32_t ecc_bytes = (frames + 7) / 8; - uint32_t header_bytes = ecc_bytes + complen_bytes; - - /* extract compressed length of base */ - uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; - if (complen_bytes > 2) - complen_base = (complen_base << 8) | src[ecc_bytes + 2]; - - /* reset and decode */ - lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); -#ifdef WANT_SUBCODE - if (header_bytes + complen_base >= complen) - return CHDERR_DECOMPRESSION_ERROR; - zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); -#endif - - /* reassemble the data */ - for (framenum = 0; framenum < frames; framenum++) - { - memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); -#ifdef WANT_SUBCODE - memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); -#endif - -#ifdef WANT_RAW_DATA_SECTOR - /* reconstitute the ECC data and sync header */ - sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; - if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) - { - memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); - ecc_generate(sector); - } -#endif - } - return CHDERR_NONE; -} +/*************************************************************************** + + libchdr_lzma_codec.c + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/*************************************************************************** + * LZMA ALLOCATOR HELPER + *************************************************************************** + */ + +/*------------------------------------------------- + * lzma_fast_alloc - fast malloc for lzma, which + * allocates and frees memory frequently + *------------------------------------------------- + */ + +static void *lzma_fast_alloc(void *p, size_t size) +{ + int scan; + uint32_t *addr = NULL; + lzma_allocator *codec = (lzma_allocator *)(p); + + /* compute the size, rounding to the nearest 1k */ + size = (size + 0x3ff) & ~0x3ff; + + /* reuse a hunk if we can */ + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + uint32_t *ptr = codec->allocptr[scan]; + if (ptr != NULL && size == *ptr) + { + /* set the low bit of the size so we don't match next time */ + *ptr |= 1; + return ptr + 1; + } + } + + /* alloc a new one and put it into the list */ + addr = (uint32_t *)malloc(sizeof(uint32_t) * (size + sizeof(uint32_t))); + if (!addr) + return NULL; + + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + if (codec->allocptr[scan] == NULL) + { + codec->allocptr[scan] = addr; + break; + } + } + + /* set the low bit of the size so we don't match next time */ + *addr = size | 1; + return addr + 1; +} + +/*------------------------------------------------- + * lzma_fast_free - fast free for lzma, which + * allocates and frees memory frequently + *------------------------------------------------- + */ +static void lzma_fast_free(void *p, void *address) +{ + int scan; + uint32_t *ptr; + lzma_allocator *codec; + if (address == NULL) + return; + + codec = (lzma_allocator *)(p); + + /* find the hunk */ + ptr = (uint32_t *)(address) - 1; + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + if (ptr == codec->allocptr[scan]) + { + /* clear the low bit of the size to allow matches */ + *ptr &= ~1; + return; + } + } +} + + +/*------------------------------------------------- + * lzma_allocator_init + *------------------------------------------------- + */ + +void lzma_allocator_init(void* p) +{ + lzma_allocator *codec = (lzma_allocator *)(p); + + /* reset pointer list */ + memset(codec->allocptr, 0, sizeof(codec->allocptr)); + codec->Alloc = lzma_fast_alloc; + codec->Free = lzma_fast_free; +} + +/*------------------------------------------------- + * lzma_allocator_free + *------------------------------------------------- + */ + +void lzma_allocator_free(void* p ) +{ + lzma_allocator *codec = (lzma_allocator *)(p); + + /* free our memory */ + int i; + for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) + { + if (codec->allocptr[i] != NULL) + free(codec->allocptr[i]); + } +} + + + +/*************************************************************************** + * LZMA DECOMPRESSOR + *************************************************************************** + */ + +/*------------------------------------------------- + * lzma_codec_init - constructor + *------------------------------------------------- + */ + +chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) +{ + CLzmaEncProps encoder_props; + CLzmaEncHandle enc; + uint8_t decoder_props[LZMA_PROPS_SIZE]; + lzma_allocator* alloc; + size_t props_size; + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + + /* construct the decoder */ + LzmaDec_Construct(&lzma_codec->decoder); + + /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK + * This code assumes that the current version of the encoder imposes the same requirements on the + * decoder as the encoder used to produce the file. This is not necessarily true. The format + * needs to be changed so the encoder properties are written to the file. + + * configure the properties like the compressor did */ + LzmaEncProps_Init(&encoder_props); + encoder_props.level = 9; + encoder_props.reduceSize = hunkbytes; + LzmaEncProps_Normalize(&encoder_props); + + /* convert to decoder properties */ + alloc = &lzma_codec->allocator; + lzma_allocator_init(alloc); + enc = LzmaEnc_Create((ISzAlloc*)alloc); + if (!enc) + return CHDERR_DECOMPRESSION_ERROR; + if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) + { + LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc); + return CHDERR_DECOMPRESSION_ERROR; + } + props_size = sizeof(decoder_props); + if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) + { + LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + return CHDERR_DECOMPRESSION_ERROR; + } + LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + + /* do memory allocations */ + if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) + return CHDERR_DECOMPRESSION_ERROR; + + /* Okay */ + return CHDERR_NONE; +} + +/*------------------------------------------------- + * lzma_codec_free + *------------------------------------------------- + */ + +void lzma_codec_free(void* codec) +{ + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + lzma_allocator* alloc = &lzma_codec->allocator; + + /* free memory */ + lzma_allocator_free(alloc); + LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator); +} + +/*------------------------------------------------- + * decompress - decompress data using the LZMA + * codec + *------------------------------------------------- + */ + +chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + ELzmaStatus status; + SRes res; + size_t consumedlen, decodedlen; + /* initialize */ + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + LzmaDec_Init(&lzma_codec->decoder); + + /* decode */ + consumedlen = complen; + decodedlen = destlen; + res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); + if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; +} + +/* cdlz */ +chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) +{ + chd_error ret; + cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; + + /* allocate buffer */ + cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (cdlz->buffer == NULL) + return CHDERR_OUT_OF_MEMORY; + + ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; + +#ifdef WANT_SUBCODE + ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; +#endif + + return CHDERR_NONE; +} + +void cdlz_codec_free(void* codec) +{ + cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; + + lzma_codec_free(&cdlz->base_decompressor); +#ifdef WANT_SUBCODE + zlib_codec_free(&cdlz->subcode_decompressor); +#endif + if (cdlz->buffer) + free(cdlz->buffer); +} + +chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ +#ifdef WANT_RAW_DATA_SECTOR + uint8_t *sector; +#endif + uint32_t framenum; + cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; + + /* determine header bytes */ + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* extract compressed length of base */ + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + /* reset and decode */ + lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + if (header_bytes + complen_base >= complen) + return CHDERR_DECOMPRESSION_ERROR; + zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); +#endif + + /* reassemble the data */ + for (framenum = 0; framenum < frames; framenum++) + { + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); +#endif + +#ifdef WANT_RAW_DATA_SECTOR + /* reconstitute the ECC data and sync header */ + sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } +#endif + } + return CHDERR_NONE; +} diff --git a/libretro-common/formats/libchdr/libchdr_zlib.c b/libretro-common/formats/libchdr/libchdr_zlib.c index 44c642f81e..6aaae8d009 100644 --- a/libretro-common/formats/libchdr/libchdr_zlib.c +++ b/libretro-common/formats/libchdr/libchdr_zlib.c @@ -1,298 +1,298 @@ -/*************************************************************************** - - libchdr_zlib.c - - MAME Compressed Hunks of Data file format - -**************************************************************************** - - Copyright Aaron Giles - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name 'MAME' nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - -***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TRUE 1 -#define FALSE 0 - -/* cdzl */ - -chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) -{ - chd_error ret; - cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; - - /* make sure the CHD's hunk size is an even multiple of the frame size */ - if (hunkbytes % CD_FRAME_SIZE != 0) - return CHDERR_CODEC_ERROR; - - cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); - if (cdzl->buffer == NULL) - return CHDERR_OUT_OF_MEMORY; - - ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); - if (ret != CHDERR_NONE) - return ret; - -#ifdef WANT_SUBCODE - ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); - if (ret != CHDERR_NONE) - return ret; -#endif - - return CHDERR_NONE; -} - -void cdzl_codec_free(void *codec) -{ - cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; - - zlib_codec_free(&cdzl->base_decompressor); -#ifdef WANT_SUBCODE - zlib_codec_free(&cdzl->subcode_decompressor); -#endif - if (cdzl->buffer) - free(cdzl->buffer); -} - -chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) -{ -#ifdef WANT_RAW_DATA_SECTOR - uint8_t *sector; -#endif - uint32_t framenum; - cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; - - /* determine header bytes */ - uint32_t frames = destlen / CD_FRAME_SIZE; - uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; - uint32_t ecc_bytes = (frames + 7) / 8; - uint32_t header_bytes = ecc_bytes + complen_bytes; - - /* extract compressed length of base */ - uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; - if (complen_bytes > 2) - complen_base = (complen_base << 8) | src[ecc_bytes + 2]; - - /* reset and decode */ - zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); -#ifdef WANT_SUBCODE - zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); -#endif - - /* reassemble the data */ - for (framenum = 0; framenum < frames; framenum++) - { - memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); -#ifdef WANT_SUBCODE - memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); -#endif - -#ifdef WANT_RAW_DATA_SECTOR - /* reconstitute the ECC data and sync header */ - sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; - if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) - { - memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); - ecc_generate(sector); - } -#endif - } - return CHDERR_NONE; -} - -/*************************************************************************** - ZLIB COMPRESSION CODEC -***************************************************************************/ - -/*------------------------------------------------- - zlib_codec_init - initialize the ZLIB codec --------------------------------------------------*/ - -chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) -{ - int zerr; - chd_error err; - zlib_codec_data *data = (zlib_codec_data*)codec; - - /* clear the buffers */ - memset(data, 0, sizeof(zlib_codec_data)); - - /* init the inflater first */ - data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */ - data->inflater.avail_in = 0; - data->inflater.zalloc = zlib_fast_alloc; - data->inflater.zfree = zlib_fast_free; - data->inflater.opaque = &data->allocator; - zerr = inflateInit2(&data->inflater, -MAX_WBITS); - - /* convert errors */ - if (zerr == Z_MEM_ERROR) - err = CHDERR_OUT_OF_MEMORY; - else if (zerr != Z_OK) - err = CHDERR_CODEC_ERROR; - else - err = CHDERR_NONE; - - return err; -} - -/*------------------------------------------------- - zlib_codec_free - free data for the ZLIB - codec --------------------------------------------------*/ - -void zlib_codec_free(void *codec) -{ - zlib_codec_data *data = (zlib_codec_data *)codec; - - /* deinit the streams */ - if (data != NULL) - { - int i; - zlib_allocator alloc; - - inflateEnd(&data->inflater); - - /* free our fast memory */ - alloc = data->allocator; - for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - if (alloc.allocptr[i]) - free(alloc.allocptr[i]); - } -} - -/*------------------------------------------------- - zlib_codec_decompress - decomrpess data using - the ZLIB codec --------------------------------------------------*/ - -chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) -{ - zlib_codec_data *data = (zlib_codec_data *)codec; - int zerr; - - /* reset the decompressor */ - data->inflater.next_in = (Bytef *)src; - data->inflater.avail_in = complen; - data->inflater.total_in = 0; - data->inflater.next_out = (Bytef *)dest; - data->inflater.avail_out = destlen; - data->inflater.total_out = 0; - zerr = inflateReset(&data->inflater); - if (zerr != Z_OK) - return CHDERR_DECOMPRESSION_ERROR; - - /* do it */ - zerr = inflate(&data->inflater, Z_FINISH); - (void)zerr; - if (data->inflater.total_out != destlen) - return CHDERR_DECOMPRESSION_ERROR; - - return CHDERR_NONE; -} - -/*------------------------------------------------- - zlib_fast_alloc - fast malloc for ZLIB, which - allocates and frees memory frequently --------------------------------------------------*/ - -voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) -{ - zlib_allocator *alloc = (zlib_allocator *)opaque; - UINT32 *ptr; - int i; - - /* compute the size, rounding to the nearest 1k */ - size = (size * items + 0x3ff) & ~0x3ff; - - /* reuse a hunk if we can */ - for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - { - ptr = alloc->allocptr[i]; - if (ptr && size == *ptr) - { - /* set the low bit of the size so we don't match next time */ - *ptr |= 1; - return ptr + 1; - } - } - - /* alloc a new one */ - ptr = (UINT32 *)malloc(size + sizeof(UINT32)); - if (!ptr) - return NULL; - - /* put it into the list */ - for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - if (!alloc->allocptr[i]) - { - alloc->allocptr[i] = ptr; - break; - } - - /* set the low bit of the size so we don't match next time */ - *ptr = size | 1; - return ptr + 1; -} - -/*------------------------------------------------- - zlib_fast_free - fast free for ZLIB, which - allocates and frees memory frequently --------------------------------------------------*/ - -void zlib_fast_free(voidpf opaque, voidpf address) -{ - zlib_allocator *alloc = (zlib_allocator *)opaque; - UINT32 *ptr = (UINT32 *)address - 1; - int i; - - /* find the hunk */ - for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - if (ptr == alloc->allocptr[i]) - { - /* clear the low bit of the size to allow matches */ - *ptr &= ~1; - return; - } -} +/*************************************************************************** + + libchdr_zlib.c + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/* cdzl */ + +chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) +{ + chd_error ret; + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + /* make sure the CHD's hunk size is an even multiple of the frame size */ + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (cdzl->buffer == NULL) + return CHDERR_OUT_OF_MEMORY; + + ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; + +#ifdef WANT_SUBCODE + ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; +#endif + + return CHDERR_NONE; +} + +void cdzl_codec_free(void *codec) +{ + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + zlib_codec_free(&cdzl->base_decompressor); +#ifdef WANT_SUBCODE + zlib_codec_free(&cdzl->subcode_decompressor); +#endif + if (cdzl->buffer) + free(cdzl->buffer); +} + +chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ +#ifdef WANT_RAW_DATA_SECTOR + uint8_t *sector; +#endif + uint32_t framenum; + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + /* determine header bytes */ + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* extract compressed length of base */ + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + /* reset and decode */ + zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); +#endif + + /* reassemble the data */ + for (framenum = 0; framenum < frames; framenum++) + { + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); +#endif + +#ifdef WANT_RAW_DATA_SECTOR + /* reconstitute the ECC data and sync header */ + sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } +#endif + } + return CHDERR_NONE; +} + +/*************************************************************************** + ZLIB COMPRESSION CODEC +***************************************************************************/ + +/*------------------------------------------------- + zlib_codec_init - initialize the ZLIB codec +-------------------------------------------------*/ + +chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) +{ + int zerr; + chd_error err; + zlib_codec_data *data = (zlib_codec_data*)codec; + + /* clear the buffers */ + memset(data, 0, sizeof(zlib_codec_data)); + + /* init the inflater first */ + data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */ + data->inflater.avail_in = 0; + data->inflater.zalloc = zlib_fast_alloc; + data->inflater.zfree = zlib_fast_free; + data->inflater.opaque = &data->allocator; + zerr = inflateInit2(&data->inflater, -MAX_WBITS); + + /* convert errors */ + if (zerr == Z_MEM_ERROR) + err = CHDERR_OUT_OF_MEMORY; + else if (zerr != Z_OK) + err = CHDERR_CODEC_ERROR; + else + err = CHDERR_NONE; + + return err; +} + +/*------------------------------------------------- + zlib_codec_free - free data for the ZLIB + codec +-------------------------------------------------*/ + +void zlib_codec_free(void *codec) +{ + zlib_codec_data *data = (zlib_codec_data *)codec; + + /* deinit the streams */ + if (data != NULL) + { + int i; + zlib_allocator alloc; + + inflateEnd(&data->inflater); + + /* free our fast memory */ + alloc = data->allocator; + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (alloc.allocptr[i]) + free(alloc.allocptr[i]); + } +} + +/*------------------------------------------------- + zlib_codec_decompress - decomrpess data using + the ZLIB codec +-------------------------------------------------*/ + +chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + zlib_codec_data *data = (zlib_codec_data *)codec; + int zerr; + + /* reset the decompressor */ + data->inflater.next_in = (Bytef *)src; + data->inflater.avail_in = complen; + data->inflater.total_in = 0; + data->inflater.next_out = (Bytef *)dest; + data->inflater.avail_out = destlen; + data->inflater.total_out = 0; + zerr = inflateReset(&data->inflater); + if (zerr != Z_OK) + return CHDERR_DECOMPRESSION_ERROR; + + /* do it */ + zerr = inflate(&data->inflater, Z_FINISH); + (void)zerr; + if (data->inflater.total_out != destlen) + return CHDERR_DECOMPRESSION_ERROR; + + return CHDERR_NONE; +} + +/*------------------------------------------------- + zlib_fast_alloc - fast malloc for ZLIB, which + allocates and frees memory frequently +-------------------------------------------------*/ + +voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + UINT32 *ptr; + int i; + + /* compute the size, rounding to the nearest 1k */ + size = (size * items + 0x3ff) & ~0x3ff; + + /* reuse a hunk if we can */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + { + ptr = alloc->allocptr[i]; + if (ptr && size == *ptr) + { + /* set the low bit of the size so we don't match next time */ + *ptr |= 1; + return ptr + 1; + } + } + + /* alloc a new one */ + ptr = (UINT32 *)malloc(size + sizeof(UINT32)); + if (!ptr) + return NULL; + + /* put it into the list */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (!alloc->allocptr[i]) + { + alloc->allocptr[i] = ptr; + break; + } + + /* set the low bit of the size so we don't match next time */ + *ptr = size | 1; + return ptr + 1; +} + +/*------------------------------------------------- + zlib_fast_free - fast free for ZLIB, which + allocates and frees memory frequently +-------------------------------------------------*/ + +void zlib_fast_free(voidpf opaque, voidpf address) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + UINT32 *ptr = (UINT32 *)address - 1; + int i; + + /* find the hunk */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (ptr == alloc->allocptr[i]) + { + /* clear the low bit of the size to allow matches */ + *ptr &= ~1; + return; + } +} diff --git a/menu/menu_networking.c b/menu/menu_networking.c index 38dee85723..4504aac070 100644 --- a/menu/menu_networking.c +++ b/menu/menu_networking.c @@ -1,293 +1,293 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2014-2017 - Jean-AndrĂ© Santoni - * Copyright (C) 2015-2017 - AndrĂ©s SuĂĄrez - * Copyright (C) 2016-2017 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETWORKING -#include -#endif - -#include "menu_driver.h" -#include "menu_networking.h" -#include "menu_cbs.h" -#include "menu_entries.h" - -#include "../core_info.h" -#include "../configuration.h" -#include "../file_path_special.h" -#include "../msg_hash.h" -#include "../tasks/task_file_transfer.h" -#include "../tasks/tasks_internal.h" - -void print_buf_lines(file_list_t *list, char *buf, - const char *label, int buf_size, - enum msg_file_type type, bool append, bool extended) -{ - char c; - int i, j = 0; - char *line_start = buf; - - if (!buf || !buf_size) - { - menu_entries_append_enum(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY), - msg_hash_to_str(MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY), - MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY, - FILE_TYPE_NONE, 0, 0); - return; - } - - for (i = 0; i < buf_size; i++) - { - size_t ln; - const char *core_date = NULL; - const char *core_crc = NULL; - const char *core_pathname = NULL; - struct string_list *str_list = NULL; - - /* The end of the buffer, print the last bit */ - if (*(buf + i) == '\0') - break; - - if (*(buf + i) != '\n') - continue; - - /* Found a line ending, print the line and compute new line_start */ - - /* Save the next char */ - c = *(buf + i + 1); - /* replace with \0 */ - *(buf + i + 1) = '\0'; - - /* We need to strip the newline. */ - ln = strlen(line_start) - 1; - if (line_start[ln] == '\n') - line_start[ln] = '\0'; - - str_list = string_split(line_start, " "); - - if (str_list->elems[0].data) - core_date = str_list->elems[0].data; - if (str_list->elems[1].data) - core_crc = str_list->elems[1].data; - if (str_list->elems[2].data) - core_pathname = str_list->elems[2].data; - - (void)core_date; - (void)core_crc; - - if (extended) - { - if (append) - menu_entries_append_enum(list, core_pathname, "", - MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); - else - menu_entries_prepend(list, core_pathname, "", - MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); - } - else - { - if (append) - menu_entries_append_enum(list, line_start, label, - MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); - else - menu_entries_prepend(list, line_start, label, - MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); - } - - switch (type) - { - case FILE_TYPE_DOWNLOAD_CORE: - { - settings_t *settings = config_get_ptr(); - - if (settings) - { - char display_name[255]; - char core_path[PATH_MAX_LENGTH]; - char *last = NULL; - - display_name[0] = core_path[0] = '\0'; - - fill_pathname_join_noext( - core_path, - settings->paths.path_libretro_info, - (extended && !string_is_empty(core_pathname)) - ? core_pathname : line_start, - sizeof(core_path)); - path_remove_extension(core_path); - - last = (char*)strrchr(core_path, '_'); - - if (!string_is_empty(last)) - { - if (string_is_not_equal_fast(last, "_libretro", 9)) - *last = '\0'; - } - - strlcat(core_path, - file_path_str(FILE_PATH_CORE_INFO_EXTENSION), - sizeof(core_path)); - - if ( - filestream_exists(core_path) - && core_info_get_display_name( - core_path, display_name, sizeof(display_name))) - file_list_set_alt_at_offset(list, j, display_name); - } - } - break; - default: - case FILE_TYPE_NONE: - break; - } - - j++; - - string_list_free(str_list); - - /* Restore the saved char */ - *(buf + i + 1) = c; - line_start = buf + i + 1; - } - - if (append) - file_list_sort_on_alt(list); - /* If the buffer was completely full, and didn't end - * with a newline, just ignore the partial last line. */ -} - -void cb_net_generic_subdir(void *task_data, void *user_data, const char *err) -{ -#ifdef HAVE_NETWORKING - char subdir_path[PATH_MAX_LENGTH]; - http_transfer_data_t *data = (http_transfer_data_t*)task_data; - file_transfer_t *state = (file_transfer_t*)user_data; - - subdir_path[0] = '\0'; - - if (!data || err) - goto finish; - - if (!string_is_empty(data->data)) - memcpy(subdir_path, data->data, data->len * sizeof(char)); - subdir_path[data->len] = '\0'; - -finish: - if (!err && !strstr(subdir_path, file_path_str(FILE_PATH_INDEX_DIRS_URL))) - { - char parent_dir[PATH_MAX_LENGTH]; - - parent_dir[0] = '\0'; - - fill_pathname_parent_dir(parent_dir, - state->path, sizeof(parent_dir)); - - /*generic_action_ok_displaylist_push(parent_dir, NULL, - subdir_path, 0, 0, 0, ACTION_OK_DL_CORE_CONTENT_DIRS_SUBDIR_LIST);*/ - } - - if (data) - { - if (data->data) - free(data->data); - free(data); - } - - if (user_data) - free(user_data); -#endif -} - -void cb_net_generic(void *task_data, void *user_data, const char *err) -{ -#ifdef HAVE_NETWORKING - bool refresh = false; - http_transfer_data_t *data = (http_transfer_data_t*)task_data; - file_transfer_t *state = (file_transfer_t*)user_data; - menu_handle_t *menu = NULL; - - if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) - goto finish; - - if (menu->core_buf) - free(menu->core_buf); - - menu->core_buf = NULL; - menu->core_len = 0; - - if (!data || err) - goto finish; - - menu->core_buf = (char*)malloc((data->len+1) * sizeof(char)); - - if (!menu->core_buf) - goto finish; - - if (!string_is_empty(data->data)) - memcpy(menu->core_buf, data->data, data->len * sizeof(char)); - menu->core_buf[data->len] = '\0'; - menu->core_len = data->len; - -finish: - refresh = true; - menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh); - - if (data) - { - if (data->data) - free(data->data); - free(data); - } - - if (!err && !strstr(state->path, file_path_str(FILE_PATH_INDEX_DIRS_URL))) - { - char *parent_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); - file_transfer_t *transf = NULL; - - parent_dir[0] = '\0'; - - fill_pathname_parent_dir(parent_dir, - state->path, PATH_MAX_LENGTH * sizeof(char)); - strlcat(parent_dir, - file_path_str(FILE_PATH_INDEX_DIRS_URL), - PATH_MAX_LENGTH * sizeof(char)); - - transf = (file_transfer_t*)malloc(sizeof(*transf)); - - transf->enum_idx = MSG_UNKNOWN; - strlcpy(transf->path, parent_dir, sizeof(transf->path)); - - task_push_http_transfer(parent_dir, true, - "index_dirs", cb_net_generic_subdir, transf); - - free(parent_dir); - } - - if (state) - free(state); -#endif -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-AndrĂ© Santoni + * Copyright (C) 2015-2017 - AndrĂ©s SuĂĄrez + * Copyright (C) 2016-2017 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETWORKING +#include +#endif + +#include "menu_driver.h" +#include "menu_networking.h" +#include "menu_cbs.h" +#include "menu_entries.h" + +#include "../core_info.h" +#include "../configuration.h" +#include "../file_path_special.h" +#include "../msg_hash.h" +#include "../tasks/task_file_transfer.h" +#include "../tasks/tasks_internal.h" + +void print_buf_lines(file_list_t *list, char *buf, + const char *label, int buf_size, + enum msg_file_type type, bool append, bool extended) +{ + char c; + int i, j = 0; + char *line_start = buf; + + if (!buf || !buf_size) + { + menu_entries_append_enum(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0); + return; + } + + for (i = 0; i < buf_size; i++) + { + size_t ln; + const char *core_date = NULL; + const char *core_crc = NULL; + const char *core_pathname = NULL; + struct string_list *str_list = NULL; + + /* The end of the buffer, print the last bit */ + if (*(buf + i) == '\0') + break; + + if (*(buf + i) != '\n') + continue; + + /* Found a line ending, print the line and compute new line_start */ + + /* Save the next char */ + c = *(buf + i + 1); + /* replace with \0 */ + *(buf + i + 1) = '\0'; + + /* We need to strip the newline. */ + ln = strlen(line_start) - 1; + if (line_start[ln] == '\n') + line_start[ln] = '\0'; + + str_list = string_split(line_start, " "); + + if (str_list->elems[0].data) + core_date = str_list->elems[0].data; + if (str_list->elems[1].data) + core_crc = str_list->elems[1].data; + if (str_list->elems[2].data) + core_pathname = str_list->elems[2].data; + + (void)core_date; + (void)core_crc; + + if (extended) + { + if (append) + menu_entries_append_enum(list, core_pathname, "", + MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); + else + menu_entries_prepend(list, core_pathname, "", + MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); + } + else + { + if (append) + menu_entries_append_enum(list, line_start, label, + MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); + else + menu_entries_prepend(list, line_start, label, + MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0); + } + + switch (type) + { + case FILE_TYPE_DOWNLOAD_CORE: + { + settings_t *settings = config_get_ptr(); + + if (settings) + { + char display_name[255]; + char core_path[PATH_MAX_LENGTH]; + char *last = NULL; + + display_name[0] = core_path[0] = '\0'; + + fill_pathname_join_noext( + core_path, + settings->paths.path_libretro_info, + (extended && !string_is_empty(core_pathname)) + ? core_pathname : line_start, + sizeof(core_path)); + path_remove_extension(core_path); + + last = (char*)strrchr(core_path, '_'); + + if (!string_is_empty(last)) + { + if (string_is_not_equal_fast(last, "_libretro", 9)) + *last = '\0'; + } + + strlcat(core_path, + file_path_str(FILE_PATH_CORE_INFO_EXTENSION), + sizeof(core_path)); + + if ( + filestream_exists(core_path) + && core_info_get_display_name( + core_path, display_name, sizeof(display_name))) + file_list_set_alt_at_offset(list, j, display_name); + } + } + break; + default: + case FILE_TYPE_NONE: + break; + } + + j++; + + string_list_free(str_list); + + /* Restore the saved char */ + *(buf + i + 1) = c; + line_start = buf + i + 1; + } + + if (append) + file_list_sort_on_alt(list); + /* If the buffer was completely full, and didn't end + * with a newline, just ignore the partial last line. */ +} + +void cb_net_generic_subdir(void *task_data, void *user_data, const char *err) +{ +#ifdef HAVE_NETWORKING + char subdir_path[PATH_MAX_LENGTH]; + http_transfer_data_t *data = (http_transfer_data_t*)task_data; + file_transfer_t *state = (file_transfer_t*)user_data; + + subdir_path[0] = '\0'; + + if (!data || err) + goto finish; + + if (!string_is_empty(data->data)) + memcpy(subdir_path, data->data, data->len * sizeof(char)); + subdir_path[data->len] = '\0'; + +finish: + if (!err && !strstr(subdir_path, file_path_str(FILE_PATH_INDEX_DIRS_URL))) + { + char parent_dir[PATH_MAX_LENGTH]; + + parent_dir[0] = '\0'; + + fill_pathname_parent_dir(parent_dir, + state->path, sizeof(parent_dir)); + + /*generic_action_ok_displaylist_push(parent_dir, NULL, + subdir_path, 0, 0, 0, ACTION_OK_DL_CORE_CONTENT_DIRS_SUBDIR_LIST);*/ + } + + if (data) + { + if (data->data) + free(data->data); + free(data); + } + + if (user_data) + free(user_data); +#endif +} + +void cb_net_generic(void *task_data, void *user_data, const char *err) +{ +#ifdef HAVE_NETWORKING + bool refresh = false; + http_transfer_data_t *data = (http_transfer_data_t*)task_data; + file_transfer_t *state = (file_transfer_t*)user_data; + menu_handle_t *menu = NULL; + + if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) + goto finish; + + if (menu->core_buf) + free(menu->core_buf); + + menu->core_buf = NULL; + menu->core_len = 0; + + if (!data || err) + goto finish; + + menu->core_buf = (char*)malloc((data->len+1) * sizeof(char)); + + if (!menu->core_buf) + goto finish; + + if (!string_is_empty(data->data)) + memcpy(menu->core_buf, data->data, data->len * sizeof(char)); + menu->core_buf[data->len] = '\0'; + menu->core_len = data->len; + +finish: + refresh = true; + menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh); + + if (data) + { + if (data->data) + free(data->data); + free(data); + } + + if (!err && !strstr(state->path, file_path_str(FILE_PATH_INDEX_DIRS_URL))) + { + char *parent_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + file_transfer_t *transf = NULL; + + parent_dir[0] = '\0'; + + fill_pathname_parent_dir(parent_dir, + state->path, PATH_MAX_LENGTH * sizeof(char)); + strlcat(parent_dir, + file_path_str(FILE_PATH_INDEX_DIRS_URL), + PATH_MAX_LENGTH * sizeof(char)); + + transf = (file_transfer_t*)malloc(sizeof(*transf)); + + transf->enum_idx = MSG_UNKNOWN; + strlcpy(transf->path, parent_dir, sizeof(transf->path)); + + task_push_http_transfer(parent_dir, true, + "index_dirs", cb_net_generic_subdir, transf); + + free(parent_dir); + } + + if (state) + free(state); +#endif +} diff --git a/menu/menu_networking.h b/menu/menu_networking.h index d88c54563a..042af4dd50 100644 --- a/menu/menu_networking.h +++ b/menu/menu_networking.h @@ -1,43 +1,43 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2016-2017 - Brad Parker - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef _MENU_NETWORKING_H -#define _MENU_NETWORKING_H - -#include - -#include -#include - -#include - -#include "../msg_hash.h" - -RETRO_BEGIN_DECLS - -void print_buf_lines(file_list_t *list, char *buf, - const char *label, int buf_size, - enum msg_file_type type, bool append, bool extended); - -void cb_net_generic_subdir(void *task_data, void *user_data, - const char *err); - -void cb_net_generic(void *task_data, void *user_data, const char *err); - -RETRO_END_DECLS - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef _MENU_NETWORKING_H +#define _MENU_NETWORKING_H + +#include + +#include +#include + +#include + +#include "../msg_hash.h" + +RETRO_BEGIN_DECLS + +void print_buf_lines(file_list_t *list, char *buf, + const char *label, int buf_size, + enum msg_file_type type, bool append, bool extended); + +void cb_net_generic_subdir(void *task_data, void *user_data, + const char *err); + +void cb_net_generic(void *task_data, void *user_data, const char *err); + +RETRO_END_DECLS + +#endif diff --git a/midi/drivers/winmm_midi.c b/midi/drivers/winmm_midi.c index 94f7937a3d..0699accb9c 100644 --- a/midi/drivers/winmm_midi.c +++ b/midi/drivers/winmm_midi.c @@ -1,630 +1,630 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2018 The RetroArch team - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include - -#include -#include -#include -#include - -#include "../midi_driver.h" - -#define WINMM_MIDI_BUF_CNT 3 -#define WINMM_MIDI_BUF_LEN 1024 - -typedef struct -{ - MIDIHDR header; - DWORD data[WINMM_MIDI_BUF_LEN]; -} winmm_midi_buffer_t; - -typedef struct -{ - uint8_t data[WINMM_MIDI_BUF_LEN * 4]; - midi_event_t events[WINMM_MIDI_BUF_LEN]; - int rd_idx; - int wr_idx; -} winmm_midi_queue_t; - -typedef struct -{ - HMIDIIN in_dev; - HMIDISTRM out_dev; - winmm_midi_queue_t in_queue; - winmm_midi_buffer_t out_bufs[WINMM_MIDI_BUF_CNT]; - int out_buf_idx; - double tick_dur; -} winmm_midi_t; - -static void winmm_midi_free(void *p); - -static bool winmm_midi_queue_read(winmm_midi_queue_t *q, midi_event_t *ev) -{ - unsigned i; - midi_event_t *src_ev = NULL; - - if (q->rd_idx == q->wr_idx) - return false; - - if (ev->data_size < q->events[q->rd_idx].data_size) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: Input queue read failed (event data too small).\n"); -#endif - return false; - } - - src_ev = &q->events[q->rd_idx]; - - for (i = 0; i < src_ev->data_size; ++i) - ev->data[i] = src_ev->data[i]; - - ev->data_size = src_ev->data_size; - ev->delta_time = src_ev->delta_time; - - if (q->rd_idx + 1 == WINMM_MIDI_BUF_LEN) - q->rd_idx = 0; - else - ++q->rd_idx; - - return true; -} - -static bool winmm_midi_queue_write(winmm_midi_queue_t *q, const midi_event_t *ev) -{ - int wr_avail; - unsigned i; - int rd_idx = q->rd_idx; - midi_event_t *dest_ev = NULL; - - if (q->wr_idx >= rd_idx) - wr_avail = WINMM_MIDI_BUF_LEN - q->wr_idx + rd_idx; - else - wr_avail = rd_idx - q->wr_idx - 1; - - if (wr_avail < 1) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: Input queue overflow.\n"); -#endif - return false; - } - - dest_ev = &q->events[q->wr_idx]; - if (ev->data_size > 4) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: Input queue write failed (event too big).\n"); -#endif - return false; - } - - for (i = 0; i < ev->data_size; ++i) - dest_ev->data[i] = ev->data[i]; - - dest_ev->data_size = ev->data_size; - dest_ev->delta_time = ev->delta_time; - - if (q->wr_idx + 1 == WINMM_MIDI_BUF_LEN) - q->wr_idx = 0; - else - ++q->wr_idx; - - return true; -} - -static void winmm_midi_queue_init(winmm_midi_queue_t *q) -{ - unsigned i, j; - - for (i = j = 0; i < WINMM_MIDI_BUF_LEN; ++i, j += 4) - { - q->events[i].data = &q->data[j]; - q->events[i].delta_time = 0; - } - - q->rd_idx = 0; - q->wr_idx = 0; -} - -static void CALLBACK winmm_midi_input_callback(HMIDIIN dev, UINT msg, - DWORD_PTR q, DWORD_PTR par1, DWORD_PTR par2) -{ - uint8_t data[3]; - midi_event_t event; - winmm_midi_queue_t *queue = (winmm_midi_queue_t*)q; - - (void)dev; - - if (msg == MIM_OPEN) - winmm_midi_queue_init(queue); - else if (msg == MIM_DATA) - { - data[0] = (uint8_t)(par1 & 0xFF); - data[1] = (uint8_t)((par1 >> 8) & 0xFF); - data[2] = (uint8_t)((par1 >> 16) & 0xFF); - - event.data = data; - event.data_size = midi_driver_get_event_size(data[0]); - event.delta_time = 0; - - if (!winmm_midi_queue_write(queue, &event)) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: Input event dropped.\n"); -#endif - } - } - else if(msg == MIM_LONGDATA) - { -#ifdef DEBUG - RARCH_WARN("[MIDI]: SysEx input not implemented, event dropped.\n"); -#endif - } -} - -static HMIDIIN winmm_midi_open_input_device(const char *dev_name, - winmm_midi_queue_t *queue) -{ - unsigned i; - UINT dev_count = midiInGetNumDevs(); - HMIDIIN dev = NULL; - - for (i = 0; i < dev_count; ++i) - { - MIDIINCAPSA caps; - MMRESULT mmr = midiInGetDevCapsA((UINT)i, &caps, sizeof(caps)); - if (mmr == MMSYSERR_NOERROR) - { - if (string_is_equal(caps.szPname, dev_name)) - { - mmr = midiInOpen(&dev, (UINT)i, (DWORD_PTR)winmm_midi_input_callback, - (DWORD_PTR)queue, CALLBACK_FUNCTION); - if (mmr != MMSYSERR_NOERROR) - RARCH_ERR("[MIDI]: midiInOpen failed with error %d.\n", mmr); - break; - } - } - else - RARCH_WARN("[MIDI]: midiInGetDevCapsA failed with error %d.\n", mmr); - } - - return dev; -} - -static HMIDISTRM winmm_midi_open_output_device(const char *dev_name) -{ - unsigned i; - UINT dev_count = midiOutGetNumDevs(); - HMIDISTRM dev = NULL; - - for (i = 0; i < dev_count; ++i) - { - MIDIOUTCAPSA caps; - MMRESULT mmr = midiOutGetDevCapsA(i, &caps, sizeof(caps)); - if (mmr == MMSYSERR_NOERROR) - { - if (string_is_equal(caps.szPname, dev_name)) - { - mmr = midiStreamOpen(&dev, &i, 1, 0, 0, CALLBACK_NULL); - if (mmr != MMSYSERR_NOERROR) - RARCH_ERR("[MIDI]: midiStreamOpen failed with error %d.\n", mmr); - break; - } - } - else - RARCH_WARN("[MIDI]: midiOutGetDevCapsA failed with error %d.\n", mmr); - } - - return dev; -} - -static bool winmm_midi_init_clock(HMIDISTRM out_dev, double *tick_dur) -{ - MIDIPROPTIMEDIV division; - MIDIPROPTEMPO tempo; - MMRESULT mmr; - - tempo.cbStruct = sizeof(tempo); - mmr = midiStreamProperty(out_dev, (LPBYTE)&tempo, - MIDIPROP_GET | MIDIPROP_TEMPO); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: Current tempo unavailable (error %d).\n", mmr); - return false; - } - - division.dwTimeDiv = 3; - while (tempo.dwTempo / division.dwTimeDiv > 320) - division.dwTimeDiv *= 2; - - division.cbStruct = sizeof(division); - mmr = midiStreamProperty(out_dev, (LPBYTE)&division, - MIDIPROP_SET | MIDIPROP_TIMEDIV); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: Time division change failed (error %d).\n", mmr); - return false; - } - - *tick_dur = (double)tempo.dwTempo / (double)division.dwTimeDiv; -#ifdef DEBUG - RARCH_LOG("[MIDI]: Tick duration %f us.\n", *tick_dur); -#endif - - return true; -} - -static bool winmm_midi_init_output_buffers(HMIDISTRM dev, - winmm_midi_buffer_t *bufs) -{ - unsigned i; - - for (i = 0; i < WINMM_MIDI_BUF_CNT; ++i) - { - MMRESULT mmr; - - bufs[i].header.dwBufferLength = sizeof(DWORD) * WINMM_MIDI_BUF_LEN; - bufs[i].header.dwBytesRecorded = 0; - bufs[i].header.dwFlags = 0; - bufs[i].header.lpData = (LPSTR)bufs[i].data; - - mmr = midiOutPrepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR)); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiOutPrepareHeader failed with error %d.\n", mmr); - - while (--i <= 0) - midiOutUnprepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR)); - - return false; - } - } - - return true; -} - -static void winmm_midi_free_output_buffers(HMIDISTRM dev, winmm_midi_buffer_t *bufs) -{ - unsigned i; - - for (i = 0; i < WINMM_MIDI_BUF_CNT; ++i) - { - MMRESULT mmr = midiOutUnprepareHeader( - (HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR)); - if (mmr != MMSYSERR_NOERROR) - RARCH_ERR("[MIDI]: midiOutUnprepareHeader failed with error %d.\n", mmr); - } -} - -static bool winmm_midi_write_short_event(winmm_midi_buffer_t *buf, - const uint8_t *data, size_t data_size, DWORD delta_time) -{ - DWORD i = buf->header.dwBytesRecorded / sizeof(DWORD); - - if (buf->header.dwBytesRecorded + sizeof(DWORD) * 3 > - sizeof(DWORD) * WINMM_MIDI_BUF_LEN) - return false; - - buf->data[i++] = delta_time; - buf->data[i++] = 0; - buf->data[i] = MEVT_F_SHORT << 24; - if (data_size == 0) - buf->data[i] |= MEVT_NOP; - else - { - buf->data[i] |= MEVT_SHORTMSG << 24 | data[0]; - if (data_size > 1) - buf->data[i] |= data[1] << 8; - if (data_size > 2) - buf->data[i] |= data[2] << 16; - } - - buf->header.dwBytesRecorded += sizeof(DWORD) * 3; - - return true; -} - -static bool winmm_midi_write_long_event(winmm_midi_buffer_t *buf, - const uint8_t *data, size_t data_size, DWORD delta_time) -{ - DWORD i = buf->header.dwBytesRecorded / sizeof(DWORD); - - if (buf->header.dwBytesRecorded + sizeof(DWORD) * 3 + data_size > - sizeof(DWORD) * WINMM_MIDI_BUF_LEN) - return false; - - buf->data[i++] = delta_time; - buf->data[i++] = 0; - buf->data[i++] = MEVT_F_LONG << 24 | MEVT_LONGMSG << 24 | data_size; - - memcpy(&buf->data[i], data, data_size); - buf->header.dwBytesRecorded += sizeof(DWORD) * 3 + data_size; - - return true; -} - -static bool winmm_midi_get_avail_inputs(struct string_list *inputs) -{ - unsigned i; - union string_list_elem_attr attr = {0}; - UINT dev_count = midiInGetNumDevs(); - - for (i = 0; i < dev_count; ++i) - { - MIDIINCAPSA caps; - MMRESULT mmr = midiInGetDevCapsA((UINT)i, &caps, sizeof(caps)); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiInGetDevCapsA failed with error %d.\n", mmr); - return false; - } - - if (!string_list_append(inputs, caps.szPname, attr)) - { - RARCH_ERR("[MIDI]: string_list_append failed.\n"); - return false; - } - } - - return true; -} - -static bool winmm_midi_get_avail_outputs(struct string_list *outputs) -{ - unsigned i; - union string_list_elem_attr attr = {0}; - UINT dev_count = midiOutGetNumDevs(); - - for (i = 0; i < dev_count; ++i) - { - MIDIOUTCAPSA caps; - MMRESULT mmr = midiOutGetDevCapsA((UINT)i, &caps, sizeof(caps)); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiOutGetDevCapsA failed with error %d.\n", mmr); - return false; - } - - if (!string_list_append(outputs, caps.szPname, attr)) - { - RARCH_ERR("[MIDI]: string_list_append failed.\n"); - return false; - } - } - - return true; -} - -static void *winmm_midi_init(const char *input, const char *output) -{ - MMRESULT mmr; - bool err = false; - winmm_midi_t *d = (winmm_midi_t*)calloc(sizeof(winmm_midi_t), 1); - - if (!d) - { - RARCH_ERR("[MIDI]: Out of memory.\n"); - return NULL; - } - - if (input) - { - d->in_dev = winmm_midi_open_input_device(input, &d->in_queue); - if (!d->in_dev) - err = true; - else - { - mmr = midiInStart(d->in_dev); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiInStart failed with error %d.\n", mmr); - err = true; - } - } - } - - if (output) - { - d->out_dev = winmm_midi_open_output_device(output); - if (!d->out_dev) - err = true; - else if (!winmm_midi_init_clock(d->out_dev, &d->tick_dur)) - err = true; - else if (!winmm_midi_init_output_buffers(d->out_dev, d->out_bufs)) - err = true; - else - { - mmr = midiStreamRestart(d->out_dev); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiStreamRestart failed with error %d.\n", mmr); - err = true; - } - } - } - - if (err) - { - winmm_midi_free(d); - return NULL; - } - - return d; -} - -static void winmm_midi_free(void *p) -{ - winmm_midi_t *d = (winmm_midi_t*)p; - - if (!d) - return; - - if (d->in_dev) - { - midiInStop(d->in_dev); - midiInClose(d->in_dev); - } - - if (d->out_dev) - { - midiStreamStop(d->out_dev); - winmm_midi_free_output_buffers(d->out_dev, d->out_bufs); - midiStreamClose(d->out_dev); - } - - free(d); -} - -static bool winmm_midi_set_input(void *p, const char *input) -{ - winmm_midi_t *d = (winmm_midi_t*)p; - HMIDIIN new_dev = NULL; - - if (input) - { - new_dev = winmm_midi_open_input_device(input, &d->in_queue); - if (!new_dev) - return false; - } - - if (d->in_dev) - { - midiInStop(d->in_dev); - midiInClose(d->in_dev); - } - - d->in_dev = new_dev; - if (d->in_dev) - { - MMRESULT mmr = midiInStart(d->in_dev); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiInStart failed with error %d.\n", mmr); - return false; - } - } - - return true; -} - -static bool winmm_midi_set_output(void *p, const char *output) -{ - winmm_midi_t *d = (winmm_midi_t*)p; - HMIDISTRM new_dev = NULL; - - if (output) - { - new_dev = winmm_midi_open_output_device(output); - if (!new_dev) - return false; - } - - if (d->out_dev) - { - midiStreamStop(d->out_dev); - winmm_midi_free_output_buffers(d->out_dev, d->out_bufs); - midiStreamClose(d->out_dev); - } - - d->out_dev = new_dev; - if (d->out_dev) - { - MMRESULT mmr; - if (!winmm_midi_init_output_buffers(d->out_dev, d->out_bufs)) - return false; - - d->out_buf_idx = 0; - - mmr = midiStreamRestart(d->out_dev); - if (mmr != MMSYSERR_NOERROR) - { - RARCH_ERR("[MIDI]: midiStreamRestart failed with error %d.\n", mmr); - return false; - } - } - - return true; -} - -static bool winmm_midi_read(void *p, midi_event_t *event) -{ - winmm_midi_t *d = (winmm_midi_t*)p; - - return winmm_midi_queue_read(&d->in_queue, event); -} - -static bool winmm_midi_write(void *p, const midi_event_t *event) -{ - winmm_midi_t *d = (winmm_midi_t*)p; - winmm_midi_buffer_t *buf = &d->out_bufs[d->out_buf_idx]; - DWORD delta_time; - - if (buf->header.dwFlags & MHDR_INQUEUE) - return false; - - if (buf->header.dwFlags & MHDR_DONE) - { - buf->header.dwBytesRecorded = 0; - buf->header.dwFlags ^= MHDR_DONE; - } - - delta_time = (DWORD)((double)event->delta_time / d->tick_dur); - if (event->data_size < 4) - return winmm_midi_write_short_event(buf, event->data, - event->data_size, delta_time); - - return winmm_midi_write_long_event(buf, event->data, - event->data_size, delta_time); -} - -static bool winmm_midi_flush(void *p) -{ - winmm_midi_t *d = (winmm_midi_t*)p; - winmm_midi_buffer_t *buf = &d->out_bufs[d->out_buf_idx]; - - if (buf->header.dwBytesRecorded) - { - MMRESULT mmr = midiStreamOut( - d->out_dev, &buf->header, sizeof(buf->header)); - - if (mmr != MMSYSERR_NOERROR) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: midiStreamOut failed with error %d.\n", mmr); -#endif - return false; - } - - if (++d->out_buf_idx == WINMM_MIDI_BUF_CNT) - d->out_buf_idx = 0; - } - - return true; -} - -midi_driver_t midi_winmm = { - "winmm", - winmm_midi_get_avail_inputs, - winmm_midi_get_avail_outputs, - winmm_midi_init, - winmm_midi_free, - winmm_midi_set_input, - winmm_midi_set_output, - winmm_midi_read, - winmm_midi_write, - winmm_midi_flush -}; +/* RetroArch - A frontend for libretro. + * Copyright (C) 2018 The RetroArch team + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include + +#include +#include +#include +#include + +#include "../midi_driver.h" + +#define WINMM_MIDI_BUF_CNT 3 +#define WINMM_MIDI_BUF_LEN 1024 + +typedef struct +{ + MIDIHDR header; + DWORD data[WINMM_MIDI_BUF_LEN]; +} winmm_midi_buffer_t; + +typedef struct +{ + uint8_t data[WINMM_MIDI_BUF_LEN * 4]; + midi_event_t events[WINMM_MIDI_BUF_LEN]; + int rd_idx; + int wr_idx; +} winmm_midi_queue_t; + +typedef struct +{ + HMIDIIN in_dev; + HMIDISTRM out_dev; + winmm_midi_queue_t in_queue; + winmm_midi_buffer_t out_bufs[WINMM_MIDI_BUF_CNT]; + int out_buf_idx; + double tick_dur; +} winmm_midi_t; + +static void winmm_midi_free(void *p); + +static bool winmm_midi_queue_read(winmm_midi_queue_t *q, midi_event_t *ev) +{ + unsigned i; + midi_event_t *src_ev = NULL; + + if (q->rd_idx == q->wr_idx) + return false; + + if (ev->data_size < q->events[q->rd_idx].data_size) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: Input queue read failed (event data too small).\n"); +#endif + return false; + } + + src_ev = &q->events[q->rd_idx]; + + for (i = 0; i < src_ev->data_size; ++i) + ev->data[i] = src_ev->data[i]; + + ev->data_size = src_ev->data_size; + ev->delta_time = src_ev->delta_time; + + if (q->rd_idx + 1 == WINMM_MIDI_BUF_LEN) + q->rd_idx = 0; + else + ++q->rd_idx; + + return true; +} + +static bool winmm_midi_queue_write(winmm_midi_queue_t *q, const midi_event_t *ev) +{ + int wr_avail; + unsigned i; + int rd_idx = q->rd_idx; + midi_event_t *dest_ev = NULL; + + if (q->wr_idx >= rd_idx) + wr_avail = WINMM_MIDI_BUF_LEN - q->wr_idx + rd_idx; + else + wr_avail = rd_idx - q->wr_idx - 1; + + if (wr_avail < 1) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: Input queue overflow.\n"); +#endif + return false; + } + + dest_ev = &q->events[q->wr_idx]; + if (ev->data_size > 4) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: Input queue write failed (event too big).\n"); +#endif + return false; + } + + for (i = 0; i < ev->data_size; ++i) + dest_ev->data[i] = ev->data[i]; + + dest_ev->data_size = ev->data_size; + dest_ev->delta_time = ev->delta_time; + + if (q->wr_idx + 1 == WINMM_MIDI_BUF_LEN) + q->wr_idx = 0; + else + ++q->wr_idx; + + return true; +} + +static void winmm_midi_queue_init(winmm_midi_queue_t *q) +{ + unsigned i, j; + + for (i = j = 0; i < WINMM_MIDI_BUF_LEN; ++i, j += 4) + { + q->events[i].data = &q->data[j]; + q->events[i].delta_time = 0; + } + + q->rd_idx = 0; + q->wr_idx = 0; +} + +static void CALLBACK winmm_midi_input_callback(HMIDIIN dev, UINT msg, + DWORD_PTR q, DWORD_PTR par1, DWORD_PTR par2) +{ + uint8_t data[3]; + midi_event_t event; + winmm_midi_queue_t *queue = (winmm_midi_queue_t*)q; + + (void)dev; + + if (msg == MIM_OPEN) + winmm_midi_queue_init(queue); + else if (msg == MIM_DATA) + { + data[0] = (uint8_t)(par1 & 0xFF); + data[1] = (uint8_t)((par1 >> 8) & 0xFF); + data[2] = (uint8_t)((par1 >> 16) & 0xFF); + + event.data = data; + event.data_size = midi_driver_get_event_size(data[0]); + event.delta_time = 0; + + if (!winmm_midi_queue_write(queue, &event)) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: Input event dropped.\n"); +#endif + } + } + else if(msg == MIM_LONGDATA) + { +#ifdef DEBUG + RARCH_WARN("[MIDI]: SysEx input not implemented, event dropped.\n"); +#endif + } +} + +static HMIDIIN winmm_midi_open_input_device(const char *dev_name, + winmm_midi_queue_t *queue) +{ + unsigned i; + UINT dev_count = midiInGetNumDevs(); + HMIDIIN dev = NULL; + + for (i = 0; i < dev_count; ++i) + { + MIDIINCAPSA caps; + MMRESULT mmr = midiInGetDevCapsA((UINT)i, &caps, sizeof(caps)); + if (mmr == MMSYSERR_NOERROR) + { + if (string_is_equal(caps.szPname, dev_name)) + { + mmr = midiInOpen(&dev, (UINT)i, (DWORD_PTR)winmm_midi_input_callback, + (DWORD_PTR)queue, CALLBACK_FUNCTION); + if (mmr != MMSYSERR_NOERROR) + RARCH_ERR("[MIDI]: midiInOpen failed with error %d.\n", mmr); + break; + } + } + else + RARCH_WARN("[MIDI]: midiInGetDevCapsA failed with error %d.\n", mmr); + } + + return dev; +} + +static HMIDISTRM winmm_midi_open_output_device(const char *dev_name) +{ + unsigned i; + UINT dev_count = midiOutGetNumDevs(); + HMIDISTRM dev = NULL; + + for (i = 0; i < dev_count; ++i) + { + MIDIOUTCAPSA caps; + MMRESULT mmr = midiOutGetDevCapsA(i, &caps, sizeof(caps)); + if (mmr == MMSYSERR_NOERROR) + { + if (string_is_equal(caps.szPname, dev_name)) + { + mmr = midiStreamOpen(&dev, &i, 1, 0, 0, CALLBACK_NULL); + if (mmr != MMSYSERR_NOERROR) + RARCH_ERR("[MIDI]: midiStreamOpen failed with error %d.\n", mmr); + break; + } + } + else + RARCH_WARN("[MIDI]: midiOutGetDevCapsA failed with error %d.\n", mmr); + } + + return dev; +} + +static bool winmm_midi_init_clock(HMIDISTRM out_dev, double *tick_dur) +{ + MIDIPROPTIMEDIV division; + MIDIPROPTEMPO tempo; + MMRESULT mmr; + + tempo.cbStruct = sizeof(tempo); + mmr = midiStreamProperty(out_dev, (LPBYTE)&tempo, + MIDIPROP_GET | MIDIPROP_TEMPO); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: Current tempo unavailable (error %d).\n", mmr); + return false; + } + + division.dwTimeDiv = 3; + while (tempo.dwTempo / division.dwTimeDiv > 320) + division.dwTimeDiv *= 2; + + division.cbStruct = sizeof(division); + mmr = midiStreamProperty(out_dev, (LPBYTE)&division, + MIDIPROP_SET | MIDIPROP_TIMEDIV); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: Time division change failed (error %d).\n", mmr); + return false; + } + + *tick_dur = (double)tempo.dwTempo / (double)division.dwTimeDiv; +#ifdef DEBUG + RARCH_LOG("[MIDI]: Tick duration %f us.\n", *tick_dur); +#endif + + return true; +} + +static bool winmm_midi_init_output_buffers(HMIDISTRM dev, + winmm_midi_buffer_t *bufs) +{ + unsigned i; + + for (i = 0; i < WINMM_MIDI_BUF_CNT; ++i) + { + MMRESULT mmr; + + bufs[i].header.dwBufferLength = sizeof(DWORD) * WINMM_MIDI_BUF_LEN; + bufs[i].header.dwBytesRecorded = 0; + bufs[i].header.dwFlags = 0; + bufs[i].header.lpData = (LPSTR)bufs[i].data; + + mmr = midiOutPrepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR)); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiOutPrepareHeader failed with error %d.\n", mmr); + + while (--i <= 0) + midiOutUnprepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR)); + + return false; + } + } + + return true; +} + +static void winmm_midi_free_output_buffers(HMIDISTRM dev, winmm_midi_buffer_t *bufs) +{ + unsigned i; + + for (i = 0; i < WINMM_MIDI_BUF_CNT; ++i) + { + MMRESULT mmr = midiOutUnprepareHeader( + (HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR)); + if (mmr != MMSYSERR_NOERROR) + RARCH_ERR("[MIDI]: midiOutUnprepareHeader failed with error %d.\n", mmr); + } +} + +static bool winmm_midi_write_short_event(winmm_midi_buffer_t *buf, + const uint8_t *data, size_t data_size, DWORD delta_time) +{ + DWORD i = buf->header.dwBytesRecorded / sizeof(DWORD); + + if (buf->header.dwBytesRecorded + sizeof(DWORD) * 3 > + sizeof(DWORD) * WINMM_MIDI_BUF_LEN) + return false; + + buf->data[i++] = delta_time; + buf->data[i++] = 0; + buf->data[i] = MEVT_F_SHORT << 24; + if (data_size == 0) + buf->data[i] |= MEVT_NOP; + else + { + buf->data[i] |= MEVT_SHORTMSG << 24 | data[0]; + if (data_size > 1) + buf->data[i] |= data[1] << 8; + if (data_size > 2) + buf->data[i] |= data[2] << 16; + } + + buf->header.dwBytesRecorded += sizeof(DWORD) * 3; + + return true; +} + +static bool winmm_midi_write_long_event(winmm_midi_buffer_t *buf, + const uint8_t *data, size_t data_size, DWORD delta_time) +{ + DWORD i = buf->header.dwBytesRecorded / sizeof(DWORD); + + if (buf->header.dwBytesRecorded + sizeof(DWORD) * 3 + data_size > + sizeof(DWORD) * WINMM_MIDI_BUF_LEN) + return false; + + buf->data[i++] = delta_time; + buf->data[i++] = 0; + buf->data[i++] = MEVT_F_LONG << 24 | MEVT_LONGMSG << 24 | data_size; + + memcpy(&buf->data[i], data, data_size); + buf->header.dwBytesRecorded += sizeof(DWORD) * 3 + data_size; + + return true; +} + +static bool winmm_midi_get_avail_inputs(struct string_list *inputs) +{ + unsigned i; + union string_list_elem_attr attr = {0}; + UINT dev_count = midiInGetNumDevs(); + + for (i = 0; i < dev_count; ++i) + { + MIDIINCAPSA caps; + MMRESULT mmr = midiInGetDevCapsA((UINT)i, &caps, sizeof(caps)); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiInGetDevCapsA failed with error %d.\n", mmr); + return false; + } + + if (!string_list_append(inputs, caps.szPname, attr)) + { + RARCH_ERR("[MIDI]: string_list_append failed.\n"); + return false; + } + } + + return true; +} + +static bool winmm_midi_get_avail_outputs(struct string_list *outputs) +{ + unsigned i; + union string_list_elem_attr attr = {0}; + UINT dev_count = midiOutGetNumDevs(); + + for (i = 0; i < dev_count; ++i) + { + MIDIOUTCAPSA caps; + MMRESULT mmr = midiOutGetDevCapsA((UINT)i, &caps, sizeof(caps)); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiOutGetDevCapsA failed with error %d.\n", mmr); + return false; + } + + if (!string_list_append(outputs, caps.szPname, attr)) + { + RARCH_ERR("[MIDI]: string_list_append failed.\n"); + return false; + } + } + + return true; +} + +static void *winmm_midi_init(const char *input, const char *output) +{ + MMRESULT mmr; + bool err = false; + winmm_midi_t *d = (winmm_midi_t*)calloc(sizeof(winmm_midi_t), 1); + + if (!d) + { + RARCH_ERR("[MIDI]: Out of memory.\n"); + return NULL; + } + + if (input) + { + d->in_dev = winmm_midi_open_input_device(input, &d->in_queue); + if (!d->in_dev) + err = true; + else + { + mmr = midiInStart(d->in_dev); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiInStart failed with error %d.\n", mmr); + err = true; + } + } + } + + if (output) + { + d->out_dev = winmm_midi_open_output_device(output); + if (!d->out_dev) + err = true; + else if (!winmm_midi_init_clock(d->out_dev, &d->tick_dur)) + err = true; + else if (!winmm_midi_init_output_buffers(d->out_dev, d->out_bufs)) + err = true; + else + { + mmr = midiStreamRestart(d->out_dev); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiStreamRestart failed with error %d.\n", mmr); + err = true; + } + } + } + + if (err) + { + winmm_midi_free(d); + return NULL; + } + + return d; +} + +static void winmm_midi_free(void *p) +{ + winmm_midi_t *d = (winmm_midi_t*)p; + + if (!d) + return; + + if (d->in_dev) + { + midiInStop(d->in_dev); + midiInClose(d->in_dev); + } + + if (d->out_dev) + { + midiStreamStop(d->out_dev); + winmm_midi_free_output_buffers(d->out_dev, d->out_bufs); + midiStreamClose(d->out_dev); + } + + free(d); +} + +static bool winmm_midi_set_input(void *p, const char *input) +{ + winmm_midi_t *d = (winmm_midi_t*)p; + HMIDIIN new_dev = NULL; + + if (input) + { + new_dev = winmm_midi_open_input_device(input, &d->in_queue); + if (!new_dev) + return false; + } + + if (d->in_dev) + { + midiInStop(d->in_dev); + midiInClose(d->in_dev); + } + + d->in_dev = new_dev; + if (d->in_dev) + { + MMRESULT mmr = midiInStart(d->in_dev); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiInStart failed with error %d.\n", mmr); + return false; + } + } + + return true; +} + +static bool winmm_midi_set_output(void *p, const char *output) +{ + winmm_midi_t *d = (winmm_midi_t*)p; + HMIDISTRM new_dev = NULL; + + if (output) + { + new_dev = winmm_midi_open_output_device(output); + if (!new_dev) + return false; + } + + if (d->out_dev) + { + midiStreamStop(d->out_dev); + winmm_midi_free_output_buffers(d->out_dev, d->out_bufs); + midiStreamClose(d->out_dev); + } + + d->out_dev = new_dev; + if (d->out_dev) + { + MMRESULT mmr; + if (!winmm_midi_init_output_buffers(d->out_dev, d->out_bufs)) + return false; + + d->out_buf_idx = 0; + + mmr = midiStreamRestart(d->out_dev); + if (mmr != MMSYSERR_NOERROR) + { + RARCH_ERR("[MIDI]: midiStreamRestart failed with error %d.\n", mmr); + return false; + } + } + + return true; +} + +static bool winmm_midi_read(void *p, midi_event_t *event) +{ + winmm_midi_t *d = (winmm_midi_t*)p; + + return winmm_midi_queue_read(&d->in_queue, event); +} + +static bool winmm_midi_write(void *p, const midi_event_t *event) +{ + winmm_midi_t *d = (winmm_midi_t*)p; + winmm_midi_buffer_t *buf = &d->out_bufs[d->out_buf_idx]; + DWORD delta_time; + + if (buf->header.dwFlags & MHDR_INQUEUE) + return false; + + if (buf->header.dwFlags & MHDR_DONE) + { + buf->header.dwBytesRecorded = 0; + buf->header.dwFlags ^= MHDR_DONE; + } + + delta_time = (DWORD)((double)event->delta_time / d->tick_dur); + if (event->data_size < 4) + return winmm_midi_write_short_event(buf, event->data, + event->data_size, delta_time); + + return winmm_midi_write_long_event(buf, event->data, + event->data_size, delta_time); +} + +static bool winmm_midi_flush(void *p) +{ + winmm_midi_t *d = (winmm_midi_t*)p; + winmm_midi_buffer_t *buf = &d->out_bufs[d->out_buf_idx]; + + if (buf->header.dwBytesRecorded) + { + MMRESULT mmr = midiStreamOut( + d->out_dev, &buf->header, sizeof(buf->header)); + + if (mmr != MMSYSERR_NOERROR) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: midiStreamOut failed with error %d.\n", mmr); +#endif + return false; + } + + if (++d->out_buf_idx == WINMM_MIDI_BUF_CNT) + d->out_buf_idx = 0; + } + + return true; +} + +midi_driver_t midi_winmm = { + "winmm", + winmm_midi_get_avail_inputs, + winmm_midi_get_avail_outputs, + winmm_midi_init, + winmm_midi_free, + winmm_midi_set_input, + winmm_midi_set_output, + winmm_midi_read, + winmm_midi_write, + winmm_midi_flush +}; diff --git a/tasks/task_file_transfer.h b/tasks/task_file_transfer.h index f1dc43379a..605b43f1f0 100644 --- a/tasks/task_file_transfer.h +++ b/tasks/task_file_transfer.h @@ -1,81 +1,81 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef TASKS_FILE_TRANSFER_H -#define TASKS_FILE_TRANSFER_H - -#include -#include -#include - -#include - -#include "../msg_hash.h" - -RETRO_BEGIN_DECLS - -enum nbio_status_enum -{ - NBIO_STATUS_INIT = 0, - NBIO_STATUS_TRANSFER, - NBIO_STATUS_TRANSFER_PARSE, - NBIO_STATUS_TRANSFER_FINISHED -}; - -enum nbio_type -{ - NBIO_TYPE_NONE = 0, - NBIO_TYPE_JPEG, - NBIO_TYPE_PNG, - NBIO_TYPE_TGA, - NBIO_TYPE_BMP, - NBIO_TYPE_OGG, - NBIO_TYPE_FLAC, - NBIO_TYPE_MP3, - NBIO_TYPE_MOD, - NBIO_TYPE_WAV -}; - -enum nbio_status_flags -{ - NBIO_FLAG_NONE = 0, - NBIO_FLAG_IMAGE_SUPPORTS_RGBA -}; - -typedef int (*transfer_cb_t)(void *data, size_t len); - -typedef struct nbio_handle -{ - enum nbio_type type; - bool is_finished; - unsigned status; - unsigned pos_increment; - uint32_t status_flags; - void *data; - char *path; - struct nbio_t *handle; - msg_queue_t *msg_queue; - transfer_cb_t cb; -} nbio_handle_t; - -typedef struct -{ - enum msg_hash_enums enum_idx; - char path[PATH_MAX_LENGTH]; -} file_transfer_t; - -RETRO_END_DECLS - -#endif +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef TASKS_FILE_TRANSFER_H +#define TASKS_FILE_TRANSFER_H + +#include +#include +#include + +#include + +#include "../msg_hash.h" + +RETRO_BEGIN_DECLS + +enum nbio_status_enum +{ + NBIO_STATUS_INIT = 0, + NBIO_STATUS_TRANSFER, + NBIO_STATUS_TRANSFER_PARSE, + NBIO_STATUS_TRANSFER_FINISHED +}; + +enum nbio_type +{ + NBIO_TYPE_NONE = 0, + NBIO_TYPE_JPEG, + NBIO_TYPE_PNG, + NBIO_TYPE_TGA, + NBIO_TYPE_BMP, + NBIO_TYPE_OGG, + NBIO_TYPE_FLAC, + NBIO_TYPE_MP3, + NBIO_TYPE_MOD, + NBIO_TYPE_WAV +}; + +enum nbio_status_flags +{ + NBIO_FLAG_NONE = 0, + NBIO_FLAG_IMAGE_SUPPORTS_RGBA +}; + +typedef int (*transfer_cb_t)(void *data, size_t len); + +typedef struct nbio_handle +{ + enum nbio_type type; + bool is_finished; + unsigned status; + unsigned pos_increment; + uint32_t status_flags; + void *data; + char *path; + struct nbio_t *handle; + msg_queue_t *msg_queue; + transfer_cb_t cb; +} nbio_handle_t; + +typedef struct +{ + enum msg_hash_enums enum_idx; + char path[PATH_MAX_LENGTH]; +} file_transfer_t; + +RETRO_END_DECLS + +#endif diff --git a/tools/ps3/ps3py/LICENSE b/tools/ps3/ps3py/LICENSE index 1580af9d38..201154bbc7 100644 --- a/tools/ps3/ps3py/LICENSE +++ b/tools/ps3/ps3py/LICENSE @@ -1,19 +1,19 @@ - Copyright (c) 2011 PSL1GHT Development Team - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. + Copyright (c) 2011 PSL1GHT Development Team + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/translation/drivers_ocr/tesseract/wrapper/tess_get_text.cpp b/translation/drivers_ocr/tesseract/wrapper/tess_get_text.cpp index 4de99e8973..fabf33d974 100644 --- a/translation/drivers_ocr/tesseract/wrapper/tess_get_text.cpp +++ b/translation/drivers_ocr/tesseract/wrapper/tess_get_text.cpp @@ -1,46 +1,46 @@ -#include -#include -#include "tess_get_text.h" - -#define ERROR_BUFFER_LENGTH 1000 - -static tesseract::TessBaseAPI *api; -static char* one_time_return_pointer = NULL; - -char tess_last_error[ERROR_BUFFER_LENGTH]; - -bool tess_init(const char* lang_data_dir, const char* language) -{ - api = new tesseract::TessBaseAPI(); - - snprintf(tess_last_error, ERROR_BUFFER_LENGTH, "No errors!\n"); - - if (api->Init(lang_data_dir, language)) - { - snprintf(tess_last_error, ERROR_BUFFER_LENGTH, - "Could not initialize tesseract.\n"); - return false; - } - - return true; -} - -void tess_deinit(void) -{ - if (one_time_return_pointer) - delete [] one_time_return_pointer; - - if (api) - api->End(); -} - -char* tess_get_text(tess_image image) -{ - if (one_time_return_pointer) - delete [] one_time_return_pointer; - - api->SetImage(image.data, image.width, image.height, - image.bytes_per_pixel, image.width * image.bytes_per_pixel); - one_time_return_pointer = api->GetUTF8Text(); - return one_time_return_pointer; -} +#include +#include +#include "tess_get_text.h" + +#define ERROR_BUFFER_LENGTH 1000 + +static tesseract::TessBaseAPI *api; +static char* one_time_return_pointer = NULL; + +char tess_last_error[ERROR_BUFFER_LENGTH]; + +bool tess_init(const char* lang_data_dir, const char* language) +{ + api = new tesseract::TessBaseAPI(); + + snprintf(tess_last_error, ERROR_BUFFER_LENGTH, "No errors!\n"); + + if (api->Init(lang_data_dir, language)) + { + snprintf(tess_last_error, ERROR_BUFFER_LENGTH, + "Could not initialize tesseract.\n"); + return false; + } + + return true; +} + +void tess_deinit(void) +{ + if (one_time_return_pointer) + delete [] one_time_return_pointer; + + if (api) + api->End(); +} + +char* tess_get_text(tess_image image) +{ + if (one_time_return_pointer) + delete [] one_time_return_pointer; + + api->SetImage(image.data, image.width, image.height, + image.bytes_per_pixel, image.width * image.bytes_per_pixel); + one_time_return_pointer = api->GetUTF8Text(); + return one_time_return_pointer; +} diff --git a/translation/drivers_ocr/tesseract/wrapper/tess_get_text.h b/translation/drivers_ocr/tesseract/wrapper/tess_get_text.h index 22410185ec..55cb827b7a 100644 --- a/translation/drivers_ocr/tesseract/wrapper/tess_get_text.h +++ b/translation/drivers_ocr/tesseract/wrapper/tess_get_text.h @@ -1,26 +1,26 @@ -#ifndef TESS_GET_TEXT -#define TESS_GET_TEXT - -#include -#include - -RETRO_BEGIN_DECLS - -typedef struct -{ - unsigned width; - unsigned height; - unsigned bytes_per_pixel; - void* data; -} tess_image; - -/* if running in RetroArch language should be "eng" or "jpn" */ -bool tess_init(const char* lang_data_dir, const char* language); -void tess_deinit(void); -char* tess_get_text(tess_image image); - -extern char tess_last_error[]; - -RETRO_END_DECLS - -#endif +#ifndef TESS_GET_TEXT +#define TESS_GET_TEXT + +#include +#include + +RETRO_BEGIN_DECLS + +typedef struct +{ + unsigned width; + unsigned height; + unsigned bytes_per_pixel; + void* data; +} tess_image; + +/* if running in RetroArch language should be "eng" or "jpn" */ +bool tess_init(const char* lang_data_dir, const char* language); +void tess_deinit(void); +char* tess_get_text(tess_image image); + +extern char tess_last_error[]; + +RETRO_END_DECLS + +#endif diff --git a/translation/ocr_driver.c b/translation/ocr_driver.c index 38bd2fb51d..5d7bb868fb 100644 --- a/translation/ocr_driver.c +++ b/translation/ocr_driver.c @@ -1,58 +1,58 @@ -#include -#include - -#include "ocr_driver.h" -#include "../configuration.h" - -static const ocr_driver_t *ocr_backends[] = { -#ifdef HAVE_TESSERACT - &ocr_tesseract, -#endif - &ocr_null, - NULL -}; - -static const ocr_driver_t *current_ocr_backend = NULL; -static void *ocr_data = NULL; - - -static const ocr_driver_t *ocr_find_backend(const char* ident) -{ - unsigned i; - - for (i = 0; ocr_backends[i]; i++) - { - if (string_is_equal(ocr_backends[i]->ident, ident)) - return ocr_backends[i]; - } - - return NULL; -} - -bool ocr_driver_init(void) -{ - settings_t *settings = config_get_ptr(); - int game_char_set = RETRO_LANGUAGE_DUMMY; - current_ocr_backend = ocr_find_backend(settings->arrays.ocr_driver); - ocr_data = NULL; - - /* TODO: get game language */ - - if (current_ocr_backend) - ocr_data = (*current_ocr_backend->init)(game_char_set); - return ocr_data != NULL; -} - -void ocr_driver_free(void) -{ - if (current_ocr_backend && ocr_data) - (*current_ocr_backend->free)(ocr_data); -} - -char* ocr_driver_get_text(struct ocr_image_info image) -{ - char* image_string = NULL; - if (current_ocr_backend && ocr_data) - image_string = (*current_ocr_backend->get_text)(ocr_data, image); - return image_string; +#include +#include + +#include "ocr_driver.h" +#include "../configuration.h" + +static const ocr_driver_t *ocr_backends[] = { +#ifdef HAVE_TESSERACT + &ocr_tesseract, +#endif + &ocr_null, + NULL +}; + +static const ocr_driver_t *current_ocr_backend = NULL; +static void *ocr_data = NULL; + + +static const ocr_driver_t *ocr_find_backend(const char* ident) +{ + unsigned i; + + for (i = 0; ocr_backends[i]; i++) + { + if (string_is_equal(ocr_backends[i]->ident, ident)) + return ocr_backends[i]; + } + + return NULL; +} + +bool ocr_driver_init(void) +{ + settings_t *settings = config_get_ptr(); + int game_char_set = RETRO_LANGUAGE_DUMMY; + current_ocr_backend = ocr_find_backend(settings->arrays.ocr_driver); + ocr_data = NULL; + + /* TODO: get game language */ + + if (current_ocr_backend) + ocr_data = (*current_ocr_backend->init)(game_char_set); + return ocr_data != NULL; +} + +void ocr_driver_free(void) +{ + if (current_ocr_backend && ocr_data) + (*current_ocr_backend->free)(ocr_data); +} + +char* ocr_driver_get_text(struct ocr_image_info image) +{ + char* image_string = NULL; + if (current_ocr_backend && ocr_data) + image_string = (*current_ocr_backend->get_text)(ocr_data, image); + return image_string; } \ No newline at end of file diff --git a/translation/ocr_driver.h b/translation/ocr_driver.h index d9241cc8d4..bd5e7cc770 100644 --- a/translation/ocr_driver.h +++ b/translation/ocr_driver.h @@ -1,41 +1,41 @@ -#ifndef __OCR_DRIVER__H -#define __OCR_DRIVER__H - -#include -#include - -RETRO_BEGIN_DECLS - -struct ocr_image_info -{ - unsigned width; - unsigned height; - unsigned pixel_format; - void* data; -}; - -typedef struct ocr_driver -{ - void* (*init)(int game_character_set); - void (*free)(void* data); - - /* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to get_text */ - char* (*get_text)(void* data, struct ocr_image_info image); - - const char *ident; -} ocr_driver_t; - -#ifdef HAVE_TESSERACT -extern const ocr_driver_t ocr_tesseract; -#endif -extern const ocr_driver_t ocr_null; - -bool ocr_driver_init(void); -void ocr_driver_free(void); - -/* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to ocr_driver_get_text */ -char* ocr_driver_get_text(struct ocr_image_info image); - -RETRO_END_DECLS - +#ifndef __OCR_DRIVER__H +#define __OCR_DRIVER__H + +#include +#include + +RETRO_BEGIN_DECLS + +struct ocr_image_info +{ + unsigned width; + unsigned height; + unsigned pixel_format; + void* data; +}; + +typedef struct ocr_driver +{ + void* (*init)(int game_character_set); + void (*free)(void* data); + + /* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to get_text */ + char* (*get_text)(void* data, struct ocr_image_info image); + + const char *ident; +} ocr_driver_t; + +#ifdef HAVE_TESSERACT +extern const ocr_driver_t ocr_tesseract; +#endif +extern const ocr_driver_t ocr_null; + +bool ocr_driver_init(void); +void ocr_driver_free(void); + +/* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to ocr_driver_get_text */ +char* ocr_driver_get_text(struct ocr_image_info image); + +RETRO_END_DECLS + #endif \ No newline at end of file diff --git a/translation/translation_driver.c b/translation/translation_driver.c index 9ab3eb32b1..4a10a86f9f 100644 --- a/translation/translation_driver.c +++ b/translation/translation_driver.c @@ -1,67 +1,67 @@ -#include - -#include "translation_driver.h" -#include "ocr_driver.h" -#include "../configuration.h" - -static const translation_driver_t *translation_backends[] = { - &translation_cached_google, - &ocr_null, - NULL -}; - -static const translation_driver_t *current_translation_backend = NULL; -static void *translation_data = NULL; - -static const translation_driver_t *translation_find_backend( - const char* ident) -{ - unsigned i; - - for (i = 0; translation_backends[i]; i++) - { - if (string_is_equal(translation_backends[i]->ident, ident)) - return translation_backends[i]; - } - - return NULL; -} - -bool translation_driver_init(void) -{ - settings_t *settings = config_get_ptr(); - - if (!settings) - return false; - - current_translation_backend = translation_find_backend( - settings->arrays.translation_driver); - translation_data = NULL; - - if (current_translation_backend) - translation_data = (*current_translation_backend->init)(); - return translation_data != NULL; -} - -void translation_driver_free(void) -{ - if (current_translation_backend && translation_data) - (*current_translation_backend->free)(translation_data); -} - -char* translation_driver_translate_image(struct ocr_image_info image) -{ - char* translated_text = NULL; - - if (current_translation_backend && translation_data) - { - if (current_translation_backend->translate_image) - translated_text = (*current_translation_backend->translate_image) - (translation_data, image); - else - translated_text = (*current_translation_backend->translate_text) - (translation_data, ocr_driver_get_text(image)); - } - - return translated_text; -} +#include + +#include "translation_driver.h" +#include "ocr_driver.h" +#include "../configuration.h" + +static const translation_driver_t *translation_backends[] = { + &translation_cached_google, + &ocr_null, + NULL +}; + +static const translation_driver_t *current_translation_backend = NULL; +static void *translation_data = NULL; + +static const translation_driver_t *translation_find_backend( + const char* ident) +{ + unsigned i; + + for (i = 0; translation_backends[i]; i++) + { + if (string_is_equal(translation_backends[i]->ident, ident)) + return translation_backends[i]; + } + + return NULL; +} + +bool translation_driver_init(void) +{ + settings_t *settings = config_get_ptr(); + + if (!settings) + return false; + + current_translation_backend = translation_find_backend( + settings->arrays.translation_driver); + translation_data = NULL; + + if (current_translation_backend) + translation_data = (*current_translation_backend->init)(); + return translation_data != NULL; +} + +void translation_driver_free(void) +{ + if (current_translation_backend && translation_data) + (*current_translation_backend->free)(translation_data); +} + +char* translation_driver_translate_image(struct ocr_image_info image) +{ + char* translated_text = NULL; + + if (current_translation_backend && translation_data) + { + if (current_translation_backend->translate_image) + translated_text = (*current_translation_backend->translate_image) + (translation_data, image); + else + translated_text = (*current_translation_backend->translate_text) + (translation_data, ocr_driver_get_text(image)); + } + + return translated_text; +} diff --git a/translation/translation_driver.h b/translation/translation_driver.h index 561a2952c1..e5d2ca38b5 100644 --- a/translation/translation_driver.h +++ b/translation/translation_driver.h @@ -1,51 +1,51 @@ -#ifndef __TRANSLATION_DRIVER__H -#define __TRANSLATION_DRIVER__H - -#include -#include - -#include "ocr_driver.h" - -RETRO_BEGIN_DECLS - -enum translation_init_errors -{ - TRANSLATION_INIT_SUCCESS = 0, - TRANSLATION_INIT_UNSUPPORTED_DEVICE_LANGUAGE, - TRANSLATION_INIT_UNSUPPORTED_GAME_LANGUAGE, - TRANSLATION_INIT_UNKNOWN_DEVICE_LANGUAGE, - TRANSLATION_INIT_UNKNOWN_GAME_LANGUAGE -}; - -struct translation_driver_info -{ - int device_language; - int game_language; -}; - -typedef struct translation_driver -{ - void* (*init)(const struct translation_driver_info *params); - void (*free)(void* data); - - /* use translate_image if non NULL else run image through ocr driver then run translate_text */ - /* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to translate_image/text */ - /* NOTE: translate_image is allowed to call the ocr driver itself if it wants */ - char* (*translate_text)(void* data, const char* game_text); - char* (*translate_image)(void* data, struct ocr_image_info image); - - const char *ident; -} translation_driver_t; - -extern const translation_driver_t translation_cached_google; -extern const translation_driver_t translation_null; - -bool translation_driver_init(void); -void translation_driver_free(void); - -/* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to translation_driver_translate_image */ -char* translation_driver_translate_image(struct ocr_image_info image); - -RETRO_END_DECLS - +#ifndef __TRANSLATION_DRIVER__H +#define __TRANSLATION_DRIVER__H + +#include +#include + +#include "ocr_driver.h" + +RETRO_BEGIN_DECLS + +enum translation_init_errors +{ + TRANSLATION_INIT_SUCCESS = 0, + TRANSLATION_INIT_UNSUPPORTED_DEVICE_LANGUAGE, + TRANSLATION_INIT_UNSUPPORTED_GAME_LANGUAGE, + TRANSLATION_INIT_UNKNOWN_DEVICE_LANGUAGE, + TRANSLATION_INIT_UNKNOWN_GAME_LANGUAGE +}; + +struct translation_driver_info +{ + int device_language; + int game_language; +}; + +typedef struct translation_driver +{ + void* (*init)(const struct translation_driver_info *params); + void (*free)(void* data); + + /* use translate_image if non NULL else run image through ocr driver then run translate_text */ + /* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to translate_image/text */ + /* NOTE: translate_image is allowed to call the ocr driver itself if it wants */ + char* (*translate_text)(void* data, const char* game_text); + char* (*translate_image)(void* data, struct ocr_image_info image); + + const char *ident; +} translation_driver_t; + +extern const translation_driver_t translation_cached_google; +extern const translation_driver_t translation_null; + +bool translation_driver_init(void); +void translation_driver_free(void); + +/* returned char pointers do not need to be freed but are 1 time use, they may be destroyed on the next call to translation_driver_translate_image */ +char* translation_driver_translate_image(struct ocr_image_info image); + +RETRO_END_DECLS + #endif \ No newline at end of file diff --git a/version.dtd b/version.dtd index ea61e030e4..bd0761a8bb 100644 --- a/version.dtd +++ b/version.dtd @@ -1 +1 @@ - +