Coder Social home page Coder Social logo

floooh / sokol Goto Github PK

View Code? Open in Web Editor NEW
6.5K 116.0 460.0 9.57 MB

minimal cross-platform standalone C headers

Home Page: https://floooh.github.io/sokol-html5

License: zlib License

C 83.67% Objective-C 13.23% Python 2.69% CMake 0.28% C++ 0.06% Shell 0.07% Batchfile 0.01%

sokol's Introduction



Simple STB-style cross-platform libraries for C and C++, written in C.

Sokol

See what's new (19-Jun-2024: bugfix in the sokol_gfx.h d3d11 backend when updating 3d textures

Build Bindings build build OdinRustDlang

Examples and Related Projects

Core libraries

  • sokol_gfx.h: 3D-API wrapper (GL/GLES3/WebGL2 + Metal + D3D11 + WebGPU)
  • sokol_app.h: app framework wrapper (entry + window + 3D-context + input)
  • sokol_time.h: time measurement
  • sokol_audio.h: minimal buffer-streaming audio playback
  • sokol_fetch.h: asynchronous data streaming from HTTP and local filesystem
  • sokol_args.h: unified cmdline/URL arg parser for web and native apps
  • sokol_log.h: provides a standard logging callback for the other sokol headers

Utility libraries

'Official' Language Bindings

These are automatically updated on changes to the C headers:

Notes

WebAssembly is a 'first-class citizen', one important motivation for the Sokol headers is to provide a collection of cross-platform APIs with a minimal footprint on the web platform while still being useful.

The core headers are standalone and can be used independently from each other.

Why C:

  • easier integration with other languages
  • easier integration into other projects
  • adds only minimal size overhead to executables

A blog post with more background info: A Tour of sokol_gfx.h

sokol_gfx.h:

  • simple, modern wrapper around GLES3/WebGL2, GL3.3, D3D11, Metal, and WebGPU
  • buffers, images, shaders, pipeline-state-objects and render-passes
  • does not handle window creation or 3D API context initialization
  • does not provide shader dialect cross-translation (BUT there's now an 'official' shader-cross-compiler solution which seamlessly integrates with sokol_gfx.h and IDEs: see here for details

sokol_app.h

A minimal cross-platform application-wrapper library:

  • unified application entry
  • single window or canvas for 3D rendering
  • 3D context initialization
  • event-based keyboard, mouse and touch input
  • supported platforms: Win32, MacOS, Linux (X11), iOS, WASM, Android, UWP
  • supported 3D-APIs: GL3.3 (GLX/WGL), Metal, D3D11, GLES3/WebGL2

The vanilla Hello-Triangle using sokol_gfx.h, sokol_app.h and the sokol-shdc shader compiler (shader code not shown):

#include "sokol_app.h"
#include "sokol_gfx.h"
#include "sokol_log.h"
#include "sokol_glue.h"
#include "triangle-sapp.glsl.h"

static struct {
    sg_pipeline pip;
    sg_bindings bind;
    sg_pass_action pass_action;
} state;

static void init(void) {
    sg_setup(&(sg_desc){
        .environment = sglue_environment(),
        .logger.func = slog_func,
    });

    float vertices[] = {
         0.0f,  0.5f, 0.5f,     1.0f, 0.0f, 0.0f, 1.0f,
         0.5f, -0.5f, 0.5f,     0.0f, 1.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f,     0.0f, 0.0f, 1.0f, 1.0f
    };
    state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
        .data = SG_RANGE(vertices),
    });

    state.pip = sg_make_pipeline(&(sg_pipeline_desc){
        .shader = sg_make_shader(triangle_shader_desc(sg_query_backend())),
        .layout = {
            .attrs = {
                [ATTR_vs_position].format = SG_VERTEXFORMAT_FLOAT3,
                [ATTR_vs_color0].format = SG_VERTEXFORMAT_FLOAT4
            }
        },
    });

    state.pass_action = (sg_pass_action) {
        .colors[0] = { .load_action=SG_LOADACTION_CLEAR, .clear_value={0.0f, 0.0f, 0.0f, 1.0f } }
    };
}

void frame(void) {
    sg_begin_pass(&(sg_pass){ .action = state.pass_action, .swapchain = sglue_swapchain() });
    sg_apply_pipeline(state.pip);
    sg_apply_bindings(&state.bind);
    sg_draw(0, 3, 1);
    sg_end_pass();
    sg_commit();
}

