sokol: update to floooh/sokol from 27-Dec-2021 (4ff3ed7) (#13044)
parent
70a0aab72b
commit
3ae4513e2e
|
@ -252,6 +252,10 @@
|
|||
may help to prevent casting back and forth between int and float
|
||||
in more strongly typed languages than C and C++.
|
||||
|
||||
double sapp_frame_duration(void)
|
||||
Returns the frame duration in seconds averaged over a number of
|
||||
frames to smooth out any jittering spikes.
|
||||
|
||||
int sapp_color_format(void)
|
||||
int sapp_depth_format(void)
|
||||
The color and depth-stencil pixelformats of the default framebuffer,
|
||||
|
@ -411,7 +415,7 @@
|
|||
- SAPP_EVENTTYPE_MOUSE_DOWN
|
||||
- SAPP_EVENTTYPE_MOUSE_UP
|
||||
- SAPP_EVENTTYPE_MOUSE_SCROLL
|
||||
- SAPP_EVENTYTPE_KEY_UP
|
||||
- SAPP_EVENTTYPE_KEY_UP
|
||||
- SAPP_EVENTTYPE_KEY_DOWN
|
||||
- The mouse lock/unlock action on the web platform is asynchronous,
|
||||
this means that sapp_mouse_locked() won't immediately return
|
||||
|
@ -1378,7 +1382,7 @@ typedef struct sapp_desc {
|
|||
bool html5_ask_leave_site; // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site())
|
||||
bool ios_keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the canvas
|
||||
// __v_ start
|
||||
bool __v_native_render; /* V patch to allow for native rendering */
|
||||
bool __v_native_render; // V patch to allow for native rendering
|
||||
// __v_ end
|
||||
} sapp_desc;
|
||||
|
||||
|
@ -1443,7 +1447,7 @@ SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void);
|
|||
/* show or hide the mouse cursor */
|
||||
SOKOL_APP_API_DECL void sapp_show_mouse(bool show);
|
||||
/* show or hide the mouse cursor */
|
||||
SOKOL_APP_API_DECL bool sapp_mouse_shown();
|
||||
SOKOL_APP_API_DECL bool sapp_mouse_shown(void);
|
||||
/* enable/disable mouse-pointer-lock mode */
|
||||
SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock);
|
||||
/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */
|
||||
|
@ -1462,6 +1466,8 @@ SOKOL_APP_API_DECL void sapp_quit(void);
|
|||
SOKOL_APP_API_DECL void sapp_consume_event(void);
|
||||
/* get the current frame counter (for comparison with sapp_event.frame_count) */
|
||||
SOKOL_APP_API_DECL uint64_t sapp_frame_count(void);
|
||||
/* get an averaged/smoothed frame duration in seconds */
|
||||
SOKOL_APP_API_DECL double sapp_frame_duration(void);
|
||||
/* write string into clipboard */
|
||||
SOKOL_APP_API_DECL void sapp_set_clipboard_string(const char* str);
|
||||
/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */
|
||||
|
@ -1685,6 +1691,8 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
|
|||
#import <GLKit/GLKit.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <mach/mach_time.h>
|
||||
#elif defined(_SAPP_EMSCRIPTEN)
|
||||
#if defined(SOKOL_WGPU)
|
||||
#include <webgpu/webgpu.h>
|
||||
|
@ -1774,6 +1782,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
|
|||
#elif defined(_SAPP_ANDROID)
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <android/native_activity.h>
|
||||
#include <android/looper.h>
|
||||
#include <EGL/egl.h>
|
||||
|
@ -1791,8 +1800,209 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
|
|||
#include <dlfcn.h> /* dlopen, dlsym, dlclose */
|
||||
#include <limits.h> /* LONG_MAX */
|
||||
#include <pthread.h> /* only used a linker-guard, search for _sapp_linux_run() and see first comment */
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
/*== frame timing helpers ===================================================*/
|
||||
#define _SAPP_RING_NUM_SLOTS (256)
|
||||
typedef struct {
|
||||
int head;
|
||||
int tail;
|
||||
double buf[_SAPP_RING_NUM_SLOTS];
|
||||
} _sapp_ring_t;
|
||||
|
||||
_SOKOL_PRIVATE int _sapp_ring_idx(int i) {
|
||||
return i % _SAPP_RING_NUM_SLOTS;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_ring_init(_sapp_ring_t* ring) {
|
||||
ring->head = 0;
|
||||
ring->tail = 0;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sapp_ring_full(_sapp_ring_t* ring) {
|
||||
return _sapp_ring_idx(ring->head + 1) == ring->tail;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sapp_ring_empty(_sapp_ring_t* ring) {
|
||||
return ring->head == ring->tail;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE int _sapp_ring_count(_sapp_ring_t* ring) {
|
||||
int count;
|
||||
if (ring->head >= ring->tail) {
|
||||
count = ring->head - ring->tail;
|
||||
}
|
||||
else {
|
||||
count = (ring->head + _SAPP_RING_NUM_SLOTS) - ring->tail;
|
||||
}
|
||||
SOKOL_ASSERT((count >= 0) && (count < _SAPP_RING_NUM_SLOTS));
|
||||
return count;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_ring_enqueue(_sapp_ring_t* ring, double val) {
|
||||
SOKOL_ASSERT(!_sapp_ring_full(ring));
|
||||
ring->buf[ring->head] = val;
|
||||
ring->head = _sapp_ring_idx(ring->head + 1);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE double _sapp_ring_dequeue(_sapp_ring_t* ring) {
|
||||
SOKOL_ASSERT(!_sapp_ring_empty(ring));
|
||||
double val = ring->buf[ring->tail];
|
||||
ring->tail = _sapp_ring_idx(ring->tail + 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
|
||||
Q: Why not use CAMetalDrawable.presentedTime on macOS and iOS?
|
||||
A: The value appears to be highly unstable during the first few
|
||||
seconds, sometimes several frames are dropped in sequence, or
|
||||
switch between 120 and 60 Hz for a few frames. Simply measuring
|
||||
and averaging the frame time yielded a more stable frame duration.
|
||||
Maybe switching to CVDisplayLink would yield better results.
|
||||
Until then just measure the time.
|
||||
*/
|
||||
typedef struct {
|
||||
#if defined(_SAPP_APPLE)
|
||||
struct {
|
||||
mach_timebase_info_data_t timebase;
|
||||
uint64_t start;
|
||||
} mach;
|
||||
#elif defined(_SAPP_EMSCRIPTEN)
|
||||
// empty
|
||||
#elif defined(_SAPP_WIN32) || defined(_SAPP_UWP)
|
||||
struct {
|
||||
LARGE_INTEGER freq;
|
||||
LARGE_INTEGER start;
|
||||
} win;
|
||||
#else // Linux, Android, ...
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
#define _SAPP_CLOCK_MONOTONIC CLOCK_MONOTONIC
|
||||
#else
|
||||
// on some embedded platforms, CLOCK_MONOTONIC isn't defined
|
||||
#define _SAPP_CLOCK_MONOTONIC (1)
|
||||
#endif
|
||||
struct {
|
||||
uint64_t start;
|
||||
} posix;
|
||||
#endif
|
||||
} _sapp_timestamp_t;
|
||||
|
||||
_SOKOL_PRIVATE int64_t _sapp_int64_muldiv(int64_t value, int64_t numer, int64_t denom) {
|
||||
int64_t q = value / denom;
|
||||
int64_t r = value % denom;
|
||||
return q * numer + r * numer / denom;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_timestamp_init(_sapp_timestamp_t* ts) {
|
||||
#if defined(_SAPP_APPLE)
|
||||
mach_timebase_info(&ts->mach.timebase);
|
||||
ts->mach.start = mach_absolute_time();
|
||||
#elif defined(_SAPP_EMSCRIPTEN)
|
||||
(void)ts;
|
||||
#elif defined(_SAPP_WIN32) || defined(_SAPP_UWP)
|
||||
QueryPerformanceFrequency(&ts->win.freq);
|
||||
QueryPerformanceCounter(&ts->win.start);
|
||||
#else
|
||||
struct timespec tspec;
|
||||
clock_gettime(_SAPP_CLOCK_MONOTONIC, &tspec);
|
||||
ts->posix.start = (uint64_t)tspec.tv_sec*1000000000 + (uint64_t)tspec.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE double _sapp_timestamp_now(_sapp_timestamp_t* ts) {
|
||||
#if defined(_SAPP_APPLE)
|
||||
const uint64_t traw = mach_absolute_time() - ts->mach.start;
|
||||
const uint64_t now = (uint64_t) _sapp_int64_muldiv((int64_t)traw, (int64_t)ts->mach.timebase.numer, (int64_t)ts->mach.timebase.denom);
|
||||
return (double)now / 1000000000.0;
|
||||
#elif defined(_SAPP_EMSCRIPTEN)
|
||||
(void)ts;
|
||||
SOKOL_ASSERT(false);
|
||||
return 0.0;
|
||||
#elif defined(_SAPP_WIN32) || defined(_SAPP_UWP)
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceCounter(&qpc);
|
||||
const uint64_t now = (uint64_t)_sapp_int64_muldiv(qpc.QuadPart - ts->win.start.QuadPart, 1000000000, ts->win.freq.QuadPart);
|
||||
return (double)now / 1000000000.0;
|
||||
#else
|
||||
struct timespec tspec;
|
||||
clock_gettime(_SAPP_CLOCK_MONOTONIC, &tspec);
|
||||
const uint64_t now = ((uint64_t)tspec.tv_sec*1000000000 + (uint64_t)tspec.tv_nsec) - ts->posix.start;
|
||||
return (double)now / 1000000000.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
double last;
|
||||
double accum;
|
||||
double avg;
|
||||
int num;
|
||||
_sapp_timestamp_t timestamp;
|
||||
_sapp_ring_t ring;
|
||||
} _sapp_timing_t;
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_timing_init(_sapp_timing_t* t) {
|
||||
t->last = 0.0;
|
||||
t->accum = 0.0;
|
||||
// dummy value until first actual value is available
|
||||
t->avg = 1.0 / 60.0;
|
||||
t->num = 0;
|
||||
_sapp_timestamp_init(&t->timestamp);
|
||||
_sapp_ring_init(&t->ring);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_timing_put(_sapp_timing_t* t, double dur) {
|
||||
// arbitrary upper limit to ignore outliers (e.g. during window resizing, or debugging)
|
||||
double min_dur = 0.0;
|
||||
double max_dur = 0.1;
|
||||
// if we have enough samples for a useful average, use a much tighter 'valid window'
|
||||
if (_sapp_ring_full(&t->ring)) {
|
||||
min_dur = t->avg * 0.8;
|
||||
max_dur = t->avg * 1.2;
|
||||
}
|
||||
if ((dur < min_dur) || (dur > max_dur)) {
|
||||
return;
|
||||
}
|
||||
if (_sapp_ring_full(&t->ring)) {
|
||||
double old_val = _sapp_ring_dequeue(&t->ring);
|
||||
t->accum -= old_val;
|
||||
t->num -= 1;
|
||||
}
|
||||
_sapp_ring_enqueue(&t->ring, dur);
|
||||
t->accum += dur;
|
||||
t->num += 1;
|
||||
SOKOL_ASSERT(t->num > 0);
|
||||
t->avg = t->accum / t->num;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_timing_measure(_sapp_timing_t* t) {
|
||||
const double now = _sapp_timestamp_now(&t->timestamp);
|
||||
if (t->last > 0.0) {
|
||||
double dur = now - t->last;
|
||||
_sapp_timing_put(t, dur);
|
||||
}
|
||||
t->last = now;
|
||||
}
|
||||
|
||||
// call this if the external timing had been disrupted somehow
|
||||
_SOKOL_PRIVATE void _sapp_timing_external_reset(_sapp_timing_t* t) {
|
||||
t->last = 0.0;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_timing_external(_sapp_timing_t* t, double now) {
|
||||
if (t->last > 0.0) {
|
||||
double dur = now - t->last;
|
||||
_sapp_timing_put(t, dur);
|
||||
}
|
||||
t->last = now;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE double _sapp_timing_get_avg(_sapp_timing_t* t) {
|
||||
return t->avg;
|
||||
}
|
||||
|
||||
/*== MACOS DECLARATIONS ======================================================*/
|
||||
#if defined(_SAPP_MACOS)
|
||||
// __v_ start
|
||||
|
@ -1830,9 +2040,8 @@ typedef struct {
|
|||
uint32_t flags_changed_store;
|
||||
uint8_t mouse_buttons;
|
||||
// __v_ start
|
||||
// NSWindow* window;
|
||||
// SokolWindow* window; // __v_
|
||||
_sapp_macos_window* window; // __v_
|
||||
//NSWindow* window; // __v_ removed
|
||||
_sapp_macos_window* window; // __v_ added
|
||||
// __v_ end
|
||||
NSTrackingArea* tracking_area;
|
||||
_sapp_macos_app_delegate* app_dlg;
|
||||
|
@ -1922,6 +2131,7 @@ typedef struct {
|
|||
ID3D11DepthStencilView* dsv;
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
|
||||
IDXGISwapChain* swap_chain;
|
||||
UINT sync_refresh_count;
|
||||
} _sapp_d3d11_t;
|
||||
#endif
|
||||
|
||||
|
@ -2300,6 +2510,7 @@ typedef struct {
|
|||
int swap_interval;
|
||||
float dpi_scale;
|
||||
uint64_t frame_count;
|
||||
_sapp_timing_t timing;
|
||||
sapp_event event;
|
||||
_sapp_mouse_t mouse;
|
||||
_sapp_clipboard_t clipboard;
|
||||
|
@ -2334,7 +2545,6 @@ typedef struct {
|
|||
char window_title[_SAPP_MAX_TITLE_LENGTH]; /* UTF-8 */
|
||||
wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */
|
||||
sapp_keycode keycodes[SAPP_MAX_KEYCODES];
|
||||
|
||||
// __v_ start
|
||||
bool __v_native_render; /* V patch to allow for native rendering */
|
||||
// __v_ end
|
||||
|
@ -2409,7 +2619,6 @@ _SOKOL_PRIVATE void _sapp_call_cleanup(void) {
|
|||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) {
|
||||
//puts("_sapp_call_event start");
|
||||
if (!_sapp.cleanup_called) {
|
||||
if (_sapp.desc.event_cb) {
|
||||
_sapp.desc.event_cb(e);
|
||||
|
@ -2418,7 +2627,6 @@ _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) {
|
|||
_sapp.desc.event_userdata_cb(e, _sapp.desc.user_data);
|
||||
}
|
||||
}
|
||||
//puts("_sapp_call_event end");
|
||||
if (_sapp.event_consumed) {
|
||||
_sapp.event_consumed = false;
|
||||
return true;
|
||||
|
@ -2481,6 +2689,14 @@ _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) {
|
|||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) {
|
||||
SOKOL_ASSERT(desc);
|
||||
SOKOL_ASSERT(desc->width >= 0);
|
||||
SOKOL_ASSERT(desc->height >= 0);
|
||||
SOKOL_ASSERT(desc->sample_count >= 0);
|
||||
SOKOL_ASSERT(desc->swap_interval >= 0);
|
||||
SOKOL_ASSERT(desc->clipboard_size >= 0);
|
||||
SOKOL_ASSERT(desc->max_dropped_files >= 0);
|
||||
SOKOL_ASSERT(desc->max_dropped_file_path_length >= 0);
|
||||
_SAPP_CLEAR(_sapp_t, _sapp);
|
||||
_sapp.desc = _sapp_desc_defaults(desc);
|
||||
_sapp.first_frame = true;
|
||||
|
@ -2511,6 +2727,7 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) {
|
|||
_sapp.dpi_scale = 1.0f;
|
||||
_sapp.fullscreen = _sapp.desc.fullscreen;
|
||||
_sapp.mouse.shown = true;
|
||||
_sapp_timing_init(&_sapp.timing);
|
||||
// __v_ start
|
||||
_sapp.__v_native_render = _sapp.desc.__v_native_render;
|
||||
// __v_end
|
||||
|
@ -3034,14 +3251,6 @@ _SOKOL_PRIVATE void _sapp_macos_update_window_title(void) {
|
|||
[_sapp.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window_title]];
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_macos_resize_window(int width, height) {
|
||||
[_sapp.macos.window setFrame:NSMakeRect(width, height, width, height) display:YES animate:YES];
|
||||
//NSRect frame = [window frame];
|
||||
//frame.size = ;
|
||||
//[window setFrame: frame display: YES animate: NO];
|
||||
}
|
||||
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_macos_update_mouse(NSEvent* event) {
|
||||
if (!_sapp.mouse.locked) {
|
||||
const NSPoint mouse_pos = event.locationInWindow;
|
||||
|
@ -3175,39 +3384,19 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
|
|||
_sapp.macos.window.acceptsMouseMovedEvents = YES;
|
||||
_sapp.macos.window.restorable = YES;
|
||||
|
||||
// _v__ start
|
||||
_sapp.macos.window.backgroundColor = [NSColor whiteColor];
|
||||
|
||||
// Quit menu
|
||||
NSMenu* menu_bar = [[NSMenu alloc] init];
|
||||
NSMenuItem* app_menu_item = [[NSMenuItem alloc] init];
|
||||
[menu_bar addItem:app_menu_item];
|
||||
NSApp.mainMenu = menu_bar;
|
||||
NSMenu* app_menu = [[NSMenu alloc] init];
|
||||
NSString* window_title_as_nsstring = [NSString stringWithUTF8String:_sapp.window_title];
|
||||
// `quit_title` memory will be owned by the NSMenuItem, so no need to release it ourselves
|
||||
NSString* quit_title = [@"Quit " stringByAppendingString:window_title_as_nsstring];
|
||||
NSMenuItem* quit_menu_item = [[NSMenuItem alloc]
|
||||
initWithTitle:quit_title
|
||||
action:@selector(terminate:)
|
||||
keyEquivalent:@"q"];
|
||||
[app_menu addItem:quit_menu_item];
|
||||
app_menu_item.submenu = app_menu;
|
||||
_SAPP_OBJC_RELEASE( window_title_as_nsstring );
|
||||
_SAPP_OBJC_RELEASE( app_menu );
|
||||
_SAPP_OBJC_RELEASE( app_menu_item );
|
||||
_SAPP_OBJC_RELEASE( menu_bar );
|
||||
|
||||
|
||||
// _v__ end
|
||||
|
||||
_sapp.macos.win_dlg = [[_sapp_macos_window_delegate alloc] init];
|
||||
_sapp.macos.window.delegate = _sapp.macos.win_dlg;
|
||||
#if defined(SOKOL_METAL)
|
||||
NSInteger max_fps = 60;
|
||||
#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 120000)
|
||||
if (@available(macOS 12.0, *)) {
|
||||
max_fps = NSScreen.mainScreen.maximumFramesPerSecond;
|
||||
}
|
||||
#endif
|
||||
_sapp.macos.mtl_device = MTLCreateSystemDefaultDevice();
|
||||
_sapp.macos.view = [[_sapp_macos_view alloc] init];
|
||||
[_sapp.macos.view updateTrackingAreas];
|
||||
_sapp.macos.view.preferredFramesPerSecond = 60 / _sapp.swap_interval;
|
||||
_sapp.macos.view.preferredFramesPerSecond = max_fps / _sapp.swap_interval;
|
||||
_sapp.macos.view.device = _sapp.macos.mtl_device;
|
||||
_sapp.macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
_sapp.macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
|
@ -3300,14 +3489,11 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
|
|||
[ contentView addSubview:g_view];
|
||||
//[ _sapp.macos.window addChildWindow:overlayWindow ordered:NSWindowAbove];
|
||||
[_sapp.macos.window center];
|
||||
|
||||
}
|
||||
//////////////////////////////////
|
||||
// __v_ end
|
||||
|
||||
[_sapp.macos.window makeKeyAndOrderFront:nil];
|
||||
_sapp_macos_update_dimensions();
|
||||
|
||||
// __v_ start
|
||||
// [NSEvent setMouseCoalescingEnabled:NO];
|
||||
// __v_ end
|
||||
|
@ -3520,6 +3706,7 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() {
|
|||
|
||||
- (void)drawRect:(NSRect)rect {
|
||||
_SOKOL_UNUSED(rect);
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
/* Catch any last-moment input events */
|
||||
_sapp_macos_poll_input_events();
|
||||
@autoreleasepool {
|
||||
|
@ -3656,8 +3843,6 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() {
|
|||
}
|
||||
}
|
||||
- (void)keyDown:(NSEvent*)event {
|
||||
//puts("-keyDown()");
|
||||
//NSLog(@"%@", event);
|
||||
if (_sapp_events_enabled()) {
|
||||
const uint32_t mods = _sapp_macos_mods(event);
|
||||
/* NOTE: macOS doesn't send keyUp events while the Cmd key is pressed,
|
||||
|
@ -3881,10 +4066,11 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
|
|||
}
|
||||
_sapp.framebuffer_width = _sapp.window_width * _sapp.dpi_scale;
|
||||
_sapp.framebuffer_height = _sapp.window_height * _sapp.dpi_scale;
|
||||
NSInteger max_fps = UIScreen.mainScreen.maximumFramesPerSecond;
|
||||
#if defined(SOKOL_METAL)
|
||||
_sapp.ios.mtl_device = MTLCreateSystemDefaultDevice();
|
||||
_sapp.ios.view = [[_sapp_ios_view alloc] init];
|
||||
_sapp.ios.view.preferredFramesPerSecond = 60 / _sapp.swap_interval;
|
||||
_sapp.ios.view.preferredFramesPerSecond = max_fps / _sapp.swap_interval;
|
||||
_sapp.ios.view.device = _sapp.ios.mtl_device;
|
||||
_sapp.ios.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
_sapp.ios.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
|
@ -3924,14 +4110,14 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
|
|||
_sapp.ios.view.multipleTouchEnabled = YES;
|
||||
// on GLKView, contentScaleFactor appears to work just fine!
|
||||
if (_sapp.desc.high_dpi) {
|
||||
_sapp.ios.view.contentScaleFactor = 2.0;
|
||||
_sapp.ios.view.contentScaleFactor = _sapp.dpi_scale;
|
||||
}
|
||||
else {
|
||||
_sapp.ios.view.contentScaleFactor = 1.0;
|
||||
}
|
||||
_sapp.ios.view_ctrl = [[GLKViewController alloc] init];
|
||||
_sapp.ios.view_ctrl.view = _sapp.ios.view;
|
||||
_sapp.ios.view_ctrl.preferredFramesPerSecond = 60 / _sapp.swap_interval;
|
||||
_sapp.ios.view_ctrl.preferredFramesPerSecond = max_fps / _sapp.swap_interval;
|
||||
_sapp.ios.window.rootViewController = _sapp.ios.view_ctrl;
|
||||
#endif
|
||||
[_sapp.ios.window makeKeyAndVisible];
|
||||
|
@ -4043,6 +4229,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
|
|||
@implementation _sapp_ios_view
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
_SOKOL_UNUSED(rect);
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
@autoreleasepool {
|
||||
_sapp_ios_frame();
|
||||
}
|
||||
|
@ -5172,8 +5359,8 @@ _SOKOL_PRIVATE void _sapp_emsc_unregister_eventhandlers() {
|
|||
}
|
||||
|
||||
_SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) {
|
||||
_SOKOL_UNUSED(time);
|
||||
_SOKOL_UNUSED(userData);
|
||||
_sapp_timing_external(&_sapp.timing, time / 1000.0);
|
||||
|
||||
#if defined(SOKOL_WGPU)
|
||||
/*
|
||||
|
@ -5591,6 +5778,14 @@ static inline HRESULT _sapp_dxgi_Present(IDXGISwapChain* self, UINT SyncInterval
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline HRESULT _sapp_dxgi_GetFrameStatistics(IDXGISwapChain* self, DXGI_FRAME_STATISTICS* pStats) {
|
||||
#if defined(__cplusplus)
|
||||
return self->GetFrameStatistics(pStats);
|
||||
#else
|
||||
return self->lpVtbl->GetFrameStatistics(self, pStats);
|
||||
#endif
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) {
|
||||
DXGI_SWAP_CHAIN_DESC* sc_desc = &_sapp.d3d11.swap_chain_desc;
|
||||
sc_desc->BufferDesc.Width = (UINT)_sapp.framebuffer_width;
|
||||
|
@ -6234,6 +6429,33 @@ _SOKOL_PRIVATE void _sapp_win32_files_dropped(HDROP hdrop) {
|
|||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sapp_win32_timing_measure(void) {
|
||||
#if defined(SOKOL_D3D11)
|
||||
// on D3D11, use the more precise DXGI timestamp
|
||||
DXGI_FRAME_STATISTICS dxgi_stats;
|
||||
_SAPP_CLEAR(DXGI_FRAME_STATISTICS, dxgi_stats);
|
||||
HRESULT hr = _sapp_dxgi_GetFrameStatistics(_sapp.d3d11.swap_chain, &dxgi_stats);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (dxgi_stats.SyncRefreshCount != _sapp.d3d11.sync_refresh_count) {
|
||||
if ((_sapp.d3d11.sync_refresh_count + 1) != dxgi_stats.SyncRefreshCount) {
|
||||
_sapp_timing_external_reset(&_sapp.timing);
|
||||
}
|
||||
_sapp.d3d11.sync_refresh_count = dxgi_stats.SyncRefreshCount;
|
||||
LARGE_INTEGER qpc = dxgi_stats.SyncQPCTime;
|
||||
const uint64_t now = (uint64_t)_sapp_int64_muldiv(qpc.QuadPart - _sapp.timing.timestamp.win.start.QuadPart, 1000000000, _sapp.timing.timestamp.win.freq.QuadPart);
|
||||
_sapp_timing_external(&_sapp.timing, (double)now / 1000000000.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// fallback if GetFrameStats doesn't work for some reason
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
}
|
||||
#endif
|
||||
#if defined(SOKOL_GLCORE33)
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
#endif
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (!_sapp.win32.in_create_window) {
|
||||
switch (uMsg) {
|
||||
|
@ -6417,6 +6639,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM
|
|||
KillTimer(_sapp.win32.hwnd, 1);
|
||||
break;
|
||||
case WM_TIMER:
|
||||
_sapp_win32_timing_measure();
|
||||
_sapp_frame();
|
||||
#if defined(SOKOL_D3D11)
|
||||
_sapp_d3d11_present();
|
||||
|
@ -6789,6 +7012,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) {
|
|||
|
||||
bool done = false;
|
||||
while (!(done || _sapp.quit_ordered)) {
|
||||
_sapp_win32_timing_measure();
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (WM_QUIT == msg.message) {
|
||||
|
@ -7729,6 +7953,7 @@ void App::Run() {
|
|||
// NOTE: UWP will simply terminate an application, it's not possible to detect when an application is being closed
|
||||
while (true) {
|
||||
if (m_windowVisible) {
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(winrt::Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
|
||||
_sapp_frame();
|
||||
m_deviceResources->Present();
|
||||
|
@ -8108,6 +8333,7 @@ _SOKOL_PRIVATE void _sapp_android_frame(void) {
|
|||
SOKOL_ASSERT(_sapp.android.display != EGL_NO_DISPLAY);
|
||||
SOKOL_ASSERT(_sapp.android.context != EGL_NO_CONTEXT);
|
||||
SOKOL_ASSERT(_sapp.android.surface != EGL_NO_SURFACE);
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
_sapp_android_update_dimensions(_sapp.android.current.window, false);
|
||||
_sapp_frame();
|
||||
eglSwapBuffers(_sapp.android.display, _sapp.android.surface);
|
||||
|
@ -10718,6 +10944,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
|
|||
_sapp_glx_swapinterval(_sapp.swap_interval);
|
||||
XFlush(_sapp.x11.display);
|
||||
while (!_sapp.quit_ordered) {
|
||||
_sapp_timing_measure(&_sapp.timing);
|
||||
_sapp_glx_make_current();
|
||||
int count = XPending(_sapp.x11.display);
|
||||
while (count--) {
|
||||
|
@ -10807,6 +11034,10 @@ SOKOL_API_IMPL uint64_t sapp_frame_count(void) {
|
|||
return _sapp.frame_count;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL double sapp_frame_duration(void) {
|
||||
return _sapp_timing_get_avg(&_sapp.timing);
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int sapp_width(void) {
|
||||
return (_sapp.framebuffer_width > 0) ? _sapp.framebuffer_width : 1;
|
||||
}
|
||||
|
@ -10995,19 +11226,6 @@ SOKOL_API_IMPL void sapp_set_window_title(const char* title) {
|
|||
#endif
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sapp_resize_window(int width, int height) {
|
||||
/*
|
||||
#if defined(_SAPP_MACOS)
|
||||
_sapp_macos_resize_window(width, height);
|
||||
#elif defined(_SAPP_WIN32)
|
||||
_sapp_win32_resize_window();
|
||||
#elif defined(_SAPP_LINUX)
|
||||
_sapp_x11_resize_window();
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) {
|
||||
SOKOL_ASSERT(desc);
|
||||
if (desc->sokol_default) {
|
||||
|
|
|
@ -439,6 +439,8 @@ SOKOL_AUDIO_API_DECL int saudio_sample_rate(void);
|
|||
SOKOL_AUDIO_API_DECL int saudio_buffer_frames(void);
|
||||
/* actual number of channels */
|
||||
SOKOL_AUDIO_API_DECL int saudio_channels(void);
|
||||
/* return true if audio context is currently suspended (only in WebAudio backend, all other backends return false) */
|
||||
SOKOL_AUDIO_API_DECL bool saudio_suspended(void);
|
||||
/* get current number of frames to fill packet queue */
|
||||
SOKOL_AUDIO_API_DECL int saudio_expect(void);
|
||||
/* push sample frames from main thread, returns number of frames actually pushed */
|
||||
|
@ -562,6 +564,7 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|||
static const IID _saudio_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483, {0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2} };
|
||||
static const IID _saudio_IID_Devinterface_Audio_Render = { 0xe6327cad, 0xdcec, 0x4949, {0xae, 0x8a, 0x99, 0x1e, 0x97, 0x6a, 0x79, 0xd2} };
|
||||
static const IID _saudio_IID_IActivateAudioInterface_Completion_Handler = { 0x94ea2b94, 0xe9cc, 0x49e0, {0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90} };
|
||||
static const GUID _saudio_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} };
|
||||
#if defined(__cplusplus)
|
||||
#define _SOKOL_AUDIO_WIN32COM_ID(x) (x)
|
||||
#else
|
||||
|
@ -821,7 +824,6 @@ typedef struct {
|
|||
#endif
|
||||
IAudioClient* audio_client;
|
||||
IAudioRenderClient* render_client;
|
||||
int si16_bytes_per_frame;
|
||||
_saudio_wasapi_thread_data_t thread;
|
||||
} _saudio_backend_t;
|
||||
|
||||
|
@ -1422,6 +1424,10 @@ _SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) {
|
|||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE int _saudio_wasapi_min(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _saudio_wasapi_submit_buffer(int num_frames) {
|
||||
BYTE* wasapi_buffer = 0;
|
||||
if (FAILED(IAudioRenderClient_GetBuffer(_saudio.backend.render_client, num_frames, &wasapi_buffer))) {
|
||||
|
@ -1429,24 +1435,34 @@ _SOKOL_PRIVATE void _saudio_wasapi_submit_buffer(int num_frames) {
|
|||
}
|
||||
SOKOL_ASSERT(wasapi_buffer);
|
||||
|
||||
/* convert float samples to int16_t, refill float buffer if needed */
|
||||
const int num_samples = num_frames * _saudio.num_channels;
|
||||
int16_t* dst = (int16_t*) wasapi_buffer;
|
||||
/* copy samples to WASAPI buffer, refill source buffer if needed */
|
||||
int num_remaining_samples = num_frames * _saudio.num_channels;
|
||||
int buffer_pos = _saudio.backend.thread.src_buffer_pos;
|
||||
const int buffer_float_size = _saudio.backend.thread.src_buffer_byte_size / (int)sizeof(float);
|
||||
float* src = _saudio.backend.thread.src_buffer;
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
const int buffer_size_in_samples = _saudio.backend.thread.src_buffer_byte_size / (int)sizeof(float);
|
||||
float* dst = (float*)wasapi_buffer;
|
||||
const float* dst_end = dst + num_remaining_samples;
|
||||
_SOKOL_UNUSED(dst_end); // suppress unused warning in release mode
|
||||
const float* src = _saudio.backend.thread.src_buffer;
|
||||
|
||||
while (num_remaining_samples > 0) {
|
||||
if (0 == buffer_pos) {
|
||||
_saudio_wasapi_fill_buffer();
|
||||
}
|
||||
dst[i] = (int16_t) (src[buffer_pos] * 0x7FFF);
|
||||
buffer_pos += 1;
|
||||
if (buffer_pos == buffer_float_size) {
|
||||
const int samples_to_copy = _saudio_wasapi_min(num_remaining_samples, buffer_size_in_samples - buffer_pos);
|
||||
SOKOL_ASSERT((buffer_pos + samples_to_copy) <= buffer_size_in_samples);
|
||||
SOKOL_ASSERT((dst + samples_to_copy) <= dst_end);
|
||||
memcpy(dst, &src[buffer_pos], (size_t)samples_to_copy * sizeof(float));
|
||||
num_remaining_samples -= samples_to_copy;
|
||||
SOKOL_ASSERT(num_remaining_samples >= 0);
|
||||
buffer_pos += samples_to_copy;
|
||||
dst += samples_to_copy;
|
||||
|
||||
SOKOL_ASSERT(buffer_pos <= buffer_size_in_samples);
|
||||
if (buffer_pos == buffer_size_in_samples) {
|
||||
buffer_pos = 0;
|
||||
}
|
||||
}
|
||||
_saudio.backend.thread.src_buffer_pos = buffer_pos;
|
||||
|
||||
IAudioRenderClient_ReleaseBuffer(_saudio.backend.render_client, num_frames, 0);
|
||||
}
|
||||
|
||||
|
@ -1584,20 +1600,25 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||
goto error;
|
||||
}
|
||||
#endif
|
||||
WAVEFORMATEX fmt;
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
fmt.nChannels = (WORD)_saudio.num_channels;
|
||||
fmt.nSamplesPerSec = (DWORD)_saudio.sample_rate;
|
||||
fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
fmt.wBitsPerSample = 16;
|
||||
fmt.nBlockAlign = (fmt.nChannels * fmt.wBitsPerSample) / 8;
|
||||
fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
|
||||
|
||||
WAVEFORMATEXTENSIBLE fmtex;
|
||||
memset(&fmtex, 0, sizeof(fmtex));
|
||||
fmtex.Format.nChannels = (WORD)_saudio.num_channels;
|
||||
fmtex.Format.nSamplesPerSec = (DWORD)_saudio.sample_rate;
|
||||
fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
fmtex.Format.wBitsPerSample = 32;
|
||||
fmtex.Format.nBlockAlign = (fmtex.Format.nChannels * fmtex.Format.wBitsPerSample) / 8;
|
||||
fmtex.Format.nAvgBytesPerSec = fmtex.Format.nSamplesPerSec * fmtex.Format.nBlockAlign;
|
||||
fmtex.Format.cbSize = 22; /* WORD + DWORD + GUID */
|
||||
fmtex.Samples.wValidBitsPerSample = 32;
|
||||
fmtex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
fmtex.SubFormat = _saudio_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
dur = (REFERENCE_TIME)
|
||||
(((double)_saudio.buffer_frames) / (((double)_saudio.sample_rate) * (1.0/10000000.0)));
|
||||
if (FAILED(IAudioClient_Initialize(_saudio.backend.audio_client,
|
||||
AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK|AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
|
||||
dur, 0, &fmt, 0)))
|
||||
dur, 0, (WAVEFORMATEX*)&fmtex, 0)))
|
||||
{
|
||||
SOKOL_LOG("sokol_audio wasapi: audio client initialize failed");
|
||||
goto error;
|
||||
|
@ -1617,7 +1638,6 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||
SOKOL_LOG("sokol_audio wasapi: audio client SetEventHandle failed");
|
||||
goto error;
|
||||
}
|
||||
_saudio.backend.si16_bytes_per_frame = _saudio.num_channels * (int)sizeof(int16_t);
|
||||
_saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
|
||||
_saudio.backend.thread.src_buffer_frames = _saudio.buffer_frames;
|
||||
_saudio.backend.thread.src_buffer_byte_size = _saudio.backend.thread.src_buffer_frames * _saudio.bytes_per_frame;
|
||||
|
@ -1776,6 +1796,18 @@ EM_JS(int, saudio_js_buffer_frames, (void), {
|
|||
}
|
||||
});
|
||||
|
||||
/* return 1 if the WebAudio context is currently suspended, else 0 */
|
||||
EM_JS(int, saudio_js_suspended, (void), {
|
||||
if (Module._saudio_context) {
|
||||
if (Module._saudio_context.state === 'suspended') {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
if (saudio_js_init(_saudio.sample_rate, _saudio.num_channels, _saudio.buffer_frames)) {
|
||||
_saudio.bytes_per_frame = (int)sizeof(float) * _saudio.num_channels;
|
||||
|
@ -2113,6 +2145,19 @@ SOKOL_API_IMPL int saudio_channels(void) {
|
|||
return _saudio.num_channels;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL bool saudio_suspended(void) {
|
||||
#if defined(_SAUDIO_EMSCRIPTEN)
|
||||
if (_saudio.valid) {
|
||||
return 1 == saudio_js_suspended();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int saudio_expect(void) {
|
||||
if (_saudio.valid) {
|
||||
const int num_frames = _saudio_fifo_writable_bytes(&_saudio.fifo) / _saudio.bytes_per_frame;
|
||||
|
|
|
@ -2976,10 +2976,10 @@ typedef struct {
|
|||
/* helper macros */
|
||||
#define _sg_def(val, def) (((val) == 0) ? (def) : (val))
|
||||
#define _sg_def_flt(val, def) (((val) == 0.0f) ? (def) : (val))
|
||||
#define _sg_min(a,b) ((a<b)?a:b)
|
||||
#define _sg_max(a,b) ((a>b)?a:b)
|
||||
#define _sg_clamp(v,v0,v1) ((v<v0)?(v0):((v>v1)?(v1):(v)))
|
||||
#define _sg_fequal(val,cmp,delta) (((val-cmp)> -delta)&&((val-cmp)<delta))
|
||||
#define _sg_min(a,b) (((a)<(b))?(a):(b))
|
||||
#define _sg_max(a,b) (((a)>(b))?(a):(b))
|
||||
#define _sg_clamp(v,v0,v1) (((v)<(v0))?(v0):(((v)>(v1))?(v1):(v)))
|
||||
#define _sg_fequal(val,cmp,delta) ((((val)-(cmp))> -(delta))&&(((val)-(cmp))<(delta)))
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
|
@ -3098,6 +3098,7 @@ _SOKOL_PRIVATE void _sg_shader_common_init(_sg_shader_common_t* cmn, const sg_sh
|
|||
typedef struct {
|
||||
sg_shader shader_id;
|
||||
sg_index_type index_type;
|
||||
bool use_instanced_draw;
|
||||
bool vertex_layout_valid[SG_MAX_SHADERSTAGE_BUFFERS];
|
||||
int color_attachment_count;
|
||||
sg_pixel_format color_formats[SG_MAX_COLOR_ATTACHMENTS];
|
||||
|
@ -3113,6 +3114,7 @@ _SOKOL_PRIVATE void _sg_pipeline_common_init(_sg_pipeline_common_t* cmn, const s
|
|||
SOKOL_ASSERT((desc->color_count >= 1) && (desc->color_count <= SG_MAX_COLOR_ATTACHMENTS));
|
||||
cmn->shader_id = desc->shader;
|
||||
cmn->index_type = desc->index_type;
|
||||
cmn->use_instanced_draw = false;
|
||||
for (int i = 0; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) {
|
||||
cmn->vertex_layout_valid[i] = false;
|
||||
}
|
||||
|
@ -3584,6 +3586,7 @@ typedef struct {
|
|||
void* user_data;
|
||||
bool in_pass;
|
||||
bool use_indexed_draw;
|
||||
bool use_instanced_draw;
|
||||
int cur_width;
|
||||
int cur_height;
|
||||
int num_rtvs;
|
||||
|
@ -3912,6 +3915,10 @@ typedef enum {
|
|||
_SG_VALIDATE_BUFFERDESC_DATA_SIZE,
|
||||
_SG_VALIDATE_BUFFERDESC_NO_DATA,
|
||||
|
||||
/* image data (for image creation and updating) */
|
||||
_SG_VALIDATE_IMAGEDATA_NODATA,
|
||||
_SG_VALIDATE_IMAGEDATA_DATA_SIZE,
|
||||
|
||||
/* image creation */
|
||||
_SG_VALIDATE_IMAGEDESC_CANARY,
|
||||
_SG_VALIDATE_IMAGEDESC_WIDTH,
|
||||
|
@ -3922,8 +3929,9 @@ typedef enum {
|
|||
_SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT,
|
||||
_SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE,
|
||||
_SG_VALIDATE_IMAGEDESC_RT_NO_DATA,
|
||||
_SG_VALIDATE_IMAGEDESC_DATA,
|
||||
_SG_VALIDATE_IMAGEDESC_NO_DATA,
|
||||
_SG_VALIDATE_IMAGEDESC_INJECTED_NO_DATA,
|
||||
_SG_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA,
|
||||
_SG_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE,
|
||||
|
||||
/* shader creation */
|
||||
_SG_VALIDATE_SHADERDESC_CANARY,
|
||||
|
@ -4019,8 +4027,6 @@ typedef enum {
|
|||
/* sg_update_image validation */
|
||||
_SG_VALIDATE_UPDIMG_USAGE,
|
||||
_SG_VALIDATE_UPDIMG_NOTENOUGHDATA,
|
||||
_SG_VALIDATE_UPDIMG_SIZE,
|
||||
_SG_VALIDATE_UPDIMG_COMPRESSED,
|
||||
_SG_VALIDATE_UPDIMG_ONCE
|
||||
} _sg_validate_error_t;
|
||||
|
||||
|
@ -4234,7 +4240,21 @@ _SOKOL_PRIVATE int _sg_roundup(int val, int round_to) {
|
|||
}
|
||||
|
||||
/* return row pitch for an image
|
||||
|
||||
see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp
|
||||
|
||||
For the special PVRTC pitch computation, see:
|
||||
GL extension requirement (https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt)
|
||||
|
||||
Quote:
|
||||
|
||||
6) How is the imageSize argument calculated for the CompressedTexImage2D
|
||||
and CompressedTexSubImage2D functions.
|
||||
|
||||
Resolution: For PVRTC 4BPP formats the imageSize is calculated as:
|
||||
( max(width, 8) * max(height, 8) * 4 + 7) / 8
|
||||
For PVRTC 2BPP formats the imageSize is calculated as:
|
||||
( max(width, 16) * max(height, 8) * 2 + 7) / 8
|
||||
*/
|
||||
_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) {
|
||||
int pitch;
|
||||
|
@ -4262,23 +4282,11 @@ _SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align)
|
|||
break;
|
||||
case SG_PIXELFORMAT_PVRTC_RGB_4BPP:
|
||||
case SG_PIXELFORMAT_PVRTC_RGBA_4BPP:
|
||||
{
|
||||
const int block_size = 4*4;
|
||||
const int bpp = 4;
|
||||
int width_blocks = width / 4;
|
||||
width_blocks = width_blocks < 2 ? 2 : width_blocks;
|
||||
pitch = width_blocks * ((block_size * bpp) / 8);
|
||||
}
|
||||
pitch = (_sg_max(width, 8) * 4 + 7) / 8;
|
||||
break;
|
||||
case SG_PIXELFORMAT_PVRTC_RGB_2BPP:
|
||||
case SG_PIXELFORMAT_PVRTC_RGBA_2BPP:
|
||||
{
|
||||
const int block_size = 8*4;
|
||||
const int bpp = 2;
|
||||
int width_blocks = width / 4;
|
||||
width_blocks = width_blocks < 2 ? 2 : width_blocks;
|
||||
pitch = width_blocks * ((block_size * bpp) / 8);
|
||||
}
|
||||
pitch = (_sg_max(width, 16) * 2 + 7) / 8;
|
||||
break;
|
||||
default:
|
||||
pitch = width * _sg_pixelformat_bytesize(fmt);
|
||||
|
@ -4307,11 +4315,19 @@ _SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) {
|
|||
case SG_PIXELFORMAT_BC6H_RGBF:
|
||||
case SG_PIXELFORMAT_BC6H_RGBUF:
|
||||
case SG_PIXELFORMAT_BC7_RGBA:
|
||||
num_rows = ((height + 3) / 4);
|
||||
break;
|
||||
case SG_PIXELFORMAT_PVRTC_RGB_4BPP:
|
||||
case SG_PIXELFORMAT_PVRTC_RGBA_4BPP:
|
||||
case SG_PIXELFORMAT_PVRTC_RGB_2BPP:
|
||||
case SG_PIXELFORMAT_PVRTC_RGBA_2BPP:
|
||||
num_rows = ((height + 3) / 4);
|
||||
/* NOTE: this is most likely not correct because it ignores any
|
||||
PVCRTC block size, but multiplied with _sg_row_pitch()
|
||||
it gives the correct surface pitch.
|
||||
|
||||
See: https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
|
||||
*/
|
||||
num_rows = ((_sg_max(height, 8) + 7) / 8) * 8;
|
||||
break;
|
||||
default:
|
||||
num_rows = height;
|
||||
|
@ -6327,7 +6343,6 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_
|
|||
gl_img_target = _sg_gl_cubeface_target(face_index);
|
||||
}
|
||||
const GLvoid* data_ptr = desc->data.subimage[face_index][mip_index].ptr;
|
||||
const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size;
|
||||
int mip_width = img->cmn.width >> mip_index;
|
||||
if (mip_width == 0) {
|
||||
mip_width = 1;
|
||||
|
@ -6338,6 +6353,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_
|
|||
}
|
||||
if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) {
|
||||
if (is_compressed) {
|
||||
const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size;
|
||||
glCompressedTexImage2D(gl_img_target, mip_index, gl_internal_format,
|
||||
mip_width, mip_height, 0, data_size, data_ptr);
|
||||
}
|
||||
|
@ -6357,6 +6373,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_
|
|||
mip_depth = 1;
|
||||
}
|
||||
if (is_compressed) {
|
||||
const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size;
|
||||
glCompressedTexImage3D(gl_img_target, mip_index, gl_internal_format,
|
||||
mip_width, mip_height, mip_depth, 0, data_size, data_ptr);
|
||||
}
|
||||
|
@ -6585,6 +6602,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pipeline(_sg_pipeline_t* pip, _sg
|
|||
}
|
||||
else {
|
||||
gl_attr->divisor = (int8_t) step_rate;
|
||||
pip->cmn.use_instanced_draw = true;
|
||||
}
|
||||
SOKOL_ASSERT(l_desc->stride > 0);
|
||||
gl_attr->stride = (uint8_t) l_desc->stride;
|
||||
|
@ -7340,6 +7358,7 @@ _SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_in
|
|||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_instances) {
|
||||
SOKOL_ASSERT(_sg.gl.cache.cur_pipeline);
|
||||
const GLenum i_type = _sg.gl.cache.cur_index_type;
|
||||
const GLenum p_type = _sg.gl.cache.cur_primitive_type;
|
||||
if (0 != i_type) {
|
||||
|
@ -7347,25 +7366,25 @@ _SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_inst
|
|||
const int i_size = (i_type == GL_UNSIGNED_SHORT) ? 2 : 4;
|
||||
const int ib_offset = _sg.gl.cache.cur_ib_offset;
|
||||
const GLvoid* indices = (const GLvoid*)(GLintptr)(base_element*i_size+ib_offset);
|
||||
if (num_instances == 1) {
|
||||
glDrawElements(p_type, num_elements, i_type, indices);
|
||||
}
|
||||
else {
|
||||
if (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw) {
|
||||
if (_sg.features.instancing) {
|
||||
glDrawElementsInstanced(p_type, num_elements, i_type, indices, num_instances);
|
||||
}
|
||||
}
|
||||
else {
|
||||
glDrawElements(p_type, num_elements, i_type, indices);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* non-indexed rendering */
|
||||
if (num_instances == 1) {
|
||||
glDrawArrays(p_type, base_element, num_elements);
|
||||
}
|
||||
else {
|
||||
if (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw) {
|
||||
if (_sg.features.instancing) {
|
||||
glDrawArraysInstanced(p_type, base_element, num_elements, num_instances);
|
||||
}
|
||||
}
|
||||
else {
|
||||
glDrawArrays(p_type, base_element, num_elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8242,8 +8261,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, cons
|
|||
init_data_ptr = &init_data;
|
||||
}
|
||||
HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_desc, init_data_ptr, &buf->d3d11.buf);
|
||||
_SOKOL_UNUSED(hr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && buf->d3d11.buf);
|
||||
if (!(SUCCEEDED(hr) && buf->d3d11.buf)) {
|
||||
SOKOL_LOG("failed to create D3D11 buffer\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
return SG_RESOURCESTATE_VALID;
|
||||
}
|
||||
|
@ -8289,7 +8310,6 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
SOKOL_ASSERT(!img->d3d11.tex2d && !img->d3d11.tex3d && !img->d3d11.texds && !img->d3d11.texmsaa);
|
||||
SOKOL_ASSERT(!img->d3d11.srv && !img->d3d11.smp);
|
||||
HRESULT hr;
|
||||
_SOKOL_UNUSED(hr);
|
||||
|
||||
_sg_image_common_init(&img->cmn, desc);
|
||||
const bool injected = (0 != desc->d3d11_texture) || (0 != desc->d3d11_shader_resource_view);
|
||||
|
@ -8316,7 +8336,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
d3d11_desc.SampleDesc.Count = (UINT)img->cmn.sample_count;
|
||||
d3d11_desc.SampleDesc.Quality = (UINT) (msaa ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0);
|
||||
hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_desc, NULL, &img->d3d11.texds);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.texds);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.texds)) {
|
||||
SOKOL_LOG("failed to create D3D11 texture 2D\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* create (or inject) color texture and shader-resource-view */
|
||||
|
@ -8386,7 +8409,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
d3d11_tex_desc.MiscFlags = (img->cmn.type == SG_IMAGETYPE_CUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
|
||||
|
||||
hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex2d);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.tex2d);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.tex2d)) {
|
||||
SOKOL_LOG("failed to create D3D11 texture 2D\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* ...and similar, if not injected, create shader-resource-view */
|
||||
|
@ -8412,7 +8438,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
SOKOL_UNREACHABLE; break;
|
||||
}
|
||||
hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex2d, &d3d11_srv_desc, &img->d3d11.srv);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.srv);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.srv)) {
|
||||
SOKOL_LOG("failed to create D3D11 resource view\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -8459,7 +8488,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
hr = _sg_d3d11_CreateTexture3D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex3d);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.tex3d);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.tex3d)) {
|
||||
SOKOL_LOG("failed to create D3D11 texture 3D\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == img->d3d11.srv) {
|
||||
|
@ -8469,7 +8501,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
d3d11_srv_desc.Texture3D.MipLevels = (UINT)img->cmn.num_mipmaps;
|
||||
hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex3d, &d3d11_srv_desc, &img->d3d11.srv);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.srv);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.srv)) {
|
||||
SOKOL_LOG("failed to create D3D11 resource view\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8488,7 +8523,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
d3d11_tex_desc.SampleDesc.Count = (UINT)img->cmn.sample_count;
|
||||
d3d11_tex_desc.SampleDesc.Quality = (UINT)D3D11_STANDARD_MULTISAMPLE_PATTERN;
|
||||
hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, NULL, &img->d3d11.texmsaa);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.texmsaa);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.texmsaa)) {
|
||||
SOKOL_LOG("failed to create D3D11 texture 2D\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* sampler state object, note D3D11 implements an internal shared-pool for sampler objects */
|
||||
|
@ -8517,7 +8555,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const
|
|||
d3d11_smp_desc.MinLOD = desc->min_lod;
|
||||
d3d11_smp_desc.MaxLOD = desc->max_lod;
|
||||
hr = _sg_d3d11_CreateSamplerState(_sg.d3d11.dev, &d3d11_smp_desc, &img->d3d11.smp);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.smp);
|
||||
if (!(SUCCEEDED(hr) && img->d3d11.smp)) {
|
||||
SOKOL_LOG("failed to create D3D11 sampler state\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
return SG_RESOURCESTATE_VALID;
|
||||
}
|
||||
|
@ -8609,7 +8650,6 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons
|
|||
SOKOL_ASSERT(shd && desc);
|
||||
SOKOL_ASSERT(!shd->d3d11.vs && !shd->d3d11.fs && !shd->d3d11.vs_blob);
|
||||
HRESULT hr;
|
||||
_SOKOL_UNUSED(hr);
|
||||
|
||||
_sg_shader_common_init(&shd->cmn, desc);
|
||||
|
||||
|
@ -8634,7 +8674,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons
|
|||
cb_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &cb_desc, NULL, &d3d11_stage->cbufs[ub_index]);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && d3d11_stage->cbufs[ub_index]);
|
||||
if (!(SUCCEEDED(hr) && d3d11_stage->cbufs[ub_index])) {
|
||||
SOKOL_LOG("failed to create D3D11 buffer\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8722,7 +8765,6 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip,
|
|||
|
||||
/* create input layout object */
|
||||
HRESULT hr;
|
||||
_SOKOL_UNUSED(hr);
|
||||
D3D11_INPUT_ELEMENT_DESC d3d11_comps[SG_MAX_VERTEX_ATTRIBUTES];
|
||||
memset(d3d11_comps, 0, sizeof(d3d11_comps));
|
||||
int attr_index = 0;
|
||||
|
@ -8744,6 +8786,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip,
|
|||
d3d11_comp->InputSlotClass = _sg_d3d11_input_classification(step_func);
|
||||
if (SG_VERTEXSTEP_PER_INSTANCE == step_func) {
|
||||
d3d11_comp->InstanceDataStepRate = (UINT)step_rate;
|
||||
pip->cmn.use_instanced_draw = true;
|
||||
}
|
||||
pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true;
|
||||
}
|
||||
|
@ -8763,7 +8806,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip,
|
|||
shd->d3d11.vs_blob, /* pShaderByteCodeWithInputSignature */
|
||||
shd->d3d11.vs_blob_length, /* BytecodeLength */
|
||||
&pip->d3d11.il);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && pip->d3d11.il);
|
||||
if (!(SUCCEEDED(hr) && pip->d3d11.il)) {
|
||||
SOKOL_LOG("failed to create D3D11 input layout\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
|
||||
/* create rasterizer state */
|
||||
D3D11_RASTERIZER_DESC rs_desc;
|
||||
|
@ -8779,7 +8825,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip,
|
|||
rs_desc.MultisampleEnable = desc->sample_count > 1;
|
||||
rs_desc.AntialiasedLineEnable = FALSE;
|
||||
hr = _sg_d3d11_CreateRasterizerState(_sg.d3d11.dev, &rs_desc, &pip->d3d11.rs);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && pip->d3d11.rs);
|
||||
if (!(SUCCEEDED(hr) && pip->d3d11.rs)) {
|
||||
SOKOL_LOG("failed to create D3D11 rasterizer state\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
|
||||
/* create depth-stencil state */
|
||||
D3D11_DEPTH_STENCIL_DESC dss_desc;
|
||||
|
@ -8801,7 +8850,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip,
|
|||
dss_desc.BackFace.StencilPassOp = _sg_d3d11_stencil_op(sb->pass_op);
|
||||
dss_desc.BackFace.StencilFunc = _sg_d3d11_compare_func(sb->compare);
|
||||
hr = _sg_d3d11_CreateDepthStencilState(_sg.d3d11.dev, &dss_desc, &pip->d3d11.dss);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && pip->d3d11.dss);
|
||||
if (!(SUCCEEDED(hr) && pip->d3d11.dss)) {
|
||||
SOKOL_LOG("failed to create D3D11 depth stencil state\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
|
||||
/* create blend state */
|
||||
D3D11_BLEND_DESC bs_desc;
|
||||
|
@ -8832,7 +8884,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip,
|
|||
}
|
||||
}
|
||||
hr = _sg_d3d11_CreateBlendState(_sg.d3d11.dev, &bs_desc, &pip->d3d11.bs);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && pip->d3d11.bs);
|
||||
if (!(SUCCEEDED(hr) && pip->d3d11.bs)) {
|
||||
SOKOL_LOG("failed to create D3D11 blend state\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
|
||||
return SG_RESOURCESTATE_VALID;
|
||||
}
|
||||
|
@ -8910,8 +8965,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima
|
|||
}
|
||||
SOKOL_ASSERT(d3d11_res);
|
||||
HRESULT hr = _sg_d3d11_CreateRenderTargetView(_sg.d3d11.dev, d3d11_res, &d3d11_rtv_desc, &pass->d3d11.color_atts[i].rtv);
|
||||
_SOKOL_UNUSED(hr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && pass->d3d11.color_atts[i].rtv);
|
||||
if (!(SUCCEEDED(hr) && pass->d3d11.color_atts[i].rtv)) {
|
||||
SOKOL_LOG("failed to create D3D11 render target view\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* optional depth-stencil image */
|
||||
|
@ -8941,8 +8998,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima
|
|||
ID3D11Resource* d3d11_res = (ID3D11Resource*) att_img->d3d11.texds;
|
||||
SOKOL_ASSERT(d3d11_res);
|
||||
HRESULT hr = _sg_d3d11_CreateDepthStencilView(_sg.d3d11.dev, d3d11_res, &d3d11_dsv_desc, &pass->d3d11.ds_att.dsv);
|
||||
_SOKOL_UNUSED(hr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr) && pass->d3d11.ds_att.dsv);
|
||||
if (!(SUCCEEDED(hr) && pass->d3d11.ds_att.dsv)) {
|
||||
SOKOL_LOG("failed to create D3D11 depth stencil view\n");
|
||||
return SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
return SG_RESOURCESTATE_VALID;
|
||||
}
|
||||
|
@ -9124,6 +9183,7 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) {
|
|||
_sg.d3d11.cur_pipeline = pip;
|
||||
_sg.d3d11.cur_pipeline_id.id = pip->slot.id;
|
||||
_sg.d3d11.use_indexed_draw = (pip->d3d11.index_format != DXGI_FORMAT_UNKNOWN);
|
||||
_sg.d3d11.use_instanced_draw = pip->cmn.use_instanced_draw;
|
||||
|
||||
_sg_d3d11_RSSetState(_sg.d3d11.ctx, pip->d3d11.rs);
|
||||
_sg_d3d11_OMSetDepthStencilState(_sg.d3d11.ctx, pip->d3d11.dss, pip->d3d11.stencil_ref);
|
||||
|
@ -9208,20 +9268,20 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub
|
|||
_SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_instances) {
|
||||
SOKOL_ASSERT(_sg.d3d11.in_pass);
|
||||
if (_sg.d3d11.use_indexed_draw) {
|
||||
if (1 == num_instances) {
|
||||
_sg_d3d11_DrawIndexed(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element, 0);
|
||||
}
|
||||
else {
|
||||
if (_sg.d3d11.use_instanced_draw) {
|
||||
_sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0, 0);
|
||||
}
|
||||
else {
|
||||
_sg_d3d11_DrawIndexed(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (1 == num_instances) {
|
||||
_sg_d3d11_Draw(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element);
|
||||
}
|
||||
else {
|
||||
if (_sg.d3d11.use_instanced_draw) {
|
||||
_sg_d3d11_DrawInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0);
|
||||
}
|
||||
else {
|
||||
_sg_d3d11_Draw(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9235,10 +9295,12 @@ _SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const sg_range* d
|
|||
SOKOL_ASSERT(buf->d3d11.buf);
|
||||
D3D11_MAPPED_SUBRESOURCE d3d11_msr;
|
||||
HRESULT hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr);
|
||||
_SOKOL_UNUSED(hr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
if (SUCCEEDED(hr)) {
|
||||
memcpy(d3d11_msr.pData, data->ptr, data->size);
|
||||
_sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0);
|
||||
} else {
|
||||
SOKOL_LOG("failed to map buffer while updating!\n");
|
||||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE int _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) {
|
||||
|
@ -9248,12 +9310,14 @@ _SOKOL_PRIVATE int _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* da
|
|||
D3D11_MAP map_type = new_frame ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE;
|
||||
D3D11_MAPPED_SUBRESOURCE d3d11_msr;
|
||||
HRESULT hr = _sg_d3d11_Map(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0, map_type, 0, &d3d11_msr);
|
||||
_SOKOL_UNUSED(hr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
if (SUCCEEDED(hr)) {
|
||||
uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData + buf->cmn.append_pos;
|
||||
memcpy(dst_ptr, data->ptr, data->size);
|
||||
_sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0);
|
||||
/* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */
|
||||
} else {
|
||||
SOKOL_LOG("failed to map buffer while appending!\n");
|
||||
}
|
||||
/* NOTE: this alignment is a requirement from WebGPU, but we want identical behaviour across all backend */
|
||||
return _sg_roundup((int)data->size, 4);
|
||||
}
|
||||
|
||||
|
@ -9273,7 +9337,6 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data
|
|||
const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1;
|
||||
UINT subres_index = 0;
|
||||
HRESULT hr;
|
||||
_SOKOL_UNUSED(hr);
|
||||
D3D11_MAPPED_SUBRESOURCE d3d11_msr;
|
||||
for (int face_index = 0; face_index < num_faces; face_index++) {
|
||||
for (int slice_index = 0; slice_index < num_slices; slice_index++) {
|
||||
|
@ -9287,7 +9350,7 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data
|
|||
const size_t slice_offset = slice_size * (size_t)slice_index;
|
||||
const uint8_t* slice_ptr = ((const uint8_t*)subimg_data->ptr) + slice_offset;
|
||||
hr = _sg_d3d11_Map(_sg.d3d11.ctx, d3d11_res, subres_index, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr);
|
||||
SOKOL_ASSERT(SUCCEEDED(hr));
|
||||
if (SUCCEEDED(hr)) {
|
||||
/* FIXME: need to handle difference in depth-pitch for 3D textures as well! */
|
||||
if (src_pitch == (int)d3d11_msr.RowPitch) {
|
||||
memcpy(d3d11_msr.pData, slice_ptr, slice_size);
|
||||
|
@ -9303,6 +9366,9 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data
|
|||
}
|
||||
}
|
||||
_sg_d3d11_Unmap(_sg.d3d11.ctx, d3d11_res, subres_index);
|
||||
} else {
|
||||
SOKOL_LOG("failed to map texture!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10110,22 +10176,31 @@ _SOKOL_PRIVATE void _sg_mtl_copy_image_data(const _sg_image_t* img, __unsafe_unr
|
|||
const uint8_t* data_ptr = (const uint8_t*)data->subimage[face_index][mip_index].ptr;
|
||||
const int mip_width = _sg_max(img->cmn.width >> mip_index, 1);
|
||||
const int mip_height = _sg_max(img->cmn.height >> mip_index, 1);
|
||||
/* special case PVRTC formats: bytePerRow must be 0 */
|
||||
/* special case PVRTC formats: bytePerRow and bytesPerImage must be 0 */
|
||||
int bytes_per_row = 0;
|
||||
int bytes_per_slice = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1);
|
||||
int bytes_per_slice = 0;
|
||||
if (!_sg_mtl_is_pvrtc(img->cmn.pixel_format)) {
|
||||
bytes_per_row = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1);
|
||||
bytes_per_slice = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1);
|
||||
}
|
||||
/* bytesPerImage special case: https://developer.apple.com/documentation/metal/mtltexture/1515679-replaceregion
|
||||
|
||||
"Supply a nonzero value only when you copy data to a MTLTextureType3D type texture"
|
||||
*/
|
||||
MTLRegion region;
|
||||
int bytes_per_image;
|
||||
if (img->cmn.type == SG_IMAGETYPE_3D) {
|
||||
const int mip_depth = _sg_max(img->cmn.num_slices >> mip_index, 1);
|
||||
region = MTLRegionMake3D(0, 0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height, (NSUInteger)mip_depth);
|
||||
bytes_per_image = bytes_per_slice;
|
||||
/* FIXME: apparently the minimal bytes_per_image size for 3D texture
|
||||
is 4 KByte... somehow need to handle this */
|
||||
}
|
||||
else {
|
||||
region = MTLRegionMake2D(0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height);
|
||||
bytes_per_image = 0;
|
||||
}
|
||||
|
||||
for (int slice_index = 0; slice_index < num_slices; slice_index++) {
|
||||
const int mtl_slice_index = (img->cmn.type == SG_IMAGETYPE_CUBE) ? face_index : slice_index;
|
||||
const int slice_offset = slice_index * bytes_per_slice;
|
||||
|
@ -10135,7 +10210,7 @@ _SOKOL_PRIVATE void _sg_mtl_copy_image_data(const _sg_image_t* img, __unsafe_unr
|
|||
slice:(NSUInteger)mtl_slice_index
|
||||
withBytes:data_ptr + slice_offset
|
||||
bytesPerRow:(NSUInteger)bytes_per_row
|
||||
bytesPerImage:(NSUInteger)bytes_per_slice];
|
||||
bytesPerImage:(NSUInteger)bytes_per_image];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10431,6 +10506,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s
|
|||
vtx_desc.layouts[mtl_vb_slot].stride = (NSUInteger)l_desc->stride;
|
||||
vtx_desc.layouts[mtl_vb_slot].stepFunction = _sg_mtl_step_function(l_desc->step_func);
|
||||
vtx_desc.layouts[mtl_vb_slot].stepRate = (NSUInteger)l_desc->step_rate;
|
||||
if (SG_VERTEXSTEP_PER_INSTANCE == l_desc->step_func) {
|
||||
// NOTE: not actually used in _sg_mtl_draw()
|
||||
pip->cmn.use_instanced_draw = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13563,6 +13642,10 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) {
|
|||
case _SG_VALIDATE_BUFFERDESC_DATA_SIZE: return "immutable buffer data size differs from buffer size";
|
||||
case _SG_VALIDATE_BUFFERDESC_NO_DATA: return "dynamic/stream usage buffers cannot be initialized with data";
|
||||
|
||||
/* image data (in image creation and updating) */
|
||||
case _SG_VALIDATE_IMAGEDATA_NODATA: return "sg_image_data: no data (.ptr and/or .size is zero)";
|
||||
case _SG_VALIDATE_IMAGEDATA_DATA_SIZE: return "sg_image_data: data size doesn't match expected surface size";
|
||||
|
||||
/* image creation validation errros */
|
||||
case _SG_VALIDATE_IMAGEDESC_CANARY: return "sg_image_desc not initialized";
|
||||
case _SG_VALIDATE_IMAGEDESC_WIDTH: return "sg_image_desc.width must be > 0";
|
||||
|
@ -13573,8 +13656,9 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) {
|
|||
case _SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT: return "MSAA not supported for this pixel format";
|
||||
case _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE: return "render target images must be SG_USAGE_IMMUTABLE";
|
||||
case _SG_VALIDATE_IMAGEDESC_RT_NO_DATA: return "render target images cannot be initialized with data";
|
||||
case _SG_VALIDATE_IMAGEDESC_DATA: return "missing or invalid data for immutable image";
|
||||
case _SG_VALIDATE_IMAGEDESC_NO_DATA: return "dynamic/stream usage images cannot be initialized with data";
|
||||
case _SG_VALIDATE_IMAGEDESC_INJECTED_NO_DATA: return "images with injected textures cannot be initialized with data";
|
||||
case _SG_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA: return "dynamic/stream images cannot be initialized with data";
|
||||
case _SG_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE: return "compressed images must be immutable";
|
||||
|
||||
/* shader creation */
|
||||
case _SG_VALIDATE_SHADERDESC_CANARY: return "sg_shader_desc not initialized";
|
||||
|
@ -13669,9 +13753,6 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) {
|
|||
|
||||
/* sg_update_image */
|
||||
case _SG_VALIDATE_UPDIMG_USAGE: return "sg_update_image: cannot update immutable image";
|
||||
case _SG_VALIDATE_UPDIMG_NOTENOUGHDATA: return "sg_update_image: not enough subimage data provided";
|
||||
case _SG_VALIDATE_UPDIMG_SIZE: return "sg_update_image: provided subimage data size too big";
|
||||
case _SG_VALIDATE_UPDIMG_COMPRESSED: return "sg_update_image: cannot update images with compressed format";
|
||||
case _SG_VALIDATE_UPDIMG_ONCE: return "sg_update_image: only one update allowed per image and frame";
|
||||
|
||||
default: return "unknown validation error";
|
||||
|
@ -13695,7 +13776,7 @@ _SOKOL_PRIVATE void _sg_validate(bool cond, _sg_validate_error_t err) {
|
|||
_SOKOL_PRIVATE bool _sg_validate_end(void) {
|
||||
if (_sg.validate_error != _SG_VALIDATE_SUCCESS) {
|
||||
#if !defined(SOKOL_VALIDATE_NON_FATAL)
|
||||
SOKOL_LOG("^^^^ VALIDATION FAILED, TERMINATING ^^^^");
|
||||
SOKOL_LOG("^^^^ SOKOL-GFX VALIDATION FAILED, TERMINATING ^^^^");
|
||||
SOKOL_ASSERT(false);
|
||||
#endif
|
||||
return false;
|
||||
|
@ -13731,6 +13812,31 @@ _SOKOL_PRIVATE bool _sg_validate_buffer_desc(const sg_buffer_desc* desc) {
|
|||
#endif
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sg_validate_image_data(const sg_image_data* data, sg_pixel_format fmt, int width, int height, int num_faces, int num_mips, int num_slices) {
|
||||
#if !defined(SOKOL_DEBUG)
|
||||
_SOKOL_UNUSED(data);
|
||||
_SOKOL_UNUSED(fmt);
|
||||
_SOKOL_UNUSED(width);
|
||||
_SOKOL_UNUSED(height);
|
||||
_SOKOL_UNUSED(num_faces);
|
||||
_SOKOL_UNUSED(num_mips);
|
||||
_SOKOL_UNUSED(num_slices);
|
||||
#else
|
||||
for (int face_index = 0; face_index < num_faces; face_index++) {
|
||||
for (int mip_index = 0; mip_index < num_mips; mip_index++) {
|
||||
const bool has_data = data->subimage[face_index][mip_index].ptr != 0;
|
||||
const bool has_size = data->subimage[face_index][mip_index].size > 0;
|
||||
SOKOL_VALIDATE(has_data && has_size, _SG_VALIDATE_IMAGEDATA_NODATA);
|
||||
const int mip_width = _sg_max(width >> mip_index, 1);
|
||||
const int mip_height = _sg_max(height >> mip_index, 1);
|
||||
const int bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, 1);
|
||||
const int expected_size = bytes_per_slice * num_slices;
|
||||
SOKOL_VALIDATE(expected_size == (int)data->subimage[face_index][mip_index].size, _SG_VALIDATE_IMAGEDATA_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _sg_validate_image_desc(const sg_image_desc* desc) {
|
||||
#if !defined(SOKOL_DEBUG)
|
||||
_SOKOL_UNUSED(desc);
|
||||
|
@ -13768,24 +13874,33 @@ _SOKOL_PRIVATE bool _sg_validate_image_desc(const sg_image_desc* desc) {
|
|||
SOKOL_VALIDATE(desc->sample_count <= 1, _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT);
|
||||
const bool valid_nonrt_fmt = !_sg_is_valid_rendertarget_depth_format(fmt);
|
||||
SOKOL_VALIDATE(valid_nonrt_fmt, _SG_VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT);
|
||||
/* FIXME: should use the same "expected size" computation as in _sg_validate_update_image() here */
|
||||
if (!injected && (usage == SG_USAGE_IMMUTABLE)) {
|
||||
const int num_faces = desc->type == SG_IMAGETYPE_CUBE ? 6:1;
|
||||
const int num_mips = desc->num_mipmaps;
|
||||
for (int face_index = 0; face_index < num_faces; face_index++) {
|
||||
for (int mip_index = 0; mip_index < num_mips; mip_index++) {
|
||||
const bool has_data = desc->data.subimage[face_index][mip_index].ptr != 0;
|
||||
const bool has_size = desc->data.subimage[face_index][mip_index].size > 0;
|
||||
SOKOL_VALIDATE(has_data && has_size, _SG_VALIDATE_IMAGEDESC_DATA);
|
||||
}
|
||||
const bool is_compressed = _sg_is_compressed_pixel_format(desc->pixel_format);
|
||||
const bool is_immutable = (usage == SG_USAGE_IMMUTABLE);
|
||||
if (is_compressed) {
|
||||
SOKOL_VALIDATE(is_immutable, _SG_VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE);
|
||||
}
|
||||
if (!injected && is_immutable) {
|
||||
// image desc must have valid data
|
||||
_sg_validate_image_data(&desc->data,
|
||||
desc->pixel_format,
|
||||
desc->width,
|
||||
desc->height,
|
||||
(desc->type == SG_IMAGETYPE_CUBE) ? 6 : 1,
|
||||
desc->num_mipmaps,
|
||||
desc->num_slices);
|
||||
}
|
||||
else {
|
||||
// image desc must not have data
|
||||
for (int face_index = 0; face_index < SG_CUBEFACE_NUM; face_index++) {
|
||||
for (int mip_index = 0; mip_index < SG_MAX_MIPMAPS; mip_index++) {
|
||||
const bool no_data = 0 == desc->data.subimage[face_index][mip_index].ptr;
|
||||
const bool no_size = 0 == desc->data.subimage[face_index][mip_index].size;
|
||||
SOKOL_VALIDATE(no_data && no_size, _SG_VALIDATE_IMAGEDESC_NO_DATA);
|
||||
if (injected) {
|
||||
SOKOL_VALIDATE(no_data && no_size, _SG_VALIDATE_IMAGEDESC_INJECTED_NO_DATA);
|
||||
}
|
||||
if (!is_immutable) {
|
||||
SOKOL_VALIDATE(no_data && no_size, _SG_VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13866,6 +13981,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) {
|
|||
#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3)
|
||||
SOKOL_VALIDATE((size_t)uniform_offset == ub_desc->size, _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH);
|
||||
SOKOL_VALIDATE(num_uniforms > 0, _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS);
|
||||
#else
|
||||
_SOKOL_UNUSED(uniform_offset);
|
||||
_SOKOL_UNUSED(num_uniforms);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@ -14233,19 +14351,13 @@ _SOKOL_PRIVATE bool _sg_validate_update_image(const _sg_image_t* img, const sg_i
|
|||
SOKOL_VALIDATE_BEGIN();
|
||||
SOKOL_VALIDATE(img->cmn.usage != SG_USAGE_IMMUTABLE, _SG_VALIDATE_UPDIMG_USAGE);
|
||||
SOKOL_VALIDATE(img->cmn.upd_frame_index != _sg.frame_index, _SG_VALIDATE_UPDIMG_ONCE);
|
||||
SOKOL_VALIDATE(!_sg_is_compressed_pixel_format(img->cmn.pixel_format), _SG_VALIDATE_UPDIMG_COMPRESSED);
|
||||
const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6 : 1;
|
||||
const int num_mips = img->cmn.num_mipmaps;
|
||||
for (int face_index = 0; face_index < num_faces; face_index++) {
|
||||
for (int mip_index = 0; mip_index < num_mips; mip_index++) {
|
||||
SOKOL_VALIDATE(0 != data->subimage[face_index][mip_index].ptr, _SG_VALIDATE_UPDIMG_NOTENOUGHDATA);
|
||||
const int mip_width = _sg_max(img->cmn.width >> mip_index, 1);
|
||||
const int mip_height = _sg_max(img->cmn.height >> mip_index, 1);
|
||||
const int bytes_per_slice = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1);
|
||||
const int expected_size = bytes_per_slice * img->cmn.num_slices;
|
||||
SOKOL_VALIDATE(data->subimage[face_index][mip_index].size <= (size_t)expected_size, _SG_VALIDATE_UPDIMG_SIZE);
|
||||
}
|
||||
}
|
||||
_sg_validate_image_data(data,
|
||||
img->cmn.pixel_format,
|
||||
img->cmn.width,
|
||||
img->cmn.height,
|
||||
(img->cmn.type == SG_IMAGETYPE_CUBE) ? 6 : 1,
|
||||
img->cmn.num_mipmaps,
|
||||
img->cmn.num_slices);
|
||||
return SOKOL_VALIDATE_END();
|
||||
#endif
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -768,7 +768,6 @@ pub fn (ctx &Context) draw_slice_empty(x f32, y f32, r f32, start_angle f32, arc
|
|||
pub fn (mut ctx Context) resize(width int, height int) {
|
||||
ctx.width = width
|
||||
ctx.height = height
|
||||
// C.sapp_resize_window(width, height)
|
||||
}
|
||||
|
||||
// Draws a line between the points provided
|
||||
|
|
|
@ -53,6 +53,8 @@ fn C.saudio_buffer_frames() int
|
|||
|
||||
fn C.saudio_channels() int
|
||||
|
||||
fn C.saudio_suspended() bool
|
||||
|
||||
fn C.saudio_expect() int
|
||||
|
||||
fn C.saudio_push(frames &f32, num_frames int) int
|
||||
|
@ -97,6 +99,12 @@ pub fn channels() int {
|
|||
return C.saudio_channels()
|
||||
}
|
||||
|
||||
// suspended returns true if audio context is currently suspended
|
||||
// (only in WebAudio backend, all other backends return false)
|
||||
pub fn suspended() bool {
|
||||
return C.saudio_suspended()
|
||||
}
|
||||
|
||||
// audio.expect - get current number of frames to fill packet queue; use in combination with audio.push/2
|
||||
pub fn expect() int {
|
||||
return C.saudio_expect()
|
||||
|
|
|
@ -136,6 +136,12 @@ pub fn frame_count() u64 {
|
|||
return C.sapp_frame_count()
|
||||
}
|
||||
|
||||
// get an averaged/smoothed frame duration in seconds
|
||||
[inline]
|
||||
pub fn frame_duration() f64 {
|
||||
return C.sapp_frame_duration()
|
||||
}
|
||||
|
||||
// write string into clipboard
|
||||
[inline]
|
||||
pub fn set_clipboard_string(str &char) {
|
||||
|
|
|
@ -56,6 +56,9 @@ fn C.sapp_consume_event()
|
|||
// get the current frame counter (for comparison with sapp_event.frame_count)
|
||||
fn C.sapp_frame_count() u64
|
||||
|
||||
// get an averaged/smoothed frame duration in seconds
|
||||
fn C.sapp_frame_duration() f64
|
||||
|
||||
// write string into clipboard
|
||||
fn C.sapp_set_clipboard_string(str &byte)
|
||||
|
||||
|
@ -115,5 +118,3 @@ fn C.sapp_get_num_dropped_files() int
|
|||
|
||||
// Get the file path of the droped file
|
||||
fn C.sapp_get_dropped_file_path(int) &byte
|
||||
|
||||
fn C.sapp_resize_window(int, int)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module sgl
|
||||
|
||||
// Error is C.sgl_error_t
|
||||
// SglError is C.sgl_error_t
|
||||
pub enum SglError {
|
||||
no_error = C.SGL_NO_ERROR // 0
|
||||
vertices_full = C.SGL_ERROR_VERTICES_FULL
|
||||
|
|
|
@ -254,6 +254,11 @@ pub fn c1i(rgba u32) {
|
|||
C.sgl_c1i(rgba)
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn point_size(s f32) {
|
||||
C.sgl_point_size(s)
|
||||
}
|
||||
|
||||
// define primitives, each begin/end is one draw command
|
||||
[inline]
|
||||
pub fn begin_points() {
|
||||
|
|
|
@ -62,6 +62,7 @@ fn C.sgl_c4f(r f32, g f32, b f32, a f32)
|
|||
fn C.sgl_c3b(r byte, g byte, b byte)
|
||||
fn C.sgl_c4b(r byte, g byte, b byte, a byte)
|
||||
fn C.sgl_c1i(rgba u32)
|
||||
fn C.sgl_point_size(s f32)
|
||||
|
||||
// define primitives, each begin/end is one draw command
|
||||
fn C.sgl_begin_points()
|
||||
|
|
Loading…
Reference in New Issue