void cleanup(void) {
    sg_shutdown();
}

sapp_desc sokol_main(int argc, char* argv[]) {
    (void)argc; (void)argv;
    return (sapp_desc){
        .init_cb = init,
        .frame_cb = frame,
        .cleanup_cb = cleanup,
        .width = 640,
        .height = 480,
        .window_title = "Triangle",
        .icon.sokol_default = true,
        .logger.func = slog_func,
    };
}

sokol_audio.h

A minimal audio-streaming API:

  • you provide a mono- or stereo-stream of 32-bit float samples which sokol_audio.h forwards into platform-specific backends
  • two ways to provide the data:
    1. directly fill backend audio buffer from your callback function running in the audio thread
    2. alternatively push small packets of audio data from your main loop, or a separate thread created by you
  • platform backends:
    • Windows: WASAPI
    • macOS/iOS: CoreAudio
    • Linux: ALSA
    • emscripten: WebAudio + ScriptProcessorNode (doesn't use the emscripten-provided OpenAL or SDL Audio wrappers)

A simple mono square-wave generator using the callback model:

// the sample callback, running in audio thread
static void stream_cb(float* buffer, int num_frames, int num_channels) {
    assert(1 == num_channels);
    static uint32_t count = 0;
    for (int i = 0; i < num_frames; i++) {
        buffer[i] = (count++ & (1<<3)) ? 0.5f : -0.5f;
    }
}

int main() {
    // init sokol-audio with default params
    saudio_setup(&(saudio_desc){
        .stream_cb = stream_cb,
        .logger.func = slog_func,
    });

    // run main loop
    ...

    // shutdown sokol-audio
    saudio_shutdown();
    return 0;

The same code using the push-model

#define BUF_SIZE (32)
int main() {
    // init sokol-audio with default params, no callback
    saudio_setup(&(saudio_desc){
        .logger.func = slog_func,
    });
    assert(saudio_channels() == 1);

    // a small intermediate buffer so we don't need to push
    // individual samples, which would be quite inefficient
    float buf[BUF_SIZE];
    int buf_pos = 0;
    uint32_t count = 0;

    // push samples from main loop
    bool done = false;
    while (!done) {
        // generate and push audio samples...
        int num_frames = saudio_expect();
        for (int i = 0; i < num_frames; i++) {
            // simple square wave generator
            buf[buf_pos++] = (count++ & (1<<3)) ? 0.5f : -0.5f;
            if (buf_pos == BUF_SIZE) {
                buf_pos = 0;
                saudio_push(buf, BUF_SIZE);
            }
        }
        // handle other per-frame stuff...
        ...
    }

    // shutdown sokol-audio
    saudio_shutdown();
    return 0;
}

sokol_fetch.h

Load entire files, or stream data asynchronously over HTTP (emscripten/wasm) or the local filesystem (all native platforms).

Simple C99 example loading a file into a static buffer:

#include "sokol_fetch.h"
#include "sokol_log.h"

static void response_callback(const sfetch_response*);

#define MAX_FILE_SIZE (1024*1024)
static uint8_t buffer[MAX_FILE_SIZE];

// application init
static void init(void) {
    ...
    // setup sokol-fetch with default config:
    sfetch_setup(&(sfetch_desc_t){ .logger.func = slog_func });

    // start loading a file into a statically allocated buffer:
    sfetch_send(&(sfetch_request_t){
        .path = "hello_world.txt",
        .callback = response_callback
        .buffer_ptr = buffer,
        .buffer_size = sizeof(buffer)
    });
}

// per frame...
static void frame(void) {
    ...
    // need to call sfetch_dowork() once per frame to 'turn the gears':
    sfetch_dowork();
    ...
}

// the response callback is where the interesting stuff happens:
static void response_callback(const sfetch_response_t* response) {
    if (response->fetched) {
        // data has been loaded into the provided buffer, do something
        // with the data...
        const void* data = response->buffer_ptr;
        uint64_t data_size = response->fetched_size;
    }
    // the finished flag is set both on success and failure
    if (response->failed) {
        // oops, something went wrong
        switch (response->error_code) {
            SFETCH_ERROR_FILE_NOT_FOUND: ...
            SFETCH_ERROR_BUFFER_TOO_SMALL: ...
            ...
        }
    }
}

// application shutdown
static void shutdown(void) {
    ...
    sfetch_shutdown();
    ...
}

sokol_time.h:

Simple cross-platform time measurement:

#include "sokol_time.h"
...
/* initialize sokol_time */
stm_setup();

/* take start timestamp */
uint64_t start = stm_now();

...some code to measure...

/* compute elapsed time */
uint64_t elapsed = stm_since(start);

/* convert to time units */
double seconds = stm_sec(elapsed);
double milliseconds = stm_ms(elapsed);
double microseconds = stm_us(elapsed);
double nanoseconds = stm_ns(elapsed);

/* difference between 2 time stamps */
uint64_t start = stm_now();
...
uint64_t end = stm_now();
uint64_t elapsed = stm_diff(end, start);

/* compute a 'lap time' (e.g. for fps) */
uint64_t last_time = 0;
while (!done) {
    ...render something...
    double frame_time_ms = stm_ms(stm_laptime(&last_time));
}

sokol_args.h

Unified argument parsing for web and native apps. Uses argc/argv on native platforms and the URL query string on the web.

Example URL with one arg:

https://floooh.github.io/tiny8bit/kc85.html?type=kc85_4

The same as command line app:

kc85 type=kc85_4

Parsed like this:

#include "sokol_args.h"

int main(int argc, char* argv[]) {
    sargs_setup(&(sargs_desc){ .argc=argc, .argv=argv });
    if (sargs_exists("type")) {
        if (sargs_equals("type", "kc85_4")) {
            // start as KC85/4
        }
        else if (sargs_equals("type", "kc85_3")) {
            // start as KC85/3
        }
        else {
            // start as KC85/2
        }
    }
    sargs_shutdown();
    return 0;
}

See the sokol_args.h header for a more complete documentation, and the Tiny Emulators for more interesting usage examples.

sokol's People

Contributors

albertofustinoni avatar allcreater avatar amerkoleci avatar angluca avatar caiiiycuk avatar castano avatar cedric-h avatar code-disaster avatar danielchasehooper avatar dtrebilco avatar edubart avatar elloramir avatar floooh avatar garettbass avatar gustavolsson avatar ibob avatar incrediblejr avatar jakubtomsu avatar kassane avatar kcbanner avatar martincohen avatar mattiasljungstrom avatar nyalloc avatar oviano avatar pplux avatar prime31 avatar randygaul avatar trace-andreason avatar waywardmonkeys avatar zoo-3d avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sokol's Issues

Nuklear example

Would be nice to have a nuklear example (instead or over imgui), since nuklear and sokol are C while imgui is C++.

sokol_app.h: text input handling on mobile HTML5

Problems in the current implementation:

  • on iOS11 (Safari) and Android (Chrome) mobile phones, the canvas is zoomed when the onscreen keyboard is opened (and not restored to the original size when the keyboard closes)
  • on Android, no character input is detected from the keyboard, Backspace seems to work
  • all sorts of breakage on iOS12 Beta 3 (after opening the keyboard once):
    • changing between portrait and landscape doesn't seem to change the horizontal pixel resolution, only the vertical
    • changing between portrait and landscape doesn't get reported to emscripten
    • when opening the keyboard, the canvas is squished vertically

Context-lost-handling for WebGL

This should go into "v1.1".

  • when this happens, put all resources into a new "SG_RESOURCESTATE_LOST"
  • also set a global sokol_gfx 'lost flag'
  • silently skip all rendering operation when in lost state
  • have a D3D9-style function pair to check for lost-flag, and a reset function to notify sokol_gfx that the lost state has been handled
  • app-code needs to call the "sg_init_xxx()" functions to re-initialize resources
  • resource handles and relationships will all be preserved

image and render pass issues

  • a depth render buffer should be a normal image object, not included in another image
  • GL: the MSAA resolve render buffer should probably go into the render pass object

Backend state inconsistencies and missing states

  • Metal doesn't seem to have a scissor-test-enabled state, consider removing this from the sokol API (scissor test would always be enabled, and the scissor rect would be reset in sg_begin_pass)
  • texture anisotropy
  • depth bias / polygon offset
  • D3D11 doesn't have signed 10-10-10-2 vertex format, but unsigned version

vertex and uniform declaration issues

  • vertex layout definition should only happen in pipeline setup, not in shader setup (or only if required by backend API)
  • there should be 2 ways to define the vertex component location, which one is used depends on rendering backend and shader language dialect:
    • by name: sg_pipeline_setup_named_attr()
    • by slot index: sg_pipeline_setup_indexed_attr()
  • there must be several ways to describe uniform blocks in the shader setup:
    • per uniform, by name (traditional GL)
    • opaque uniform blocks (only useful with Metal, D3D11 or GL with shader-code-generation)
    • in general, shader setup should have different options depending on whether some sort of shader code generation is available, or shader setup needs to happen "manually"
  • vertex layout definition should have an explicit offset

Running out of resources when creating and destroying buffers with the Metal backend

I'm running into trouble when creating and destroying buffers (or pipelines) every frame with the Metal backend.

Here's a test case made by moving the vertex buffer creation from init to frame in the triangle-metal.c sample and destroying it after using it. After a few seconds it fires an assert:

Assertion failed: (_sg_mtl_free_queue_top > 0), function _sg_mtl_add_resource, file sokol/_sokol_gfx_metal.impl.h, line 379.

One possible error could be with the logic in _sg_mtl_garbage_collect, since it is called after every frame via sg_commit but seems to never process any of the resources in the release queue. Specifically, on line 413 it checks if frame index of the oldest resource is less than the current frame + inflight frames + 1, which should always be true if the frame index only increases and inflight frames is positive.

Make sokol C89 clean

On RaspberryPi with an older GCC (4.9.1) there are a lot of errors because of "for (int...)". If this is the only problem, it's worth it to make sokol_gfx.h C89 clean.

resource pools todo

Cleanup the 'item id 0 is reserved' stuff:

  • must allocate one more item then requested
  • size of the free-index queue is requested size, and doesn't have index 0 in it

Assert break in sokol_gfx init: Linux + glew 1.13

Hi
I'm on ubuntu with installed package glew 1.13.
I got assertion on the first _SG_GL_CHECK_ERROR(); in _sg_create_context function. because there was a pending GL error (GL_INVALID_ENUM)
It seems that the problem is with version 1.13 of glew documented here

So I had to reset the errors after glewInit. Is it ok if sokol_gfx clears errors on setup and throw a warning or something, in case if previous errors are raised by glew or similiar lib ?

Buffer offsets in sg_draw_state?

Add optional buffer offsets to sg_draw_state, this would allow to pack several things into the same buffer.

sg_draw_state ds = {
    .pipeline = pip;
    .vertex_buffers = {
        [0] = vbuf,
        [1] = vbuf,
    },
    .vertex_buffer_offsets = {
        [0] = 128,
        [1] = 2048,
    },
    .index_buffer = ibuf,
    .index_buffer_offset = 256,
    // ...
};

In GL, the offset would be applied during glVertexAttribPointer() calls, in D3D11 in IASetVertexBuffers() and IASetIndexBuffer(), and in Metal in [setVertexBuffer:offset:atIndex] and for indices in [drawIndexedPrimitives:...]

Oh, but it's still illlegal to put vertices and indices into the same buffer (because of WebGL), but this is already checked in _sg_validate_draw_state().

calling sg_reset_state_cache produces opengl error 0x502

Every frame I'm rendering I mix sokol with other opengl related libraries, not a good Idea I know, but sokol is supposed to handle that with sg_reset_state_cache, doesn't it?

the order is:

  1. render with sokol
  2. render with another_lib (nanovg)
  3. frame
  4. call sg_reset_state_cache
    --> something inside sg_reset_state_cache produces OpenGL error 0x502
  5. sokol refuses to render due to openGL error

If I clear openglErrors between 4 and 5, it works... but something is not right.

(Thanks for an awesome library, btw 👍 )

PD: The proper way is to implement a nanovg backend on top of soko_gfx, I know! Just need time.

[[point_size]] in msl

Not sure if this is really a Sokol problem but referencing
KhronosGroup/SPIRV-Cross#169
it does not seem to be a problem with Oryol?

So the problem is currently, if a msl defines the out struct of the vertex shader with a [point_size]

struct main0_out {
 float gl_PointSize [[point_size]]; // This by default is always in the compiled shader
};

Sokol/Metal complains: Compiler failed to build request
Vertex shader writes point size but inputPrimitiveTopology is MTLPrimitiveTopologyClassTriangle

Could this something specific to the Metal API Validation being enabled?
Currently fixed the problem in the spirv-cross compiler with "opts.point_size_compat = true" but thats not good solution.

Sokol fails to compile for SOKOL_GLES2

In the function _sg_create_context the line

SOKOL_ASSERT(0 == ctx->vao);

fails to compile when compiling with #define SOKOL_GLES2.

This is not surprising since we have

typedef struct {
    _sg_slot slot;
    #if !defined(SOKOL_GLES2)
    GLuint vao; 
    #endif
    GLuint default_framebuffer;
} _sg_context;

Should be an easy fix. Just a side question; this makes me feel that SOKOL_GLES3 is more tested. Are there maybe more issues related to vao for GLES2? Things seems to work and afaict the sokol-samples are compiled for GLES2...?

missing validations

  • sg_apply_draw_state: must check whether sample_count in pipeline matches current render pass sample count

pass vs pipeline validation

sg_apply_draw_state() must check:

  • if pipeline mrt_count matches pass number of color attachments
  • if pipeline color_format matches pass color attachments pixel format
  • if pipeline depth_format matches pass depth format
  • if pipeline sample count matches pass attachment sample count

GL backend todo

  • apply-draw-state: state caching for vertex attribute definition
  • apply-draw-state: bind textures
  • extension check, sg_query_feature(), instancing functions
  • error codes and messages
  • _sg_create_shader: resolve uniform and texture locations (named and 'opaque')
  • create image
  • create pass
  • query default frame buffer at start
  • MRT passes
  • draw-elements-instanced
  • cleanup resources on shutdown
  • viewport and scissor rect functions are totally missing

Visualize depth buffer

Hi, thanks for creating sokol, I find very refreshing working with it!
Question:
do you have somewhere a snippet of code or an example on how I can access/visualize the depth buffer?
I naively tried to attach the depth_image to a color attachment but it doesn't seem to work for me.

For example, in the offscreen-glow.c sample, if I modify the default draw state like this (around line 242):

    sg_draw_state default_ds = {
        .pipeline = default_pip,
        .vertex_buffers[0] = vbuf,
        .index_buffer = ibuf,
        .fs_images[0] = depth_img // was: "color_img"
    };

I see no difference in the generated output image.

Similarly, using the mrt-glfw.c sample, if I change the debug view in the main loop to also draw the depth, like this (around line345):

        sg_draw(0, 4, 1);
        for (int i = 0; i < 3; i++) {
            sg_apply_viewport(i*100, 0, 100, 100, false);
            dbg_ds.fs_images[0] = offscreen_pass_desc.color_attachments[i].image;
            sg_apply_draw_state(&dbg_ds);
            sg_draw(0, 4, 1);
        }
        for (int i = 3; i < 4; i++) {
            sg_apply_viewport(i*100, 0, 100, 100, false);
            dbg_ds.fs_images[0] = offscreen_pass_desc.depth_stencil_attachment.image;
            sg_apply_draw_state(&dbg_ds);
            sg_draw(0, 4, 1);
        }
        sg_end_pass();

what I get is a duplication of the last color attachment that has been bound (see the following screenshot).
screen shot 2018-03-26 at 7 00 37 am

Probably I'm trying to "map" my OpenGL mindset to Sokol, and doing something wrong.
Any suggestion on the right way to use the depth buffer in a shader?

thanks!

sokol_entry

I started a library thats similar to https://github.com/jimon/entrypoint
The point of it:

  • Support: Windows, OSX, IOS, Android, X11
  • provide an entrypoint for your application
  • lifetime events
  • window/drawing surface & basic setup for Metal/OpenGL/DX11/WebGL
  • provide touch, gamepad, keyboard, mouse ect.
  • dragNdrop for OSX/Windows/X11

Other features I want to add but I'm not sure about them, or maybe add it after a 1.0:

  • async IO
  • network primitives (http requests ect.)
  • Android/iOS shop integration
  • iOS GameCenter
  • DX12 & Vulkan entrypoints

So the way its used its pretty similar to your sokol samples, in fact these entry points there is what I started with.
Currently I'm implementing OSX and iOS, both supporting Metal & OpenGL (for OpenGL it looks like I still need something like glad)

So this is how your clear-metal looks now with sokol_entry, not much changed, in fact for OSX/iOS its mostly renaming...

//------------------------------------------------------------------------------
//  clear-metal.c
//------------------------------------------------------------------------------
#include "sokol_gfx.h"
#include "sokol_entry/sokol_entry.h"

sg_pass_action pass_action;

void init(const sg_gfx_init_data *data) {
    sg_desc desc = {
        .mtl_device = data->mtl_device,
        .mtl_renderpass_descriptor_cb = data->mtl_renderpass_descriptor_cb,
        .mtl_drawable_cb = data->mtl_drawable_cb
    };
    sg_setup(&desc);
    pass_action = (sg_pass_action) {
        .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 1.0f, 0.0f, 0.0f, 1.0f } }
    };
}
static bool wasFullscreen;
void frame() {
    sg_set_window_fullscreen(true);
    if (sg_is_window_fullscreen()) {
        wasFullscreen = true;
    }
    if (!sg_is_window_fullscreen() && wasFullscreen) {
        sg_quite();
    }
    
    /* animate clear colors */
    float g = pass_action.colors[0].val[1] + 0.01f;
    if (g > 1.0f) g = 0.0f;
    pass_action.colors[0].val[1] = g;

    /* draw one frame */
    sg_begin_default_pass(&pass_action, sg_get_window_width(), sg_get_window_width());
    sg_end_pass();
    sg_commit();
}

void shutdown() {
    sg_shutdown();
}

void sg_main() {
    sg_start(840, 480, 1, "Sokol Clear (Metal)", init, frame, shutdown);
}

So.. do you have interest in this? If not I will rename it to something else. Also any feedback is very welcome.

You can see my current WiP code here:
https://github.com/pjako/sokol/tree/entry/sokol_entry

Buffer Offsets TODO

  • D3D11 sample
  • Metal sample
  • emscripten sample
  • update Nim bindings
  • update samples webpage

sokol_gfx: Support for multiple contexts/windows

As far as I can see by the implementation, sokol_gfx can not support multiple windows/contexts. Maybe it is just a matter of storing the _sg_backend object and restoring it with a reset_state_cache call between contexts.

Road to v1.0

  • validation for sg_update_buffer()
  • validation for sg_update_image()
  • WebGL2->WebGL fallback
  • 10-10-10-2 vertex format inconsistency (D3D11 only has unsigned format)
  • remove scissor_test_enabled, must be always enabled (Metal doesn't have that)
  • reset scissor rect to full render target size at start of pass
  • depth-bias stuff, need to check if there's a common ground for GL, D3D11, Metal
  • depth_clip_enabled(?) not supported by GLES2/WebGL or GLES3/WebGL2
  • antialiased_line_enabled(?) not supported on Metal, and with many caveats on D3D11
  • max_anisotropy (sampler state, so needs to go into sg_image_desc)
  • sampler state min_lod, max_lod, mip_lod_bias(?) mip_lod_bias as render state is only in D3D11, min_lod/max_lod is not in GLES2/WebGL (just ignore it there)
  • allow use of externally created "native" D3D11, GL and Metal buffer and image resources
  • Metal samples for iOS

OPTIONAL:

  • RaspberryPi2 samples

sokol_app: Compile error on MSVC + cl

when building with cpp cl compiler, I get error in sokol_app.h, line 2873:

1>error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

here's the place where it happens (function: _sapp_d3d11_destroy_device_and_swapchain):

_SOKOL_PRIVATE _sapp_d3d11_destroy_device_and_swapchain(void) {
    _SAPP_SAFE_RELEASE(IDXGISwapChain, _sapp_dxgi_swap_chain);
    _SAPP_SAFE_RELEASE(ID3D11DeviceContext, _sapp_d3d11_device_context);
    _SAPP_SAFE_RELEASE(ID3D11Device, _sapp_d3d11_device);
}

I guess inserting void on the beginning of the declaration solved the problem

content initialization/update for immutable buffers and images

  • rename 'data_ptr' to 'content' everywhere
  • in sg_image_desc, replace the data pointer-pointers with a simple 2D array (faces and mipmaps), this is ok since 2D-array-slices and 3D-texture-slices are provided 'en-bloc', and not through unique pointers
  • define a new sg_image_content struct for sg_update_image() which holds the subimage pointers and sizes (would make sense to use this also embedded in the sg_image_desc struct)

Failed assertion with texture samples in the metal backend

When running the sapp dear imgui sample with xcode/metal the app crashes. The strange thing is that it worked a day ago with no problem...

2018-05-30 15:32:49.223915+0200 imgui-sapp[1812:27662] [DYMTLInitPlatform] platform initialization successful
2018-05-30 15:32:49.461297+0200 imgui-sapp[1812:27593] Metal GPU Frame Capture Enabled
2018-05-30 15:32:49.461684+0200 imgui-sapp[1812:27593] Metal API Validation Enabled
2018-05-30 15:32:49.739457+0200 imgui-sapp[1812:27684] MessageTracer: Falling back to default whitelist
2018-05-30 15:32:50.341674+0200 imgui-sapp[1812:27593] -[MTLTextureDescriptorInternal validateWithDevice:], line 832: error 'MTLTextureDescriptor has sampleCount set but is using a type that does not allow sampleCount.'
-[MTLTextureDescriptorInternal validateWithDevice:]:832: failed assertion `MTLTextureDescriptor has sampleCount set but is using a type that does not allow sampleCount.'

images should not be baked into pass object

The pass object should only have the minimally required information baked in (number of attachments, and their types - check Vulkan and D3D12 for exact requirements), and the actual render target image ids should be provided in the 'dynamic' sg_pass_action (probably would make sense to rename this struct then to something else).

Define uniforms with introspection.

Why are uniforms in sg_shader_uniform_block_desc set manually ?
Maybe the could be set automatically during the compilation of the shader with introspection ?

Thank you in advance.

Non-interleaved vertex data

Hi,

First of all, thanks so much for the library!
I am currently learning how to use it by writing a simple mesh-viewer application, however I am running into trouble when submitting my vertex data. In my application I am keeping my vertex positions and vertex normals as separate buffers, however all examples showcase interleaved vertex data.

Is there a way to inform sokol about non-interleaved vertex data? (VVVNNN) vs (VNVNVN)

OpenGL pseudocode snipped to show what I am trying to achieve:

    glBufferSubData( GL_ARRAY_BUFFER, 0, mesh->n_vertices*3*sizeof(float), &(mesh->positions[0]) );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    glBufferSubData( GL_ARRAY_BUFFER,  3 * sizeof(float) * mesh->n_vertices, 3 * sizeof(float) * mesh->n_vertices, &(mesh->normals[0]) );
    glEnableVertexAttribArray( 1 );
    glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, (void*) ( 3 * sizeof(float) * mesh->n_vertices) );

Shader reuse over multiple models

Nice API!

I would like to set up soko with one shader setup and render multiple models(verts/index date) with the same format.
I've probably missed something really obvious, but I can't see a way to do this?
I see SG_MAX_SHADERSTAGE_BUFFERS is set to 4 and streaming data via sg_update_buffer is also limited to "... only one update allowed per frame and resource object, and data must be written from the start (but the data size can be smaller than the resource size)."

Any help would be great :)
Cheers
Mike.

Framebuffer Ping-Ponging

Hello,

A common way to implement the gaussian blur in OpenGL/GLSL is to setup ping-ponging framebuffers and apply horizontal and vertical blurs with fixed width kernel repeatedly (ref).

Attempting to implement such setup in sokol seems to be quite tricky. While it is possible to change the input texture by setting .fs_images[i] variable of sg_draw_state object, it seems to be impossible to change the output framebuffer, as it is only set when creating sg_pass object, and setting color attachements. As such I don't really see a way to setup buffer ping-ponging in sokol, other than a) injecting openGL or b) creating and destroying pass object on the fly.

My questions are then - have I missed anything and there is in fact a way to set up the ping-ponging framebuffer? Otherwise, given that buffer ping-ponging is relatively common operation, should it be possible to express that operation in sokol without injecting gl code.

Thanks!

Updating buffers more than once per frame

Hi,

Is there any reason for one update per frame restriction?

I'm implementing a sprite batch using sokol_gfx. A common pattern for this (such as in FNA) is to instantiate a fixed-size array which stores all the vertices and indices of the sprites, and if the user provides more sprites, the sprites are drawn, and the buffers reused for more sprites in the same frame.

Sticking to one buffer update per frame would force me to have a large upper bound on number of sprites which wastes memory, or using heap allocated memory, which is bad for cache.

Removing SOKOL_ASSERT(buf->upd_frame_index != _sg.frame_index); from sg_update_buffer simply works for me. So I'm curious to know what your reasons for this are.

EDIT: This is the code if you're interested in how I'm using sokol_gfx: https://github.com/sherjilozair/sokol2d/blob/master/sokol2d.h#L347

Test, please ignore

sokol/sokol_gfx.h

Lines 375 to 392 in 2070f2b

typedef enum {
SG_FEATURE_INSTANCING,
SG_FEATURE_TEXTURE_COMPRESSION_DXT,
SG_FEATURE_TEXTURE_COMPRESSION_PVRTC,
SG_FEATURE_TEXTURE_COMPRESSION_ATC,
SG_FEATURE_TEXTURE_COMPRESSION_ETC2,
SG_FEATURE_TEXTURE_FLOAT,
SG_FEATURE_TEXTURE_HALF_FLOAT,
SG_FEATURE_ORIGIN_BOTTOM_LEFT,
SG_FEATURE_ORIGIN_TOP_LEFT,
SG_FEATURE_MSAA_RENDER_TARGETS,
SG_FEATURE_PACKED_VERTEX_FORMAT_10_2,
SG_FEATURE_MULTIPLE_RENDER_TARGET,
SG_FEATURE_IMAGETYPE_3D,
SG_FEATURE_IMAGETYPE_ARRAY,
SG_NUM_FEATURES
} sg_feature;

protection against uninitialized structs

It's easy to forget calling the sg_init_* functions to initialize structs. Solution: add a magic cookie field that's set in the sg_init functions, and check for the correct magic value when the struct is inspected.

Image Export

Hi Andre,
I use sokol since few weeks and (for now) I think the only missing feature is the export of image to CPU side.
I don't known if this request is compatible with Metal and GLES API but I think it's Ok for DX11 and OpenGL.
And maybe you don't want to add new feature to your lib?
Anyway, thanks for this awesome little and simple lib.

Split into .c and .h files

when the .h file is referenced from multiple .c files, compilation performance suffers (on low-end devices: ARM, lowend x86/x64, ...) as well as IDE performance. Splitting it to .c and .h files would reduce that enormously.

PROS:

  • Compilation Time
  • Linting/intellisense performance
  • Ability to package sokol into a shared library
  • Reduce readability overhead
  • Having a shared library, makes it easy to make wrappers for other languages

If you still have to do that, you can include one intermediate header file that include both .c and .h files

Note: Nuklear started by having a header only file, then ended up doing the split

sokol_app: Can't compile with d3d11 + cpp

I'm trying to build sokol_app in a cpp file, but I can't get it done without cl complaining ...

file: d3d11.h , line: 1128

error C2733: 'operator ==': second C linkage of overloaded function not allowed

this is fixed with defining D3D11_NO_HELPERS before including sokol_app.h

But these errors :

error C3861: 'ID3D11DeviceContext_Release': identifier not found
error C3861: 'ID3D11Device_Release': identifier not found
error C3861: 'IDXGISwapChain_GetBuffer': identifier not found
error C3861: 'ID3D11Device_CreateRenderTargetView': identifier not found
error C3861: 'ID3D11Device_CreateTexture2D': identifier not found
error C3861: 'ID3D11Device_CreateDepthStencilView': identifier not found
error C3861: 'ID3D11Texture2D_Release': identifier not found
error C3861: 'ID3D11RenderTargetView_Release': identifier not found
error C3861: 'ID3D11Texture2D_Release': identifier not found
error C3861: 'ID3D11DepthStencilView_Release': identifier not found
error C3861: 'IDXGISwapChain_ResizeBuffers': identifier not found
error C3861: 'IDXGISwapChain_Present': identifier not found

still exist, and I can't get rid of them because the code is disabled in __cplusplus. By inspecting dxgi.h, I defined CINTERFACE and the code is enabled again, but this error shows up:

sokol_app.h(2881): error C2664: 'HRESULT (IDXGISwapChain *,UINT,const IID &,void **)': cannot convert argument 3 from 'const IID *' to 'const IID &'

So I had to add another __cplusplus case for this issue to fix:

#ifdef __cplusplus
    hr = IDXGISwapChain_GetBuffer(_sapp_dxgi_swap_chain, 0, IID_ID3D11Texture2D, (void**)&_sapp_d3d11_rt);
#else
    hr = IDXGISwapChain_GetBuffer(_sapp_dxgi_swap_chain, 0, &IID_ID3D11Texture2D, (void**)&_sapp_d3d11_rt);
#endif

PS. there is also a minor performance warning in msvc that is raised and not really important but I though I'd let you know:

warning C4800: 'const char *const ': forcing value to bool 'true' or 'false' (performance warning)

in SOKOL_VALIDATE , sokol_gfx.h (8092)

Cleanly separate the GL3.3, GLES2 and GLES3 backends variations.

The GL backend variations are currently "leaking" into each other, e.g. the GLES2 backend is using functionality that isn't actually available in GLES2.

  • if SOKOL_GLES2 is set, only use GLES2 functionality
  • same for GLES3
  • provide the ability to fallback to GLES2 if GLES3 could not be initialized (for WebGL2 vs WebGL)
  • ...on emscripten with WebGL1, use the proper GLES2 emscripten headers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.