diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ba189f4b6..9f03d464eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,8 +190,8 @@ jobs: - name: Shader examples can be build run: | - wget https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz - tar -xf pre-feb2021-api-changes.tar.gz + wget https://github.com/floooh/sokol-tools-bin/raw/master/bin/linux/sokol-shdc + chmod +x ./sokol-shdc for f in examples/sokol/02_cubes_glsl/cube_glsl \ examples/sokol/03_march_tracing_glsl/rt_glsl \ examples/sokol/04_multi_shader_glsl/rt_glsl_puppy \ @@ -200,7 +200,7 @@ jobs: examples/sokol/06_obj_viewer/gouraud \ ; do \ echo "compiling shader $f.glsl ..."; \ - sokol-tools-bin-pre-feb2021-api-changes/bin/linux/sokol-shdc --input $f.glsl --output $f.h --slang glsl330 ; \ + ./sokol-shdc --input $f.glsl --output $f.h --slang glsl330 ; \ done for vfile in examples/sokol/0?*/*.v; do echo "compiling $vfile ..."; ./v $vfile ; done diff --git a/examples/sokol/01_cubes/cube.v b/examples/sokol/01_cubes/cube.v index 66034cabce..e0e3803777 100644 --- a/examples/sokol/01_cubes/cube.v +++ b/examples/sokol/01_cubes/cube.v @@ -54,9 +54,9 @@ fn create_texture(w int, h int, buf &byte) C.sg_image { d3d11_texture: 0 } // commen if .dynamic is enabled - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } sg_img := C.sg_make_image(&img_desc) @@ -70,10 +70,10 @@ fn destroy_texture(sg_img C.sg_image) { // Use only if usage: .dynamic is enabled fn update_text_texture(sg_img C.sg_image, w int, h int, buf &byte) { sz := w * h * 4 - mut tmp_sbc := C.sg_image_content{} - tmp_sbc.subimage[0][0] = C.sg_subimage_content{ + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } C.sg_update_image(sg_img, &tmp_sbc) } @@ -323,16 +323,21 @@ fn my_init(mut app App) { // 3d pipeline mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } - pipdesc.blend.enabled = true - pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) - pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) + + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .back + pipdesc.colors[0] = color_state + + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back app.pip_3d = sgl.make_pipeline(&pipdesc) // create chessboard texture 256*256 RGBA diff --git a/examples/sokol/02_cubes_glsl/cube_glsl.v b/examples/sokol/02_cubes_glsl/cube_glsl.v index b60f864ae4..9dd1653f32 100644 --- a/examples/sokol/02_cubes_glsl/cube_glsl.v +++ b/examples/sokol/02_cubes_glsl/cube_glsl.v @@ -43,7 +43,7 @@ import gg.m4 #flag -I @VROOT/. #include "cube_glsl.h" #Please use sokol-shdc to generate the necessary cube_glsl.h file from cube_glsl.glsl (see the instructions at the top of this file) -fn C.cube_shader_desc() &C.sg_shader_desc +fn C.cube_shader_desc(gfx.Backend) &C.sg_shader_desc const ( win_width = 800 @@ -87,9 +87,9 @@ fn create_texture(w int, h int, buf &byte) C.sg_image { d3d11_texture: 0 } // comment if .dynamic is enabled - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } sg_img := C.sg_make_image(&img_desc) @@ -103,10 +103,10 @@ fn destroy_texture(sg_img C.sg_image) { // Use only if usage: .dynamic is enabled fn update_text_texture(sg_img C.sg_image, w int, h int, buf &byte) { sz := w * h * 4 - mut tmp_sbc := C.sg_image_content{} - tmp_sbc.subimage[0][0] = C.sg_subimage_content{ + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } C.sg_update_image(sg_img, &tmp_sbc) } @@ -295,8 +295,13 @@ fn init_cube_glsl(mut app App) { mut vert_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) } - vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t)) - vert_buffer_desc.content = &byte(vertices.data) + + vert_buffer_desc.size = size_t(vertices.len * int(sizeof(Vertex_t))) + vert_buffer_desc.data = C.sg_range{ + ptr: vertices.data + size: size_t(vertices.len * int(sizeof(Vertex_t))) + } + vert_buffer_desc.@type = .vertexbuffer // vert_buffer_desc.usage = .immutable vert_buffer_desc.label = 'cube-vertices'.str @@ -314,14 +319,19 @@ fn init_cube_glsl(mut app App) { mut index_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) } - index_buffer_desc.size = indices.len * int(sizeof(u16)) - index_buffer_desc.content = &byte(indices.data) + + index_buffer_desc.size = size_t(indices.len * int(sizeof(u16))) + index_buffer_desc.data = C.sg_range{ + ptr: indices.data + size: size_t(indices.len * int(sizeof(u16))) + } + index_buffer_desc.@type = .indexbuffer index_buffer_desc.label = 'cube-indices'.str ibuf := gfx.make_buffer(&index_buffer_desc) // create shader - shader := gfx.make_shader(C.cube_shader_desc()) + shader := gfx.make_shader(C.cube_shader_desc(C.sg_query_backend())) mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } @@ -336,13 +346,12 @@ fn init_cube_glsl(mut app App) { pipdesc.shader = shader pipdesc.index_type = .uint16 - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) - } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .back + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back + pipdesc.label = 'glsl_shader pipeline'.str app.cube_bind.vertex_buffers[0] = vbuf @@ -376,7 +385,11 @@ fn draw_cube_glsl(app App) { //*************** // passing the view matrix as uniform // res is a 4x4 matrix of f32 thus: 4*16 byte of size - gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &tr_matrix, 4 * 16) + vs_uniforms_range := C.sg_range{ + ptr: &tr_matrix + size: size_t(4 * 16) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &vs_uniforms_range) // fs uniforms time_ticks := f32(time.ticks() - app.ticks) / 1000 @@ -386,7 +399,11 @@ fn draw_cube_glsl(app App) { time_ticks, /* time as f32 */ 0 /* padding 4 Bytes == 1 f32 */, ]! - gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &text_res, 4 * 4) + fs_uniforms_range := C.sg_range{ + ptr: &text_res + size: size_t(4 * 4) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range) gfx.draw(0, (3 * 2) * 6, 1) gfx.end_pass() @@ -461,11 +478,13 @@ fn frame(mut app App) { // clear mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_DONTCARE) // C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 1.0 + g: 1.0 + b: 1.0 + a: 1.0 + } } - color_action.val[0] = 1 - color_action.val[1] = 1 - color_action.val[2] = 1 - color_action.val[3] = 1.0 mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action gfx.begin_default_pass(&pass_action, ws.width, ws.height) @@ -494,16 +513,22 @@ fn my_init(mut app App) { // 3d pipeline mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } - pipdesc.blend.enabled = true - pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) - pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) + + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .back + pipdesc.colors[0] = color_state + + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back + app.pip_3d = sgl.make_pipeline(&pipdesc) // create chessboard texture 256*256 RGBA diff --git a/examples/sokol/03_march_tracing_glsl/rt_glsl.v b/examples/sokol/03_march_tracing_glsl/rt_glsl.v index 9306a6c2d7..4e578d2946 100644 --- a/examples/sokol/03_march_tracing_glsl/rt_glsl.v +++ b/examples/sokol/03_march_tracing_glsl/rt_glsl.v @@ -44,7 +44,7 @@ import time #flag -I @VROOT/. #include "rt_glsl.h" #Please use sokol-shdc to generate the necessary rt_glsl.h file from rt_glsl.glsl (see the instructions at the top of this file) -fn C.rt_shader_desc() &C.sg_shader_desc +fn C.rt_shader_desc(gfx.Backend) &C.sg_shader_desc const ( win_width = 800 @@ -86,9 +86,9 @@ fn create_texture(w int, h int, buf &byte) C.sg_image { d3d11_texture: 0 } // comment if .dynamic is enabled - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } sg_img := C.sg_make_image(&img_desc) @@ -102,10 +102,10 @@ fn destroy_texture(sg_img C.sg_image) { // Use only if usage: .dynamic is enabled fn update_text_texture(sg_img C.sg_image, w int, h int, buf &byte) { sz := w * h * 4 - mut tmp_sbc := C.sg_image_content{} - tmp_sbc.subimage[0][0] = C.sg_subimage_content{ + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } C.sg_update_image(sg_img, &tmp_sbc) } @@ -174,8 +174,13 @@ fn init_cube_glsl(mut app App) { mut vert_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) } - vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t)) - vert_buffer_desc.content = &byte(vertices.data) + + vert_buffer_desc.size = size_t(vertices.len * int(sizeof(Vertex_t))) + vert_buffer_desc.data = C.sg_range{ + ptr: vertices.data + size: size_t(vertices.len * int(sizeof(Vertex_t))) + } + vert_buffer_desc.@type = .vertexbuffer vert_buffer_desc.label = 'cube-vertices'.str vbuf := gfx.make_buffer(&vert_buffer_desc) @@ -192,14 +197,19 @@ fn init_cube_glsl(mut app App) { mut index_buffer_desc := C.sg_buffer_desc{} unsafe {C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc))} - index_buffer_desc.size = indices.len * int(sizeof(u16)) - index_buffer_desc.content = &byte(indices.data) + + index_buffer_desc.size = size_t(indices.len * int(sizeof(u16))) + index_buffer_desc.data = C.sg_range{ + ptr: indices.data + size: size_t(indices.len * int(sizeof(u16))) + } + index_buffer_desc.@type = .indexbuffer index_buffer_desc.label = "cube-indices".str ibuf := gfx.make_buffer(&index_buffer_desc) - + // create shader - shader := gfx.make_shader(C.rt_shader_desc()) + shader := gfx.make_shader(C.rt_shader_desc(C.sg_query_backend())) mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } @@ -214,13 +224,12 @@ fn init_cube_glsl(mut app App) { pipdesc.shader = shader pipdesc.index_type = .uint16 - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) - } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .back + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back + pipdesc.label = 'glsl_shader pipeline'.str app.cube_bind.vertex_buffers[0] = vbuf @@ -230,7 +239,7 @@ fn init_cube_glsl(mut app App) { println('GLSL init DONE!') } -[inline] +[inline] fn vec4(x f32, y f32, z f32, w f32) m4.Vec4 { return m4.Vec4{e:[x, y, z, w]!} } @@ -274,7 +283,11 @@ fn draw_cube_glsl(app App) { // *** vertex shadeer uniforms *** // passing the view matrix as uniform // res is a 4x4 matrix of f32 thus: 4*16 byte of size - gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &tr_matrix, 4 * 16) + vs_uniforms_range := C.sg_range{ + ptr: &tr_matrix + size: size_t(4 * 16) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &vs_uniforms_range) // *** fragment shader uniforms *** time_ticks := f32(time.ticks() - app.ticks) / 1000 @@ -286,9 +299,13 @@ fn draw_cube_glsl(app App) { time_ticks, // time as f32 app.frame_count, // frame count 0, - 0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h + 0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h ]! - gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &tmp_fs_params, int(sizeof(tmp_fs_params))) + fs_uniforms_range := C.sg_range{ + ptr: &tmp_fs_params + size: size_t(sizeof(tmp_fs_params)) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range) // 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw gfx.draw(0, (3 * 2) * 6, 1) @@ -302,11 +319,14 @@ fn frame(mut app App) { // clear mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 0.0 + g: 0.0 + b: 0.0 + a: 1.0 + } } - color_action.val[0] = 0 - color_action.val[1] = 0 - color_action.val[2] = 0 - color_action.val[3] = 1.0 + mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action gfx.begin_default_pass(&pass_action, ws.width, ws.height) diff --git a/examples/sokol/04_multi_shader_glsl/rt_glsl.v b/examples/sokol/04_multi_shader_glsl/rt_glsl.v index f109e73d03..046afef73e 100644 --- a/examples/sokol/04_multi_shader_glsl/rt_glsl.v +++ b/examples/sokol/04_multi_shader_glsl/rt_glsl.v @@ -45,8 +45,8 @@ import time #flag -I @VROOT/. #include "rt_glsl_march.h" #Please use sokol-shdc to generate the necessary rt_glsl_march.h file from rt_glsl_march.glsl (see the instructions at the top of this file) #include "rt_glsl_puppy.h" #Please use sokol-shdc to generate the necessary rt_glsl_puppy.h file from rt_glsl_puppy.glsl (see the instructions at the top of this file) -fn C.rt_march_shader_desc() &C.sg_shader_desc -fn C.rt_puppy_shader_desc() &C.sg_shader_desc +fn C.rt_march_shader_desc(gfx.Backend) &C.sg_shader_desc +fn C.rt_puppy_shader_desc(gfx.Backend) &C.sg_shader_desc const ( win_width = 800 @@ -90,9 +90,9 @@ fn create_texture(w int, h int, buf byteptr) C.sg_image { d3d11_texture: 0 } // comment if .dynamic is enabled - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } sg_img := C.sg_make_image(&img_desc) @@ -106,10 +106,10 @@ fn destroy_texture(sg_img C.sg_image) { // Use only if usage: .dynamic is enabled fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr) { sz := w * h * 4 - mut tmp_sbc := C.sg_image_content{} - tmp_sbc.subimage[0][0] = C.sg_subimage_content{ + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } C.sg_update_image(sg_img, &tmp_sbc) } @@ -178,8 +178,11 @@ fn init_cube_glsl_m(mut app App) { mut vert_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) } - vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t)) - vert_buffer_desc.content = byteptr(vertices.data) + vert_buffer_desc.size = size_t(vertices.len * int(sizeof(Vertex_t))) + vert_buffer_desc.data = C.sg_range{ + ptr: vertices.data + size: size_t(vertices.len * int(sizeof(Vertex_t))) + } vert_buffer_desc.@type = .vertexbuffer vert_buffer_desc.label = 'cube-vertices'.str vbuf := gfx.make_buffer(&vert_buffer_desc) @@ -198,14 +201,17 @@ fn init_cube_glsl_m(mut app App) { mut index_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) } - index_buffer_desc.size = indices.len * int(sizeof(u16)) - index_buffer_desc.content = byteptr(indices.data) + index_buffer_desc.size = size_t(indices.len * int(sizeof(u16))) + index_buffer_desc.data = C.sg_range{ + ptr: indices.data + size: size_t(indices.len * int(sizeof(u16))) + } index_buffer_desc.@type = .indexbuffer index_buffer_desc.label = 'cube-indices'.str ibuf := gfx.make_buffer(&index_buffer_desc) // create shader - shader := gfx.make_shader(C.rt_march_shader_desc()) + shader := gfx.make_shader(C.rt_march_shader_desc(C.sg_query_backend())) mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } @@ -220,13 +226,11 @@ fn init_cube_glsl_m(mut app App) { pipdesc.shader = shader pipdesc.index_type = .uint16 - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) - } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .back + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back pipdesc.label = 'glsl_shader pipeline'.str mut bind := C.sg_bindings{} @@ -282,8 +286,11 @@ fn init_cube_glsl_p(mut app App) { mut vert_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) } - vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t)) - vert_buffer_desc.content = byteptr(vertices.data) + vert_buffer_desc.size = size_t(vertices.len * int(sizeof(Vertex_t))) + vert_buffer_desc.data = C.sg_range{ + ptr: vertices.data + size: size_t(vertices.len * int(sizeof(Vertex_t))) + } vert_buffer_desc.@type = .vertexbuffer vert_buffer_desc.label = 'cube-vertices'.str vbuf := gfx.make_buffer(&vert_buffer_desc) @@ -303,14 +310,17 @@ fn init_cube_glsl_p(mut app App) { mut index_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) } - index_buffer_desc.size = indices.len * int(sizeof(u16)) - index_buffer_desc.content = byteptr(indices.data) + index_buffer_desc.size = size_t(indices.len * int(sizeof(u16))) + index_buffer_desc.data = C.sg_range{ + ptr: indices.data + size: size_t(indices.len * int(sizeof(u16))) + } index_buffer_desc.@type = .indexbuffer index_buffer_desc.label = 'cube-indices'.str ibuf := gfx.make_buffer(&index_buffer_desc) // create shader - shader := gfx.make_shader(C.rt_puppy_shader_desc()) + shader := gfx.make_shader(C.rt_puppy_shader_desc(C.sg_query_backend())) mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } @@ -325,13 +335,12 @@ fn init_cube_glsl_p(mut app App) { pipdesc.shader = shader pipdesc.index_type = .uint16 - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) - } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .back + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back + pipdesc.label = 'glsl_shader pipeline'.str mut bind := C.sg_bindings{} @@ -346,7 +355,7 @@ fn init_cube_glsl_p(mut app App) { println('GLSL Puppy init DONE!') } -[inline] +[inline] fn vec4(x f32, y f32, z f32, w f32) m4.Vec4 { return m4.Vec4{e:[x, y, z, w]!} } @@ -387,7 +396,11 @@ fn draw_cube_glsl_m(app App) { // *** vertex shadeer uniforms *** // passing the view matrix as uniform // res is a 4x4 matrix of f32 thus: 4*16 byte of size - gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_m, &tr_matrix, 4 * 16) + vs_uniforms_range := C.sg_range{ + ptr: &tr_matrix + size: size_t(4 * 16) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_m, &vs_uniforms_range) // *** fragment shader uniforms *** time_ticks := f32(time.ticks() - app.ticks) / 1000 @@ -403,7 +416,11 @@ fn draw_cube_glsl_m(app App) { 0, 0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h ]! - gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_m, &tmp_fs_params, int(sizeof(tmp_fs_params))) + fs_uniforms_range := C.sg_range{ + ptr: &tmp_fs_params + size: size_t(sizeof(tmp_fs_params)) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_p, &fs_uniforms_range) // 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw gfx.draw(0, (3 * 2) * 3, 1) @@ -431,7 +448,11 @@ fn draw_cube_glsl_p(app App) { // *** vertex shadeer uniforms *** // passing the view matrix as uniform // res is a 4x4 matrix of f32 thus: 4*16 byte of size - gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_p, &tr_matrix, 4 * 16) + vs_uniforms_range := C.sg_range{ + ptr: &tr_matrix + size: size_t(4 * 16) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_p, &vs_uniforms_range) // *** fragment shader uniforms *** time_ticks := f32(time.ticks() - app.ticks) / 1000 @@ -447,7 +468,11 @@ fn draw_cube_glsl_p(app App) { 0, 0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h ]! - gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_p, &tmp_fs_params, int(sizeof(tmp_fs_params))) + fs_uniforms_range := C.sg_range{ + ptr: &tmp_fs_params + size: size_t(sizeof(tmp_fs_params)) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_p, &fs_uniforms_range) // 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw gfx.draw(0, (3 * 2) * 3, 1) @@ -477,11 +502,13 @@ fn frame(mut app App) { // clear mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 0.0 + g: 0.0 + b: 0.0 + a: 1.0 + } } - color_action.val[0] = 0 - color_action.val[1] = 0 - color_action.val[2] = 0 - color_action.val[3] = 1.0 mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action gfx.begin_default_pass(&pass_action, ws.width, ws.height) diff --git a/examples/sokol/05_instancing_glsl/rt_glsl.v b/examples/sokol/05_instancing_glsl/rt_glsl.v index 71dc849b58..639a9ea065 100644 --- a/examples/sokol/05_instancing_glsl/rt_glsl.v +++ b/examples/sokol/05_instancing_glsl/rt_glsl.v @@ -12,7 +12,7 @@ * - compile the .glsl shared file with: * linux : sokol-shdc --input rt_glsl_instancing.glsl --output rt_glsl_instancing.h --slang glsl330 * windows: sokol-shdc.exe --input rt_glsl_instancing.glsl --output rt_glsl_instancing.h --slang glsl330 -* +* * --slang parameter can be: * - glsl330: desktop GL * - glsl100: GLES2 / WebGL @@ -57,20 +57,20 @@ mut: mouse_x int = -1 mouse_y int = -1 mouse_down bool - + // glsl cube_pip_glsl C.sg_pipeline cube_bind C.sg_bindings - + pipe map[string]C.sg_pipeline bind map[string]C.sg_bindings - + // time ticks i64 - + // instances inst_pos [num_inst]m4.Vec4 - + // camera camera_x f32 camera_z f32 @@ -81,7 +81,7 @@ mut: ******************************************************************************/ #flag -I @VROOT/. #include "rt_glsl_instancing.h" #Please use sokol-shdc to generate the necessary rt_glsl_march.h file from rt_glsl_march.glsl (see the instructions at the top of this file) -fn C.instancing_shader_desc() &C.sg_shader_desc +fn C.instancing_shader_desc(gfx.Backend) &C.sg_shader_desc /****************************************************************************** * Texture functions @@ -101,9 +101,9 @@ fn create_texture(w int, h int, buf byteptr) C.sg_image{ d3d11_texture: 0 } // comment if .dynamic is enabled - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } sg_img := C.sg_make_image(&img_desc) @@ -117,10 +117,10 @@ fn destroy_texture(sg_img C.sg_image){ // Use only if usage: .dynamic is enabled fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr){ sz := w * h * 4 - mut tmp_sbc := C.sg_image_content{} - tmp_sbc.subimage[0][0] = C.sg_subimage_content { + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } C.sg_update_image(sg_img, &tmp_sbc) } @@ -143,12 +143,12 @@ struct Vertex_t { y f32 z f32 color u32 - + //u u16 // for compatibility with D3D11 //v u16 // for compatibility with D3D11 u f32 v f32 -} +} // march shader init fn init_cube_glsl_i(mut app App) { @@ -191,22 +191,26 @@ fn init_cube_glsl_i(mut app App) { mut vert_buffer_desc := C.sg_buffer_desc{} unsafe {C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc))} - vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t)) - vert_buffer_desc.content = byteptr(vertices.data) + vert_buffer_desc.size = size_t(vertices.len * int(sizeof(Vertex_t))) + vert_buffer_desc.data = C.sg_range{ + ptr: vertices.data + size: size_t(vertices.len * int(sizeof(Vertex_t))) + } vert_buffer_desc.@type = .vertexbuffer vert_buffer_desc.label = "cube-vertices".str vbuf := gfx.make_buffer(&vert_buffer_desc) - + /* create an instance buffer for the cube */ mut inst_buffer_desc := C.sg_buffer_desc{} unsafe {C.memset(&inst_buffer_desc, 0, sizeof(inst_buffer_desc))} - inst_buffer_desc.size = num_inst * int(sizeof(m4.Vec4)) + + inst_buffer_desc.size = size_t(num_inst * int(sizeof(m4.Vec4))) inst_buffer_desc.@type = .vertexbuffer inst_buffer_desc.usage = .stream inst_buffer_desc.label = "instance-data".str inst_buf := gfx.make_buffer(&inst_buffer_desc) - - + + /* create an index buffer for the cube */ indices := [ u16(0), 1, 2, 0, 2, 3, @@ -216,22 +220,25 @@ fn init_cube_glsl_i(mut app App) { 16, 17, 18, 16, 18, 19, 22, 21, 20, 23, 22, 20 ] - + mut index_buffer_desc := C.sg_buffer_desc{} unsafe {C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc))} - index_buffer_desc.size = indices.len * int(sizeof(u16)) - index_buffer_desc.content = byteptr(indices.data) + index_buffer_desc.size = size_t(indices.len * int(sizeof(u16))) + index_buffer_desc.data = C.sg_range{ + ptr: indices.data + size: size_t(indices.len * int(sizeof(u16))) + } index_buffer_desc.@type = .indexbuffer index_buffer_desc.label = "cube-indices".str ibuf := gfx.make_buffer(&index_buffer_desc) - + /* create shader */ - shader := gfx.make_shader(C.instancing_shader_desc()) + shader := gfx.make_shader(C.instancing_shader_desc(C.sg_query_backend())) mut pipdesc := C.sg_pipeline_desc{} unsafe {C.memset(&pipdesc, 0, sizeof(pipdesc))} pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t)) - + // the constants [C.ATTR_vs_m_pos, C.ATTR_vs_m_color0, C.ATTR_vs_m_texcoord0] are generated by sokol-shdc pipdesc.layout.attrs[C.ATTR_vs_i_pos ].format = .float3 // x,y,z as f32 pipdesc.layout.attrs[C.ATTR_vs_i_pos ].buffer_index = 0 @@ -239,26 +246,25 @@ fn init_cube_glsl_i(mut app App) { pipdesc.layout.attrs[C.ATTR_vs_i_pos ].buffer_index = 0 pipdesc.layout.attrs[C.ATTR_vs_i_texcoord0].format = .float2 // u,v as f32 pipdesc.layout.attrs[C.ATTR_vs_i_pos ].buffer_index = 0 - + // instancing // the constant ATTR_vs_i_inst_pos is generated by sokol-shdc pipdesc.layout.buffers[1].stride = int(sizeof(m4.Vec4)) pipdesc.layout.buffers[1].step_func = .per_instance // we will pass a single parameter for each instance!! pipdesc.layout.attrs[C.ATTR_vs_i_inst_pos ].format = .float4 pipdesc.layout.attrs[C.ATTR_vs_i_inst_pos ].buffer_index = 1 - + pipdesc.shader = shader pipdesc.index_type = .uint16 - - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func : gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) - } - pipdesc.rasterizer = C.sg_rasterizer_state { - cull_mode: .back + + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .back + pipdesc.label = "glsl_shader pipeline".str - + mut bind := C.sg_bindings{} unsafe {C.memset(&bind, 0, sizeof(bind))} bind.vertex_buffers[0] = vbuf // vertex buffer @@ -267,21 +273,21 @@ fn init_cube_glsl_i(mut app App) { bind.fs_images[C.SLOT_tex] = app.texture app.bind['inst'] = bind app.pipe['inst'] = gfx.make_pipeline(&pipdesc) - + println("GLSL March init DONE!") } fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) m4.Mat4{ proj := m4.perspective(60, w/h, 0.01, 4000.0) view := m4.look_at(m4.Vec4{e:[f32(0.0),100,6,0]!}, m4.Vec4{e:[f32(0),0,0,0]!}, m4.Vec4{e:[f32(0),1.0,0,0]!}) - view_proj := view * proj - + view_proj := view * proj + rxm := m4.rotate(m4.rad(rx), m4.Vec4{e:[f32(1),0,0,0]!}) rym := m4.rotate(m4.rad(ry), m4.Vec4{e:[f32(0),1,0,0]!}) - + model := rym * rxm scale_m := m4.scale(m4.Vec4{e:[in_scale, in_scale, in_scale, 1]!}) - + res := (scale_m * model)* view_proj return res } @@ -296,13 +302,13 @@ fn draw_cube_glsl_i(mut app App){ //ratio := f32(ws.width) / ws.height dw := f32(ws.width / 2) dh := f32(ws.height / 2) - + rot := [f32(app.mouse_y), f32(app.mouse_x)] tr_matrix := calc_tr_matrices(dw, dh, rot[0], rot[1], 2.3) - + gfx.apply_pipeline(app.pipe['inst']) gfx.apply_bindings(app.bind['inst']) - + //*************** // Instancing //*************** @@ -324,15 +330,23 @@ fn draw_cube_glsl_i(mut app App){ spare_param := f32(index % 10) app.inst_pos[index] = m4.Vec4{e:[f32((x - cx - app.camera_x) * cube_size),y ,f32( (z - cz - app.camera_z) * cube_size),spare_param]!} } - gfx.update_buffer(app.bind['inst'].vertex_buffers[1], &app.inst_pos , num_inst * int(sizeof(m4.Vec4)) ) - + range := C.sg_range{ + ptr: &app.inst_pos + size: size_t(num_inst * int(sizeof(m4.Vec4))) + } + gfx.update_buffer(app.bind['inst'].vertex_buffers[1], &range ) + // Uniforms // *** vertex shadeer uniforms *** // passing the view matrix as uniform // res is a 4x4 matrix of f32 thus: 4*16 byte of size - gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_i, &tr_matrix, 4*16 ) + vs_uniforms_range := C.sg_range{ + ptr: &tr_matrix + size: size_t(4 * 16) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_i, &vs_uniforms_range) -/* +/* // *** fragment shader uniforms *** time_ticks := f32(time.ticks() - app.ticks) / 1000 mut tmp_fs_params := [ @@ -342,10 +356,14 @@ fn draw_cube_glsl_i(mut app App){ //ws.height - app.mouse_y*2, // mouse y scaled time_ticks, // time as f32 app.frame_count, // frame count - 0,0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h + 0,0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h ]! - gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_i, &tmp_fs_params, int(sizeof(tmp_fs_params))) -*/ + fs_uniforms_range := C.sg_range{ + ptr: &tmp_fs_params + size: size_t(sizeof(tmp_fs_params)) + } + gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range) +*/ // 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw for num_inst times gfx.draw(0, (3 * 2) * 6, num_inst) } @@ -375,11 +393,13 @@ fn frame(mut app App) { // clear mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 0.0 + g: 0.0 + b: 0.0 + a: 1.0 + } } - color_action.val[0] = 0 - color_action.val[1] = 0 - color_action.val[2] = 0 - color_action.val[3] = 1.0 mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action gfx.begin_default_pass(&pass_action, ws.width, ws.height) @@ -388,7 +408,7 @@ fn frame(mut app App) { draw_cube_glsl_i(mut app) draw_end_glsl(app) app.frame_count++ -} +} /****************************************************************************** * Init / Cleanup @@ -431,7 +451,7 @@ fn my_init(mut app App) { app.texture = create_texture(w, h, tmp_txt) free(tmp_txt) } - + // glsl init_cube_glsl_i(mut app) app.init_flag = true @@ -462,7 +482,7 @@ fn my_event_manager(mut ev gg.Event, mut app App) { app.mouse_y = int(touch_point.pos_y) } } - + // keyboard if ev.typ == .key_down { step := f32(1.0) @@ -500,6 +520,6 @@ fn main(){ event_fn: my_event_manager }) - app.ticks = time.ticks() + app.ticks = time.ticks() app.gg.run() } diff --git a/examples/sokol/06_obj_viewer/obj/rend.v b/examples/sokol/06_obj_viewer/obj/rend.v index 87a445304c..8084059177 100644 --- a/examples/sokol/06_obj_viewer/obj/rend.v +++ b/examples/sokol/06_obj_viewer/obj/rend.v @@ -32,9 +32,9 @@ pub fn create_texture(w int, h int, buf &byte) C.sg_image { d3d11_texture: 0 } // comment if .dynamic is enabled - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: buf - size: sz + size: size_t(sz) } sg_img := C.sg_make_image(&img_desc) @@ -65,25 +65,35 @@ pub fn (mut obj_part ObjPart) create_pipeline(in_part []int, shader C.sg_shader, obj_buf := obj_part.get_buffer(in_part) res.n_vert = obj_buf.n_vertex res.material = obj_part.part[in_part[0]].material - + // vertex buffer mut vert_buffer_desc := C.sg_buffer_desc{} unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) } - vert_buffer_desc.size = obj_buf.vbuf.len * int(sizeof(Vertex_pnct)) - vert_buffer_desc.content = &byte(obj_buf.vbuf.data) + + vert_buffer_desc.size = size_t(obj_buf.vbuf.len * int(sizeof(Vertex_pnct))) + vert_buffer_desc.data = C.sg_range{ + ptr: obj_buf.vbuf.data + size: size_t(obj_buf.vbuf.len * int(sizeof(Vertex_pnct))) + } + vert_buffer_desc.@type = .vertexbuffer vert_buffer_desc.label = 'vertbuf_part_${in_part:03}'.str vbuf := gfx.make_buffer(&vert_buffer_desc) - + // index buffer mut index_buffer_desc := C.sg_buffer_desc{} unsafe {C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc))} - index_buffer_desc.size = obj_buf.ibuf.len * int(sizeof(u32)) - index_buffer_desc.content = &byte(obj_buf.ibuf.data) + + index_buffer_desc.size = size_t(obj_buf.ibuf.len * int(sizeof(u32))) + index_buffer_desc.data = C.sg_range{ + ptr: obj_buf.ibuf.data + size: size_t(obj_buf.ibuf.len * int(sizeof(u32))) + } + index_buffer_desc.@type = .indexbuffer index_buffer_desc.label = "indbuf_part_${in_part:03}".str ibuf := gfx.make_buffer(&index_buffer_desc) - + mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_pnct)) @@ -96,19 +106,23 @@ pub fn (mut obj_part ObjPart) create_pipeline(in_part []int, shader C.sg_shader, // pipdesc.layout.attrs[C.ATTR_vs_a_Texcoord0].format = .short2n // u,v as u16 pipdesc.index_type = .uint32 - pipdesc.blend.enabled = true - pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) - pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) - - pipdesc.depth_stencil = C.sg_depth_stencil_state{ - depth_write_enabled: true - depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } } - pipdesc.rasterizer = C.sg_rasterizer_state{ - cull_mode: .front //.back + pipdesc.colors[0] = color_state + + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) } + pipdesc.cull_mode = .front + pipdesc.label = 'pip_part_${in_part:03}'.str - + // shader pipdesc.shader = shader @@ -128,9 +142,8 @@ pub fn (mut obj_part ObjPart) create_pipeline(in_part []int, shader C.sg_shader, pub fn (mut obj_part ObjPart) init_render_data(texture C.sg_image) { // create shader // One shader for all the model - shader := gfx.make_shader(C.gouraud_shader_desc()) - //shader := gfx.make_shader(C.gouraud_shader_desc(gfx.query_backend())) - + shader := gfx.make_shader(C.gouraud_shader_desc(gfx.query_backend())) + mut part_dict := map[string][]int{} for i, p in obj_part.part { if p.faces.len > 0 { @@ -139,7 +152,7 @@ pub fn (mut obj_part ObjPart) init_render_data(texture C.sg_image) { } obj_part.rend_data.clear() //println("Material dict: ${obj_part.mat_map.keys()}") - + for k, v in part_dict { //println("$k => Parts $v") @@ -172,27 +185,27 @@ pub fn (mut obj_part ObjPart) init_render_data(texture C.sg_image) { pub fn (obj_part ObjPart) bind_and_draw(rend_data_index int, in_data Shader_data) u32 { // apply the pipline and bindings mut part_render_data := obj_part.rend_data[rend_data_index] - + // pass light position mut tmp_fs_params := obj.Tmp_fs_param{} tmp_fs_params.ligth = in_data.fs_data.ligth - + if part_render_data.material in obj_part.mat_map { mat_index := obj_part.mat_map[part_render_data.material] mat := obj_part.mat[mat_index] - + // ambient tmp_fs_params.ka = in_data.fs_data.ka if 'Ka' in mat.ks { tmp_fs_params.ka = mat.ks['Ka'] } - + // specular tmp_fs_params.ks = in_data.fs_data.ks if 'Ks' in mat.ks { tmp_fs_params.ks = mat.ks['Ks'] } - + // specular exponent Ns if 'Ns' in mat.ns { tmp_fs_params.ks.e[3] = mat.ns['Ns'] / 1000.0 @@ -200,7 +213,7 @@ pub fn (obj_part ObjPart) bind_and_draw(rend_data_index int, in_data Shader_data // defautl value is 10 tmp_fs_params.ks.e[3] = f32(10) / 1000.0 } - + // diffuse tmp_fs_params.kd = in_data.fs_data.kd if 'Kd' in mat.ks { @@ -212,11 +225,21 @@ pub fn (obj_part ObjPart) bind_and_draw(rend_data_index int, in_data Shader_data tmp_fs_params.kd.e[3] = mat.ns['Tr'] } } - + gfx.apply_pipeline(part_render_data.pipeline) gfx.apply_bindings(part_render_data.bind) - gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, in_data.vs_data, in_data.vs_len) - gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &tmp_fs_params, in_data.fs_len) + + vs_uniforms_range := C.sg_range{ + ptr: in_data.vs_data + size: size_t(in_data.vs_len) + } + fs_uniforms_range := C.sg_range{ + ptr: &tmp_fs_params + size: size_t(in_data.fs_len) + } + + gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &vs_uniforms_range) + gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range) gfx.draw(0, int(part_render_data.n_vert), 1) return part_render_data.n_vert } @@ -237,7 +260,7 @@ pub fn (mut obj_part ObjPart) calc_bbox() { if v.e[0] > obj_part.max.e[0] { obj_part.max.e[0] = v.e[0] } if v.e[1] > obj_part.max.e[1] { obj_part.max.e[1] = v.e[1] } if v.e[2] > obj_part.max.e[2] { obj_part.max.e[2] = v.e[2] } - + if v.e[0] < obj_part.min.e[0] { obj_part.min.e[0] = v.e[0] } if v.e[1] < obj_part.min.e[1] { obj_part.min.e[1] = v.e[1] } if v.e[2] < obj_part.min.e[2] { obj_part.min.e[2] = v.e[2] } diff --git a/examples/sokol/06_obj_viewer/show_obj.v b/examples/sokol/06_obj_viewer/show_obj.v index ec9a55908e..d433e03b27 100644 --- a/examples/sokol/06_obj_viewer/show_obj.v +++ b/examples/sokol/06_obj_viewer/show_obj.v @@ -52,8 +52,7 @@ import obj #flag -I @VROOT/. #include "gouraud.h" #Please use sokol-shdc to generate the necessary rt_glsl.h file from rt_glsl.glsl (see the instructions at the top of this file) -//fn C.gouraud_shader_desc(gfx.Backend) &C.sg_shader_desc -fn C.gouraud_shader_desc() &C.sg_shader_desc +fn C.gouraud_shader_desc(gfx.Backend) &C.sg_shader_desc const ( win_width = 600 @@ -74,11 +73,11 @@ mut: // time ticks i64 - + // model obj_part &obj.ObjPart n_vertex u32 - + // init parameters file_name string single_material_flag bool @@ -87,7 +86,7 @@ mut: /****************************************************************************** * Draw functions ******************************************************************************/ -[inline] +[inline] fn vec4(x f32, y f32, z f32, w f32) m4.Vec4 { return m4.Vec4{e:[x, y, z, w]!} } @@ -99,7 +98,7 @@ fn calc_matrices(w f32, h f32, rx f32, ry f32, in_scale f32, pos m4.Vec4) obj.Ma rxm := m4.rotate(m4.rad(rx), vec4(f32(1), 0, 0, 0)) rym := m4.rotate(m4.rad(ry), vec4(f32(0), 1, 0, 0)) - + model_pos := m4.unit_m4().translate(pos) model_m := (rym * rxm) * model_pos @@ -108,7 +107,7 @@ fn calc_matrices(w f32, h f32, rx f32, ry f32, in_scale f32, pos m4.Vec4) obj.Ma mv := scale_m * model_m // model view nm := mv.inverse().transpose() // normal matrix mvp := mv * view_proj // model view projection - + return obj.Mats{mv:mv, mvp:mvp, nm:nm} } @@ -123,23 +122,23 @@ fn draw_model(app App, model_pos m4.Vec4) u32 { mut scale := f32(1) if app.obj_part.radius > 1 { - scale = 1/(app.obj_part.radius) + scale = 1/(app.obj_part.radius) } else { scale = app.obj_part.radius } scale *= 3 - + // *** vertex shader uniforms *** rot := [f32(app.mouse_y), f32(app.mouse_x)] mut zoom_scale := scale + f32(app.scroll_y) / (app.obj_part.radius*4) mats := calc_matrices(dw, dh, rot[0], rot[1] , zoom_scale, model_pos) - + mut tmp_vs_param := obj.Tmp_vs_param{ mv: mats.mv, mvp: mats.mvp, nm: mats.nm } - + // *** fragment shader uniforms *** time_ticks := f32(time.ticks() - app.ticks) / 1000 radius_light := f32(app.obj_part.radius) @@ -148,7 +147,7 @@ fn draw_model(app App, model_pos m4.Vec4) u32 { mut tmp_fs_params := obj.Tmp_fs_param{} tmp_fs_params.ligth = m4.vec3(x_light, radius_light, z_light) - + sd := obj.Shader_data{ vs_data: &tmp_vs_param vs_len: int(sizeof(tmp_vs_param)) @@ -156,7 +155,7 @@ fn draw_model(app App, model_pos m4.Vec4) u32 { fs_len: int(sizeof(tmp_fs_params)) } - return app.obj_part.bind_and_draw_all(sd) + return app.obj_part.bind_and_draw_all(sd) } fn frame(mut app App) { @@ -165,11 +164,14 @@ fn frame(mut app App) { // clear mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 0.0 + g: 0.0 + b: 0.0 + a: 1.0 + } } - color_action.val[0] = 0 - color_action.val[1] = 0 - color_action.val[2] = 0 - color_action.val[3] = 1.0 + mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action gfx.begin_default_pass(&pass_action, ws.width, ws.height) @@ -178,7 +180,7 @@ fn frame(mut app App) { draw_start_glsl(app) draw_model(app, m4.Vec4{}) // uncoment if you want a raw benchmark mode -/* +/* mut n_vertex_drawn := u32(0) n_x_obj := 20 @@ -189,9 +191,9 @@ fn frame(mut app App) { } } } -*/ +*/ draw_end_glsl(app) - + //println("v:$n_vertex_drawn") app.frame_count++ } @@ -227,7 +229,7 @@ fn my_init(mut app App) { max_vertices: 128 * 65536 } sgl.setup(&sgl_desc) - + // 1x1 pixel white, default texture unsafe { tmp_txt := malloc(4) @@ -238,7 +240,7 @@ fn my_init(mut app App) { app.texture = obj.create_texture(1, 1, tmp_txt) free(tmp_txt) } - + // glsl app.obj_part.init_render_data(app.texture) app.init_flag = true @@ -250,7 +252,7 @@ fn cleanup(mut app App) { for _, mat in app.obj_part.texture { obj.destroy_texture(mat) } -*/ +*/ } /****************************************************************************** @@ -261,11 +263,11 @@ fn my_event_manager(mut ev gg.Event, mut app App) { app.mouse_x = int(ev.mouse_x) app.mouse_y = int(ev.mouse_y) } - + if ev.scroll_y != 0 { app.scroll_y += int(ev.scroll_y) } - + if ev.typ == .touches_began || ev.typ == .touches_moved { if ev.num_touches > 0 { touch_point := ev.touches[0] @@ -290,8 +292,9 @@ fn main() { gg: 0 obj_part: 0 } - + app.file_name = "v.obj_" // default object is the v logo + app.single_material_flag = false $if !android { if os.args.len > 3 || (os.args.len >= 2 && os.args[1] in ['-h', '--help', '\\?', '-?']) { @@ -302,8 +305,8 @@ fn main() { eprintln('single_material_flag: if true the viewer use for all the model\'s parts the default material\n') exit(0) } - - if os.args.len >= 2 { + + if os.args.len >= 2 { app.file_name = os.args[1] } if os.args.len >= 3 { @@ -312,7 +315,7 @@ fn main() { println("Loading model: $app.file_name") println("Using single material: $app.single_material_flag") } - + app.gg = gg.new_context( width: win_width height: win_height diff --git a/examples/sokol/fonts.v b/examples/sokol/fonts.v index b1c0979eaf..f5774ac596 100644 --- a/examples/sokol/fonts.v +++ b/examples/sokol/fonts.v @@ -15,11 +15,13 @@ mut: fn main() { mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 0.3 + g: 0.3 + b: 0.32 + a: 1.0 + } } - color_action.val[0] = 0.3 - color_action.val[1] = 0.3 - color_action.val[2] = 0.32 - color_action.val[3] = 1.0 mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action state := &AppState{ diff --git a/examples/sokol/freetype_raven.v b/examples/sokol/freetype_raven.v index 0d9d5d4bbe..4b867a787c 100644 --- a/examples/sokol/freetype_raven.v +++ b/examples/sokol/freetype_raven.v @@ -65,11 +65,13 @@ mut: fn main() { mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color{ + r: 1.0 + g: 1.0 + b: 1.0 + a: 1.0 + } } - color_action.val[0] = 1 - color_action.val[1] = 1 - color_action.val[2] = 1 - color_action.val[3] = 1.0 mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action state := &AppState{ diff --git a/examples/sokol/particles/particles.v b/examples/sokol/particles/particles.v index d3765ddb65..64d93f9a69 100644 --- a/examples/sokol/particles/particles.v +++ b/examples/sokol/particles/particles.v @@ -81,9 +81,16 @@ fn init(user_data voidptr) { sgl.setup(&sgl_desc) mut pipdesc := C.sg_pipeline_desc{} unsafe {C.memset(&pipdesc, 0, sizeof(pipdesc))} - pipdesc.blend.enabled = true - pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) - pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } + } + pipdesc.colors[0] = color_state + app.alpha_pip = sgl.make_pipeline(&pipdesc) } diff --git a/thirdparty/sokol/sokol_app.h b/thirdparty/sokol/sokol_app.h index 4cdfb98162..dc26fc9f57 100644 --- a/thirdparty/sokol/sokol_app.h +++ b/thirdparty/sokol/sokol_app.h @@ -1,3 +1,6 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_APP_IMPL) +#define SOKOL_APP_IMPL +#endif #ifndef SOKOL_APP_INCLUDED /* sokol_app.h -- cross-platform application wrapper @@ -5,7 +8,8 @@ Project URL: https://github.com/floooh/sokol Do this: - #define SOKOL_IMPL + #define SOKOL_IMPL or + #define SOKOL_APP_IMPL before you include this file in *one* C or C++ file to create the implementation. @@ -29,7 +33,8 @@ SOKOL_ABORT() - called after an unrecoverable error (default: abort()) SOKOL_WIN32_FORCE_MAIN - define this on Win32 to use a main() entry point instead of WinMain SOKOL_NO_ENTRY - define this if sokol_app.h shouldn't "hijack" the main() function - SOKOL_API_DECL - public function declaration prefix (default: extern) + SOKOL_APP_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_APP_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) SOKOL_CALLOC - your own calloc function (default: calloc(n, s)) SOKOL_FREE - your own free function (default: free(p)) @@ -44,22 +49,9 @@ SOKOL_DLL - On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport) + On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as __declspec(dllexport) or __declspec(dllimport) as needed. - If you use sokol_app.h together with sokol_gfx.h, include both headers - in the implementation source file, and include sokol_app.h before - sokol_gfx.h since sokol_app.h will also include the required 3D-API - headers. - - On Windows, a minimal 'GL header' and function loader is integrated which - contains just enough of GL for sokol_gfx.h. If you want to use your own - GL header-generator/loader instead, define SOKOL_WIN32_NO_GL_LOADER - before including the implementation part of sokol_app.h. - - To make use of the integrated GL loader, simply include the sokol_app.h - implementation before the sokol_gfx.h implementation. - For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp Portions of the Windows and Linux GL initialization and event code have been @@ -71,11 +63,15 @@ - on macOS with Metal: Cocoa, QuartzCore, Metal, MetalKit - on macOS with GL: Cocoa, QuartzCore, OpenGL - - on iOS with Metal: UIKit, Metal, MetalKit - - on iOS with GL: UIKit, OpenGLES, GLKit + - on iOS with Metal: Foundation, UIKit, Metal, MetalKit + - on iOS with GL: Foundation, UIKit, OpenGLES, GLKit - on Linux: X11, Xi, Xcursor, GL, dl, pthread, m(?) - on Android: GLESv3, EGL, log, android - - on Windows: no action needed, libs are defined in-source via pragma-comment-lib + - on Windows with the MSVC or Clang toolchains: no action needed, libs are defined in-source via pragma-comment-lib + - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' so that _WIN32 is defined + - link with the following libs: -lkernel32 -luser32 -lshell32 + - additionally with the GL backend: -lgdi32 + - additionally with the D3D11 backend: -ld3d11 -ldxgi -dxguid On Linux, you also need to use the -pthread compiler and linker option, otherwise weird things will happen, see here for details: https://github.com/floooh/sokol/issues/376 @@ -138,13 +134,14 @@ high-dpi | YES | YES | TODO | YES | YES | YES | TODO | YES clipboard | YES | YES | TODO | --- | --- | TODO | --- | YES MSAA | YES | YES | YES | YES | YES | TODO | TODO | YES + drag'n'drop | YES | YES | YES | --- | --- | TODO | TODO | YES TODO ==== - Linux: - clipboard support - UWP: - - clipboard, mouselock, MSAA support + - clipboard, mouselock - sapp_consume_event() on non-web platforms? STEP BY STEP @@ -244,6 +241,13 @@ this may change from one frame to the next, and it may be different from the initial size provided in the sapp_desc struct. + float sapp_widthf(void) + float sapp_heightf(void) + These are alternatives to sapp_width() and sapp_height() which return + the default framebuffer size as float values instead of integer. This + may help to prevent casting back and forth between int and float + in more strongly typed languages than C and C++. + int sapp_color_format(void) int sapp_depth_format(void) The color and depth-stencil pixelformats of the default framebuffer, @@ -334,6 +338,7 @@ - the application was suspended or restored (on mobile platforms) - the user or application code has asked to quit the application - a string was pasted to the system clipboard + - one or more files have been dropped onto the application window To explicitly 'consume' an event and prevent that the event is forwarded for further handling to the operating system, call @@ -498,6 +503,141 @@ - on HTML5: when the browser sends a 'paste' event to the global 'window' object - on all other platforms: when the Ctrl+V key is pressed down + DRAG AND DROP SUPPORT + ===================== + PLEASE NOTE: the drag'n'drop feature works differently on WASM/HTML5 + and on the native desktop platforms (Win32, Linux and macOS) because + of security-related restrictions in the HTML5 drag'n'drop API. The + WASM/HTML5 specifics are described at the end of this documentation + section: + + Like clipboard support, drag'n'drop support must be explicitly enabled + at startup in the sapp_desc struct. + + sapp_desc sokol_main() { + return (sapp_desc) { + .enable_dragndrop = true, // default is false + ... + }; + } + + You can also adjust the maximum number of files that are accepted + in a drop operation, and the maximum path length in bytes if needed: + + sapp_desc sokol_main() { + return (sapp_desc) { + .enable_dragndrop = true, // default is false + .max_dropped_files = 8, // default is 1 + .max_dropped_file_path_length = 8192, // in bytes, default is 2048 + ... + }; + } + + When drag'n'drop is enabled, the event callback will be invoked with an + event of type SAPP_EVENTTYPE_FILES_DROPPED whenever the user drops files on + the application window. + + After the SAPP_EVENTTYPE_FILES_DROPPED is received, you can query the + number of dropped files, and their absolute paths by calling separate + functions: + + void on_event(const sapp_event* ev) { + if (ev->type == SAPP_EVENTTYPE_FILES_DROPPED) { + + // the mouse position where the drop happened + float x = ev->mouse_x; + float y = ev->mouse_y; + + // get the number of files and their paths like this: + const int num_dropped_files = sapp_get_num_dropped_files(); + for (int i = 0; i < num_dropped_files; i++) { + const char* path = sapp_get_dropped_file_path(i); + ... + } + } + } + + The returned file paths are UTF-8 encoded strings. + + You can call sapp_get_num_dropped_files() and sapp_get_dropped_file_path() + anywhere, also outside the event handler callback, but be aware that the + file path strings will be overwritten with the next drop operation. + + In any case, sapp_get_dropped_file_path() will never return a null pointer, + instead an empty string "" will be returned if the drag'n'drop feature + hasn't been enabled, the last drop-operation failed, or the file path index + is out of range. + + Drag'n'drop caveats: + + - if more files are dropped in a single drop-action + than sapp_desc.max_dropped_files, the additional + files will be silently ignored + - if any of the file paths is longer than + sapp_desc.max_dropped_file_path_length (in number of bytes, after UTF-8 + encoding) the entire drop operation will be silently ignored (this + needs some sort of error feedback in the future) + - no mouse positions are reported while the drag is in + process, this may change in the future + + Drag'n'drop on HTML5/WASM: + + The HTML5 drag'n'drop API doesn't return file paths, but instead + black-box 'file objects' which must be used to load the content + of dropped files. This is the reason why sokol_app.h adds two + HTML5-specific functions to the drag'n'drop API: + + uint32_t sapp_html5_get_dropped_file_size(int index) + Returns the size in bytes of a dropped file. + + void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) + Asynchronously loads the content of a dropped file into a + provided memory buffer (which must be big enough to hold + the file content) + + To start loading the first dropped file after an SAPP_EVENTTYPE_FILES_DROPPED + event is received: + + sapp_html5_fetch_dropped_file(&(sapp_html5_fetch_request){ + .dropped_file_index = 0, + .callback = fetch_cb + .buffer_ptr = buf, + .buffer_size = buf_size, + .user_data = ... + }); + + Make sure that the memory pointed to by 'buf' stays valid until the + callback function is called! + + As result of the asynchronous loading operation (no matter if succeeded or + failed) the 'fetch_cb' function will be called: + + void fetch_cb(const sapp_html5_fetch_response* response) { + // IMPORTANT: check if the loading operation actually succeeded: + if (response->succeeded) { + // the size of the loaded file: + const uint32_t num_bytes = response->fetched_size; + // and the pointer to the data (same as 'buf' in the fetch-call): + const void* ptr = response->buffer_ptr; + } + else { + // on error check the error code: + switch (response->error_code) { + case SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL: + ... + break; + case SAPP_HTML5_FETCH_ERROR_OTHER: + ... + break; + } + } + } + + Check the droptest-sapp example for a real-world example which works + both on native platforms and the web: + + https://github.com/floooh/sokol-samples/blob/master/sapp/droptest-sapp.c + HIGH-DPI RENDERING ================== You can set the sapp_desc.high_dpi flag during initialization to request @@ -550,7 +690,7 @@ from the application code, and a quit initiated by the application user can be intercepted (for instance to show a custom dialog box). - This 'programmatic quit protocol' is implemented trough 3 functions + This 'programmatic quit protocol' is implemented through 3 functions and 1 event: - sapp_quit(): This function simply quits the application without @@ -679,6 +819,36 @@ NOTE: SOKOL_NO_ENTRY is currently not supported on Android. + WINDOWS CONSOLE OUTPUT + ====================== + On Windows, regular windowed applications don't show any stdout/stderr text + output, which can be a bit of a hassle for printf() debugging or generally + logging text to the console. Also, console output by default uses a local + codepage setting and thus international UTF-8 encoded text is printed + as garbage. + + To help with these issues, sokol_app.h can be configured at startup + via the following Windows-specific sapp_desc flags: + + sapp_desc.win32_console_utf8 (default: false) + When set to true, the output console codepage will be switched + to UTF-8 (and restored to the original codepage on exit) + + sapp_desc.win32_console_attach (default: false) + When set to true, stdout and stderr will be attached to the + console of the parent process (if the parent process actually + has a console). This means that if the application was started + in a command line window, stdout and stderr output will be printed + to the terminal, just like a regular command line program. But if + the application is started via double-click, it will behave like + a regular UI application, and stdout/stderr will not be visible. + + sapp_desc.win32_console_create (default: false) + When set to true, a new console window will be created and + stdout/stderr will be redirected to that console window. It + doesn't matter if the application is started from the command + line or via double-click. + TEMP NOTE DUMP ============== - onscreen keyboard support on Android requires Java :(, should we even bother? @@ -723,13 +893,16 @@ #include #include -#ifndef SOKOL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) -#define SOKOL_API_DECL __declspec(dllexport) +#if defined(SOKOL_API_DECL) && !defined(SOKOL_APP_API_DECL) +#define SOKOL_APP_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_APP_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_APP_IMPL) +#define SOKOL_APP_API_DECL __declspec(dllexport) #elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_API_DECL __declspec(dllimport) +#define SOKOL_APP_API_DECL __declspec(dllimport) #else -#define SOKOL_API_DECL extern +#define SOKOL_APP_API_DECL extern #endif #endif @@ -766,6 +939,7 @@ typedef enum sapp_event_type { SAPP_EVENTTYPE_UPDATE_CURSOR, SAPP_EVENTTYPE_QUIT_REQUESTED, SAPP_EVENTTYPE_CLIPBOARD_PASTED, + SAPP_EVENTTYPE_FILES_DROPPED, _SAPP_EVENTTYPE_NUM, _SAPP_EVENTTYPE_FORCE_U32 = 0x7FFFFFFF } sapp_event_type; @@ -903,17 +1077,17 @@ typedef struct sapp_touchpoint { } sapp_touchpoint; typedef enum sapp_mousebutton { - SAPP_MOUSEBUTTON_INVALID = -1, - SAPP_MOUSEBUTTON_LEFT = 0, - SAPP_MOUSEBUTTON_RIGHT = 1, - SAPP_MOUSEBUTTON_MIDDLE = 2, + SAPP_MOUSEBUTTON_LEFT = 0x0, + SAPP_MOUSEBUTTON_RIGHT = 0x1, + SAPP_MOUSEBUTTON_MIDDLE = 0x2, + SAPP_MOUSEBUTTON_INVALID = 0x100, } sapp_mousebutton; enum { - SAPP_MODIFIER_SHIFT = (1<<0), - SAPP_MODIFIER_CTRL = (1<<1), - SAPP_MODIFIER_ALT = (1<<2), - SAPP_MODIFIER_SUPER = (1<<3) + SAPP_MODIFIER_SHIFT = 0x1, + SAPP_MODIFIER_CTRL = 0x2, + SAPP_MODIFIER_ALT = 0x4, + SAPP_MODIFIER_SUPER = 0x8 }; typedef struct sapp_event { @@ -963,121 +1137,169 @@ typedef struct sapp_desc { bool user_cursor; /* if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR */ bool enable_clipboard; /* enable clipboard access, default is false */ int clipboard_size; /* max size of clipboard content in bytes */ + bool enable_dragndrop; /* enable file dropping (drag'n'drop), default is false */ + int max_dropped_files; /* max number of dropped files to process (default: 1) */ + int max_dropped_file_path_length; /* max length in bytes of a dropped UTF-8 file path (default: 2048) */ + /* backend-specific options */ + bool gl_force_gles2; /* if true, setup GLES2/WebGL even if GLES3/WebGL2 is available */ + bool win32_console_utf8; /* if true, set the output console codepage to UTF-8 */ + bool win32_console_create; /* if true, attach stdout/stderr to a new console window */ + bool win32_console_attach; /* if true, attach stdout/stderr to parent process */ const char* html5_canvas_name; /* the name (id) of the HTML5 canvas element, default is "canvas" */ bool html5_canvas_resize; /* if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked */ bool html5_preserve_drawing_buffer; /* HTML5 only: whether to preserve default framebuffer content between frames */ bool html5_premultiplied_alpha; /* HTML5 only: whether the rendered pixels use premultiplied alpha convention */ 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 */ - bool gl_force_gles2; /* if true, setup GLES2/WebGL even if GLES3/WebGL2 is available */ - bool native_render; + + /* V patches */ + bool __v_native_render; /* V patch to allow for native rendering */ } sapp_desc; +/* HTML5 specific: request and response structs for + asynchronously loading dropped-file content. +*/ +typedef enum sapp_html5_fetch_error { + SAPP_HTML5_FETCH_ERROR_NO_ERROR, + SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL, + SAPP_HTML5_FETCH_ERROR_OTHER, +} sapp_html5_fetch_error; + +typedef struct sapp_html5_fetch_response { + bool succeeded; /* true if the loading operation has succeeded */ + sapp_html5_fetch_error error_code; + int file_index; /* index of the dropped file (0..sapp_get_num_dropped_filed()-1) */ + uint32_t fetched_size; /* size in bytes of loaded data */ + void* buffer_ptr; /* pointer to user-provided buffer which contains the loaded data */ + uint32_t buffer_size; /* size of user-provided buffer (buffer_size >= fetched_size) */ + void* user_data; /* user-provided user data pointer */ +} sapp_html5_fetch_response; + +typedef struct sapp_html5_fetch_request { + int dropped_file_index; /* 0..sapp_get_num_dropped_files()-1 */ + void (*callback)(const sapp_html5_fetch_response*); /* response callback function pointer (required) */ + void* buffer_ptr; /* pointer to buffer to load data into */ + uint32_t buffer_size; /* size in bytes of buffer */ + void* user_data; /* optional userdata pointer */ +} sapp_html5_fetch_request; + /* user-provided functions */ extern sapp_desc sokol_main(int argc, char* argv[]); /* returns true after sokol-app has been initialized */ -SOKOL_API_DECL bool sapp_isvalid(void); +SOKOL_APP_API_DECL bool sapp_isvalid(void); /* returns the current framebuffer width in pixels */ -SOKOL_API_DECL int sapp_width(void); +SOKOL_APP_API_DECL int sapp_width(void); +/* same as sapp_width(), but returns float */ +SOKOL_APP_API_DECL float sapp_widthf(void); /* returns the current framebuffer height in pixels */ -SOKOL_API_DECL int sapp_height(void); +SOKOL_APP_API_DECL int sapp_height(void); +/* same as sapp_height(), but returns float */ +SOKOL_APP_API_DECL float sapp_heightf(void); /* get default framebuffer color pixel format */ -SOKOL_API_DECL int sapp_color_format(void); +SOKOL_APP_API_DECL int sapp_color_format(void); /* get default framebuffer depth pixel format */ -SOKOL_API_DECL int sapp_depth_format(void); +SOKOL_APP_API_DECL int sapp_depth_format(void); /* get default framebuffer sample count */ -SOKOL_API_DECL int sapp_sample_count(void); +SOKOL_APP_API_DECL int sapp_sample_count(void); /* returns true when high_dpi was requested and actually running in a high-dpi scenario */ -SOKOL_API_DECL bool sapp_high_dpi(void); +SOKOL_APP_API_DECL bool sapp_high_dpi(void); /* returns the dpi scaling factor (window pixels to framebuffer pixels) */ -SOKOL_API_DECL float sapp_dpi_scale(void); +SOKOL_APP_API_DECL float sapp_dpi_scale(void); /* show or hide the mobile device onscreen keyboard */ -SOKOL_API_DECL void sapp_show_keyboard(bool show); +SOKOL_APP_API_DECL void sapp_show_keyboard(bool show); /* return true if the mobile device onscreen keyboard is currently shown */ -SOKOL_API_DECL bool sapp_keyboard_shown(void); +SOKOL_APP_API_DECL bool sapp_keyboard_shown(void); /* query fullscreen mode */ -SOKOL_API_DECL bool sapp_is_fullscreen(void); +SOKOL_APP_API_DECL bool sapp_is_fullscreen(void); /* toggle fullscreen mode */ -SOKOL_API_DECL void sapp_toggle_fullscreen(void); +SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void); /* show or hide the mouse cursor */ -SOKOL_API_DECL void sapp_show_mouse(bool show); +SOKOL_APP_API_DECL void sapp_show_mouse(bool show); /* show or hide the mouse cursor */ -SOKOL_API_DECL bool sapp_mouse_shown(); +SOKOL_APP_API_DECL bool sapp_mouse_shown(); /* enable/disable mouse-pointer-lock mode */ -SOKOL_API_DECL void sapp_lock_mouse(bool lock); +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) */ -SOKOL_API_DECL bool sapp_mouse_locked(void); +SOKOL_APP_API_DECL bool sapp_mouse_locked(void); /* return the userdata pointer optionally provided in sapp_desc */ -SOKOL_API_DECL void* sapp_userdata(void); +SOKOL_APP_API_DECL void* sapp_userdata(void); /* return a copy of the sapp_desc structure */ -SOKOL_API_DECL sapp_desc sapp_query_desc(void); +SOKOL_APP_API_DECL sapp_desc sapp_query_desc(void); /* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */ -SOKOL_API_DECL void sapp_request_quit(void); +SOKOL_APP_API_DECL void sapp_request_quit(void); /* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) */ -SOKOL_API_DECL void sapp_cancel_quit(void); +SOKOL_APP_API_DECL void sapp_cancel_quit(void); /* initiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUSTED) */ -SOKOL_API_DECL void sapp_quit(void); +SOKOL_APP_API_DECL void sapp_quit(void); /* call from inside event callback to consume the current event (don't forward to platform) */ -SOKOL_API_DECL void sapp_consume_event(void); +SOKOL_APP_API_DECL void sapp_consume_event(void); /* get the current frame counter (for comparison with sapp_event.frame_count) */ -SOKOL_API_DECL uint64_t sapp_frame_count(void); +SOKOL_APP_API_DECL uint64_t sapp_frame_count(void); /* write string into clipboard */ -SOKOL_API_DECL void sapp_set_clipboard_string(const char* str); +SOKOL_APP_API_DECL void sapp_set_clipboard_string(const char* str); /* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */ -SOKOL_API_DECL const char* sapp_get_clipboard_string(void); +SOKOL_APP_API_DECL const char* sapp_get_clipboard_string(void); /* set the window title (only on desktop platforms) */ -SOKOL_API_DECL void sapp_set_window_title(const char* str); +SOKOL_APP_API_DECL void sapp_set_window_title(const char* str); +/* gets the total number of dropped files (after an SAPP_EVENTTYPE_FILES_DROPPED event) */ +SOKOL_APP_API_DECL int sapp_get_num_dropped_files(void); +/* gets the dropped file paths */ +SOKOL_APP_API_DECL const char* sapp_get_dropped_file_path(int index); /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ -SOKOL_API_DECL int sapp_run(const sapp_desc* desc); +SOKOL_APP_API_DECL void sapp_run(const sapp_desc* desc); /* GL: return true when GLES2 fallback is active (to detect fallback from GLES3) */ -SOKOL_API_DECL bool sapp_gles2(void); +SOKOL_APP_API_DECL bool sapp_gles2(void); /* HTML5: enable or disable the hardwired "Leave Site?" dialog box */ -SOKOL_API_DECL void sapp_html5_ask_leave_site(bool ask); +SOKOL_APP_API_DECL void sapp_html5_ask_leave_site(bool ask); +/* HTML5: get byte size of a dropped file */ +SOKOL_APP_API_DECL uint32_t sapp_html5_get_dropped_file_size(int index); +/* HTML5: asynchronously load the content of a dropped file */ +SOKOL_APP_API_DECL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request); /* Metal: get bridged pointer to Metal device object */ -SOKOL_API_DECL const void* sapp_metal_get_device(void); +SOKOL_APP_API_DECL const void* sapp_metal_get_device(void); /* Metal: get bridged pointer to this frame's renderpass descriptor */ -SOKOL_API_DECL const void* sapp_metal_get_renderpass_descriptor(void); +SOKOL_APP_API_DECL const void* sapp_metal_get_renderpass_descriptor(void); /* Metal: get bridged pointer to current drawable */ -SOKOL_API_DECL const void* sapp_metal_get_drawable(void); +SOKOL_APP_API_DECL const void* sapp_metal_get_drawable(void); /* macOS: get bridged pointer to macOS NSWindow */ -SOKOL_API_DECL const void* sapp_macos_get_window(void); +SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); /* iOS: get bridged pointer to iOS UIWindow */ -SOKOL_API_DECL const void* sapp_ios_get_window(void); +SOKOL_APP_API_DECL const void* sapp_ios_get_window(void); /* D3D11: get pointer to ID3D11Device object */ -SOKOL_API_DECL const void* sapp_d3d11_get_device(void); +SOKOL_APP_API_DECL const void* sapp_d3d11_get_device(void); /* D3D11: get pointer to ID3D11DeviceContext object */ -SOKOL_API_DECL const void* sapp_d3d11_get_device_context(void); +SOKOL_APP_API_DECL const void* sapp_d3d11_get_device_context(void); /* D3D11: get pointer to ID3D11RenderTargetView object */ -SOKOL_API_DECL const void* sapp_d3d11_get_render_target_view(void); +SOKOL_APP_API_DECL const void* sapp_d3d11_get_render_target_view(void); /* D3D11: get pointer to ID3D11DepthStencilView */ -SOKOL_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void); +SOKOL_APP_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void); /* Win32: get the HWND window handle */ -SOKOL_API_DECL const void* sapp_win32_get_hwnd(void); +SOKOL_APP_API_DECL const void* sapp_win32_get_hwnd(void); /* WebGPU: get WGPUDevice handle */ -SOKOL_API_DECL const void* sapp_wgpu_get_device(void); +SOKOL_APP_API_DECL const void* sapp_wgpu_get_device(void); /* WebGPU: get swapchain's WGPUTextureView handle for rendering */ -SOKOL_API_DECL const void* sapp_wgpu_get_render_view(void); +SOKOL_APP_API_DECL const void* sapp_wgpu_get_render_view(void); /* WebGPU: get swapchain's MSAA-resolve WGPUTextureView (may return null) */ -SOKOL_API_DECL const void* sapp_wgpu_get_resolve_view(void); +SOKOL_APP_API_DECL const void* sapp_wgpu_get_resolve_view(void); /* WebGPU: get swapchain's WGPUTextureView for the depth-stencil surface */ -SOKOL_API_DECL const void* sapp_wgpu_get_depth_stencil_view(void); +SOKOL_APP_API_DECL const void* sapp_wgpu_get_depth_stencil_view(void); /* Android: get native activity handle */ -SOKOL_API_DECL const void* sapp_android_get_native_activity(void); +SOKOL_APP_API_DECL const void* sapp_android_get_native_activity(void); #ifdef __cplusplus } /* extern "C" */ /* reference-based equivalents for C++ */ -inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } +inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif @@ -1092,10 +1314,11 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif // SOKOL_APP_INCLUDED /*-- IMPLEMENTATION ----------------------------------------------------------*/ -#ifdef SOKOL_IMPL +#ifdef SOKOL_APP_IMPL #define SOKOL_APP_IMPL_INCLUDED (1) -#include /* memset */ +#include // memset +#include // size_t /* check if the config defines are alright */ #if defined(__APPLE__) @@ -1135,7 +1358,7 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #error("sokol_app.h: unknown 3D API selected for UWP, must be SOKOL_D3D11") #endif #if !defined(__cplusplus) - #error("UWP bindings require C++/17") + #error("sokol_app.h: UWP bindings require C++/17") #endif #else #define _SAPP_WIN32 (1) @@ -1226,26 +1449,15 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #define GL_SILENCE_DEPRECATION #endif #include - #include #endif #elif defined(_SAPP_IOS) #import #if !defined(SOKOL_METAL) #import - #include - #include #endif #endif #elif defined(_SAPP_EMSCRIPTEN) - #if defined(SOKOL_GLES3) - #include - #elif defined(SOKOL_GLES2) - #ifndef GL_EXT_PROTOTYPES - #define GL_GLEXT_PROTOTYPES - #endif - #include - #include - #elif defined(SOKOL_WGPU) + #if defined(SOKOL_WGPU) #include #endif #include @@ -1269,12 +1481,19 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #include #include #include - #if !defined(SOKOL_WIN32_FORCE_MAIN) - #pragma comment (linker, "/subsystem:windows") + #if !defined(SOKOL_NO_ENTRY) // if SOKOL_NO_ENTRY is defined, it's the applications' responsibility to use the right subsystem + #if defined(SOKOL_WIN32_FORCE_MAIN) + #pragma comment (linker, "/subsystem:console") + #else + #pragma comment (linker, "/subsystem:windows") + #endif #endif + #include /* freopen_s() */ + #include /* wcslen() */ + #pragma comment (lib, "kernel32") #pragma comment (lib, "user32") - #pragma comment (lib, "Shell32") + #pragma comment (lib, "shell32") /* CommandLineToArgvW, DragQueryFileW, DragFinished */ #if defined(SOKOL_D3D11) #pragma comment (lib, "dxgi") #pragma comment (lib, "d3d11") @@ -1290,6 +1509,8 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif #include #include + // DXGI_SWAP_EFFECT_FLIP_DISCARD is only defined in newer Windows SDKs, so don't depend on it + #define _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD (4) #endif #ifndef WM_MOUSEHWHEEL /* see https://github.com/floooh/sokol/issues/138 */ #define WM_MOUSEHWHEEL (0x020E) @@ -1298,7 +1519,6 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #ifndef NOMINMAX #define NOMINMAX #endif - #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ @@ -1331,15 +1551,6 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #include #include #include - #if defined(SOKOL_GLES3) - #include - #else - #ifndef GL_EXT_PROTOTYPES - #define GL_GLEXT_PROTOTYPES - #endif - #include - #include - #endif #elif defined(_SAPP_LINUX) #define GL_GLEXT_PROTOTYPES #include @@ -1347,37 +1558,23 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #include #include #include + #include #include #include #include /* CARD32 */ - #include #include /* dlopen, dlsym, dlclose */ #include /* LONG_MAX */ + #include /* only used a linker-guard, search for _sapp_linux_run() and see first comment */ #endif /*== MACOS DECLARATIONS ======================================================*/ #if defined(_SAPP_MACOS) -@interface SokolWindow : NSWindow { -} -@end - - @interface MyView2 : NSView - @end - - MyView2* g_view; - -// A custom NSWindow interface to handle events in borderless windows. -@implementation SokolWindow -- (BOOL)canBecomeKeyWindow { return YES; } // needed for NSWindowStyleMaskBorderless -- (BOOL)canBecomeMainWindow { return YES; } -@end - - @interface _sapp_macos_app_delegate : NSObject @end +@interface _sapp_macos_window : NSWindow +@end @interface _sapp_macos_window_delegate : NSObject @end - #if defined(SOKOL_METAL) @interface _sapp_macos_view : MTKView @end @@ -1390,8 +1587,7 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } typedef struct { uint32_t flags_changed_store; uint8_t mouse_buttons; -// NSWindow* window; - SokolWindow* window; + NSWindow* window; NSTrackingArea* tracking_area; _sapp_macos_app_delegate* app_dlg; _sapp_macos_window_delegate* win_dlg; @@ -1473,6 +1669,8 @@ typedef struct { ID3D11DeviceContext* device_context; ID3D11Texture2D* rt; ID3D11RenderTargetView* rtv; + ID3D11Texture2D* msaa_rt; + ID3D11RenderTargetView* msaa_rtv; ID3D11Texture2D* ds; ID3D11DepthStencilView* dsv; DXGI_SWAP_CHAIN_DESC swap_chain_desc; @@ -1508,7 +1706,9 @@ typedef struct { typedef struct { HWND hwnd; HDC dc; + UINT orig_codepage; LONG mouse_locked_x, mouse_locked_y; + bool is_win10_or_greater; bool in_create_window; bool iconified; bool mouse_tracked; @@ -1648,6 +1848,8 @@ typedef struct { /*== LINUX DECLARATIONS ======================================================*/ #if defined(_SAPP_LINUX) +#define _SAPP_X11_XDND_VERSION (5) + #define GLX_VENDOR 1 #define GLX_RGBA_BIT 0x00000001 #define GLX_WINDOW_BIT 0x00000001 @@ -1683,7 +1885,7 @@ typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext); typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable); typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); -typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName); +typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const char *procName); typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); @@ -1701,6 +1903,22 @@ typedef struct { int minor; } _sapp_xi_t; +typedef struct { + int version; + Window source; + Atom format; + Atom XdndAware; + Atom XdndEnter; + Atom XdndPosition; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndDrop; + Atom XdndFinished; + Atom XdndSelection; + Atom XdndTypeList; + Atom text_uri_list; +} _sapp_xdnd_t; + typedef struct { uint8_t mouse_buttons; Display* display; @@ -1721,6 +1939,7 @@ typedef struct { Atom NET_WM_STATE; Atom NET_WM_STATE_FULLSCREEN; _sapp_xi_t xi; + _sapp_xdnd_t xdnd; } _sapp_x11_t; typedef struct { @@ -1779,7 +1998,7 @@ typedef struct { #if defined(_SAPP_MACOS) || defined(_SAPP_IOS) // this is ARC compatible #if defined(__cplusplus) - #define _SAPP_CLEAR(type, item) { item = { }; } + #define _SAPP_CLEAR(type, item) { item = (type) { }; } #else #define _SAPP_CLEAR(type, item) { item = (type) { 0 }; } #endif @@ -1793,6 +2012,15 @@ typedef struct { char* buffer; } _sapp_clipboard_t; +typedef struct { + bool enabled; + int max_files; + int max_path_length; + int num_files; + int buf_size; + char* buffer; +} _sapp_drop_t; + typedef struct { float x, y; float dx, dy; @@ -1825,6 +2053,7 @@ typedef struct { sapp_event event; _sapp_mouse_t mouse; _sapp_clipboard_t clipboard; + _sapp_drop_t drop; #if defined(_SAPP_MACOS) _sapp_macos_t macos; #elif defined(_SAPP_IOS) @@ -1849,376 +2078,13 @@ typedef struct { _sapp_x11_t x11; _sapp_glx_t glx; #endif - char html5_canvas_name[_SAPP_MAX_TITLE_LENGTH]; + char html5_canvas_selector[_SAPP_MAX_TITLE_LENGTH]; 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]; -bool native_render; } _sapp_t; static _sapp_t _sapp; -/*=== OPTIONAL MINI GL LOADER FOR WIN32/WGL ==================================*/ -#if defined(_SAPP_WIN32) && defined(SOKOL_GLCORE33) && !defined(SOKOL_WIN32_NO_GL_LOADER) -#define __gl_h_ 1 -#define __gl32_h_ 1 -#define __gl31_h_ 1 -#define __GL_H__ 1 -#define __glext_h_ 1 -#define __GLEXT_H_ 1 -#define __gltypes_h_ 1 -#define __glcorearb_h_ 1 -#define __gl_glcorearb_h_ 1 -#define GL_APIENTRY APIENTRY - -typedef unsigned int GLenum; -typedef unsigned int GLuint; -typedef int GLsizei; -typedef char GLchar; -typedef ptrdiff_t GLintptr; -typedef ptrdiff_t GLsizeiptr; -typedef double GLclampd; -typedef unsigned short GLushort; -typedef unsigned char GLubyte; -typedef unsigned char GLboolean; -typedef uint64_t GLuint64; -typedef double GLdouble; -typedef unsigned short GLhalf; -typedef float GLclampf; -typedef unsigned int GLbitfield; -typedef signed char GLbyte; -typedef short GLshort; -typedef void GLvoid; -typedef int64_t GLint64; -typedef float GLfloat; -typedef struct __GLsync * GLsync; -typedef int GLint; -#define GL_INT_2_10_10_10_REV 0x8D9F -#define GL_R32F 0x822E -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_R16F 0x822D -#define GL_COLOR_ATTACHMENT22 0x8CF6 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_NUM_EXTENSIONS 0x821D -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_INCR 0x1E02 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_STATIC_DRAW 0x88E4 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_CONSTANT_COLOR 0x8001 -#define GL_DECR_WRAP 0x8508 -#define GL_R8 0x8229 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_SHORT 0x1402 -#define GL_DEPTH_TEST 0x0B71 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_LINK_STATUS 0x8B82 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_RGBA16F 0x881A -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_STREAM_DRAW 0x88E0 -#define GL_ONE 1 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA8 0x8058 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_RGBA4 0x8056 -#define GL_RGB8 0x8051 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_STENCIL 0x1802 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_DEPTH 0x1801 -#define GL_FRONT 0x0404 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_REPEAT 0x2901 -#define GL_RGBA 0x1908 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_DECR 0x1E03 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_FLOAT 0x1406 -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_COLOR 0x1800 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_TRIANGLES 0x0004 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_NONE 0 -#define GL_SRC_COLOR 0x0300 -#define GL_BYTE 0x1400 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_LINE_STRIP 0x0003 -#define GL_TEXTURE_3D 0x806F -#define GL_CW 0x0900 -#define GL_LINEAR 0x2601 -#define GL_RENDERBUFFER 0x8D41 -#define GL_GEQUAL 0x0206 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_RGBA32F 0x8814 -#define GL_BLEND 0x0BE2 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_EXTENSIONS 0x1F03 -#define GL_NO_ERROR 0 -#define GL_REPLACE 0x1E01 -#define GL_KEEP 0x1E00 -#define GL_CCW 0x0901 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_RGB 0x1907 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_FALSE 0 -#define GL_ZERO 0 -#define GL_CULL_FACE 0x0B44 -#define GL_INVERT 0x150A -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_NEAREST 0x2600 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_LEQUAL 0x0203 -#define GL_STENCIL_TEST 0x0B90 -#define GL_DITHER 0x0BD0 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_EQUAL 0x0202 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RGB5 0x8050 -#define GL_LINES 0x0001 -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_SRC_ALPHA 0x0302 -#define GL_INCR_WRAP 0x8507 -#define GL_LESS 0x0201 -#define GL_MULTISAMPLE 0x809D -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_BACK 0x0405 -#define GL_ALWAYS 0x0207 -#define GL_FUNC_ADD 0x8006 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_NOTEQUAL 0x0205 -#define GL_DST_COLOR 0x0306 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_RED 0x1903 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_DST_ALPHA 0x0304 -#define GL_RGB5_A1 0x8057 -#define GL_GREATER 0x0204 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_TRUE 1 -#define GL_NEVER 0x0200 -#define GL_POINTS 0x0000 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_RGBA_INTEGER 0x8D99 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_RGBA16 0x805B -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_CURRENT_PROGRAM 0x8B8D - -// X Macro list of GL function names and signatures -#define _SAPP_GL_FUNCS \ - _SAPP_XMACRO(glBindVertexArray, void, (GLuint array)) \ - _SAPP_XMACRO(glFramebufferTextureLayer, void, (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)) \ - _SAPP_XMACRO(glGenFramebuffers, void, (GLsizei n, GLuint * framebuffers)) \ - _SAPP_XMACRO(glBindFramebuffer, void, (GLenum target, GLuint framebuffer)) \ - _SAPP_XMACRO(glBindRenderbuffer, void, (GLenum target, GLuint renderbuffer)) \ - _SAPP_XMACRO(glGetStringi, const GLubyte *, (GLenum name, GLuint index)) \ - _SAPP_XMACRO(glClearBufferfi, void, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) \ - _SAPP_XMACRO(glClearBufferfv, void, (GLenum buffer, GLint drawbuffer, const GLfloat * value)) \ - _SAPP_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \ - _SAPP_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \ - _SAPP_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \ - _SAPP_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SAPP_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SAPP_XMACRO(glUseProgram, void, (GLuint program)) \ - _SAPP_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \ - _SAPP_XMACRO(glLinkProgram, void, (GLuint program)) \ - _SAPP_XMACRO(glGetUniformLocation, GLint, (GLuint program, const GLchar * name)) \ - _SAPP_XMACRO(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint * params)) \ - _SAPP_XMACRO(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ - _SAPP_XMACRO(glGetAttribLocation, GLint, (GLuint program, const GLchar * name)) \ - _SAPP_XMACRO(glDisableVertexAttribArray, void, (GLuint index)) \ - _SAPP_XMACRO(glDeleteShader, void, (GLuint shader)) \ - _SAPP_XMACRO(glDeleteProgram, void, (GLuint program)) \ - _SAPP_XMACRO(glCompileShader, void, (GLuint shader)) \ - _SAPP_XMACRO(glStencilFuncSeparate, void, (GLenum face, GLenum func, GLint ref, GLuint mask)) \ - _SAPP_XMACRO(glStencilOpSeparate, void, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) \ - _SAPP_XMACRO(glRenderbufferStorageMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)) \ - _SAPP_XMACRO(glDrawBuffers, void, (GLsizei n, const GLenum * bufs)) \ - _SAPP_XMACRO(glVertexAttribDivisor, void, (GLuint index, GLuint divisor)) \ - _SAPP_XMACRO(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void * data)) \ - _SAPP_XMACRO(glGenBuffers, void, (GLsizei n, GLuint * buffers)) \ - _SAPP_XMACRO(glCheckFramebufferStatus, GLenum, (GLenum target)) \ - _SAPP_XMACRO(glFramebufferRenderbuffer, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \ - _SAPP_XMACRO(glCompressedTexImage2D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data)) \ - _SAPP_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \ - _SAPP_XMACRO(glActiveTexture, void, (GLenum texture)) \ - _SAPP_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \ - _SAPP_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \ - _SAPP_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \ - _SAPP_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \ - _SAPP_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \ - _SAPP_XMACRO(glDrawElements, void, (GLenum mode, GLsizei count, GLenum type, const void * indices)) \ - _SAPP_XMACRO(glDeleteFramebuffers, void, (GLsizei n, const GLuint * framebuffers)) \ - _SAPP_XMACRO(glBlendEquationSeparate, void, (GLenum modeRGB, GLenum modeAlpha)) \ - _SAPP_XMACRO(glDeleteTextures, void, (GLsizei n, const GLuint * textures)) \ - _SAPP_XMACRO(glGetProgramiv, void, (GLuint program, GLenum pname, GLint * params)) \ - _SAPP_XMACRO(glBindTexture, void, (GLenum target, GLuint texture)) \ - _SAPP_XMACRO(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels)) \ - _SAPP_XMACRO(glCreateShader, GLuint, (GLenum type)) \ - _SAPP_XMACRO(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels)) \ - _SAPP_XMACRO(glClearDepth, void, (GLdouble depth)) \ - _SAPP_XMACRO(glFramebufferTexture2D, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) \ - _SAPP_XMACRO(glCreateProgram, GLuint, (void)) \ - _SAPP_XMACRO(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ - _SAPP_XMACRO(glDeleteBuffers, void, (GLsizei n, const GLuint * buffers)) \ - _SAPP_XMACRO(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) \ - _SAPP_XMACRO(glDrawElementsInstanced, void, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) \ - _SAPP_XMACRO(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)) \ - _SAPP_XMACRO(glUniform1i, void, (GLint location, GLint v0)) \ - _SAPP_XMACRO(glDisable, void, (GLenum cap)) \ - _SAPP_XMACRO(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ - _SAPP_XMACRO(glBindBuffer, void, (GLenum target, GLuint buffer)) \ - _SAPP_XMACRO(glDeleteVertexArrays, void, (GLsizei n, const GLuint * arrays)) \ - _SAPP_XMACRO(glDepthMask, void, (GLboolean flag)) \ - _SAPP_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \ - _SAPP_XMACRO(glClearStencil, void, (GLint s)) \ - _SAPP_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ - _SAPP_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SAPP_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \ - _SAPP_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \ - _SAPP_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \ - _SAPP_XMACRO(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) \ - _SAPP_XMACRO(glGetIntegerv, void, (GLenum pname, GLint * data)) \ - _SAPP_XMACRO(glEnable, void, (GLenum cap)) \ - _SAPP_XMACRO(glBlitFramebuffer, void, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) \ - _SAPP_XMACRO(glStencilMask, void, (GLuint mask)) \ - _SAPP_XMACRO(glAttachShader, void, (GLuint program, GLuint shader)) \ - _SAPP_XMACRO(glGetError, GLenum, (void)) \ - _SAPP_XMACRO(glClearColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ - _SAPP_XMACRO(glBlendColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ - _SAPP_XMACRO(glTexParameterf, void, (GLenum target, GLenum pname, GLfloat param)) \ - _SAPP_XMACRO(glTexParameterfv, void, (GLenum target, GLenum pname, GLfloat* params)) \ - _SAPP_XMACRO(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ - _SAPP_XMACRO(glDepthFunc, void, (GLenum func)) \ - _SAPP_XMACRO(glStencilOp , void, (GLenum fail, GLenum zfail, GLenum zpass)) \ - _SAPP_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \ - _SAPP_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \ - _SAPP_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \ - _SAPP_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ - _SAPP_XMACRO(glReadBuffer, void, (GLenum src)) \ - _SAPP_XMACRO(glClear, void, (GLbitfield mask)) \ - _SAPP_XMACRO(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)) \ - _SAPP_XMACRO(glGenVertexArrays, void, (GLsizei n, GLuint * arrays)) \ - _SAPP_XMACRO(glFrontFace, void, (GLenum mode)) \ - _SAPP_XMACRO(glCullFace, void, (GLenum mode)) - -// generate GL function pointer typedefs -#define _SAPP_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args; -_SAPP_GL_FUNCS -#undef _SAPP_XMACRO - -// generate GL function pointers -#define _SAPP_XMACRO(name, ret, args) static PFN_ ## name name; -_SAPP_GL_FUNCS -#undef _SAPP_XMACRO - -// helper function to lookup GL functions in GL DLL -_SOKOL_PRIVATE void* _sapp_win32_glgetprocaddr(const char* name) { - void* proc_addr = (void*) _sapp.wgl.GetProcAddress(name); - if (0 == proc_addr) { - proc_addr = (void*) GetProcAddress(_sapp.wgl.opengl32, name); - } - SOKOL_ASSERT(proc_addr); - return proc_addr; -} - -// populate GL function pointers -_SOKOL_PRIVATE void _sapp_win32_gl_loadfuncs(void) { - SOKOL_ASSERT(_sapp.wgl.GetProcAddress); - SOKOL_ASSERT(_sapp.wgl.opengl32); - #define _SAPP_XMACRO(name, ret, args) name = (PFN_ ## name) _sapp_win32_glgetprocaddr(#name); - _SAPP_GL_FUNCS - #undef _SAPP_XMACRO -} - -#endif // _SAPP_WIN32 && SOKOL_GLCORE33 && !SOKOL_WIN32_NO_GL_LOADER - /*=== PRIVATE HELPER FUNCTIONS ===============================================*/ _SOKOL_PRIVATE void _sapp_fail(const char* msg) { if (_sapp.desc.fail_cb) { @@ -2243,23 +2109,7 @@ _SOKOL_PRIVATE void _sapp_call_init(void) { _sapp.init_called = true; } - - _SOKOL_PRIVATE void _sapp_call_frame(void) { - if (_sapp.native_render) { - return; - } - if (_sapp.init_called && !_sapp.cleanup_called) { - if (_sapp.desc.frame_cb) { - _sapp.desc.frame_cb(); - } - else if (_sapp.desc.frame_userdata_cb) { - _sapp.desc.frame_userdata_cb(_sapp.desc.user_data); - } - } -} - -_SOKOL_PRIVATE void _sapp_call_frame2(void) { if (_sapp.init_called && !_sapp.cleanup_called) { if (_sapp.desc.frame_cb) { _sapp.desc.frame_cb(); @@ -2300,7 +2150,24 @@ _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { } } -_SOKOL_PRIVATE void _sapp_strcpy(const char* src, char* dst, int max_len) { +_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) { + SOKOL_ASSERT(_sapp.drop.buffer); + SOKOL_ASSERT((index >= 0) && (index <= _sapp.drop.max_files)); + int offset = index * _sapp.drop.max_path_length; + SOKOL_ASSERT(offset < _sapp.drop.buf_size); + return &_sapp.drop.buffer[offset]; +} + +/* Copy a string into a fixed size buffer with guaranteed zero- + termination. + + Return false if the string didn't fit into the buffer and had to be clamped. + + FIXME: Currently UTF-8 strings might become invalid if the string + is clamped, because the last zero-byte might be written into + the middle of a multi-byte sequence. +*/ +_SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { SOKOL_ASSERT(src && dst && (max_len > 0)); char* const end = &(dst[max_len-1]); char c = 0; @@ -2314,6 +2181,10 @@ _SOKOL_PRIVATE void _sapp_strcpy(const char* src, char* dst, int max_len) { /* truncated? */ if (c != 0) { *end = 0; + return false; + } + else { + return true; } } @@ -2325,6 +2196,8 @@ _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { desc.swap_interval = _sapp_def(desc.swap_interval, 1); desc.html5_canvas_name = _sapp_def(desc.html5_canvas_name, "canvas"); desc.clipboard_size = _sapp_def(desc.clipboard_size, 8192); + desc.max_dropped_files = _sapp_def(desc.max_dropped_files, 1); + desc.max_dropped_file_path_length = _sapp_def(desc.max_dropped_file_path_length, 2048); desc.window_title = _sapp_def(desc.window_title, "sokol_app"); return desc; } @@ -2339,20 +2212,27 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.framebuffer_height = _sapp.window_height; _sapp.sample_count = _sapp.desc.sample_count; _sapp.swap_interval = _sapp.desc.swap_interval; - _sapp_strcpy(_sapp.desc.html5_canvas_name, _sapp.html5_canvas_name, sizeof(_sapp.html5_canvas_name)); - _sapp.desc.html5_canvas_name = _sapp.html5_canvas_name; + _sapp.html5_canvas_selector[0] = '#'; + _sapp_strcpy(_sapp.desc.html5_canvas_name, &_sapp.html5_canvas_selector[1], sizeof(_sapp.html5_canvas_selector) - 1); + _sapp.desc.html5_canvas_name = &_sapp.html5_canvas_selector[1]; _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site; _sapp.clipboard.enabled = _sapp.desc.enable_clipboard; if (_sapp.clipboard.enabled) { _sapp.clipboard.buf_size = _sapp.desc.clipboard_size; - _sapp.clipboard.buffer = (char*) SOKOL_CALLOC(1, _sapp.clipboard.buf_size); + _sapp.clipboard.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.clipboard.buf_size); + } + _sapp.drop.enabled = _sapp.desc.enable_dragndrop; + if (_sapp.drop.enabled) { + _sapp.drop.max_files = _sapp.desc.max_dropped_files; + _sapp.drop.max_path_length = _sapp.desc.max_dropped_file_path_length; + _sapp.drop.buf_size = _sapp.drop.max_files * _sapp.drop.max_path_length; + _sapp.drop.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.drop.buf_size); } _sapp_strcpy(_sapp.desc.window_title, _sapp.window_title, sizeof(_sapp.window_title)); _sapp.desc.window_title = _sapp.window_title; _sapp.dpi_scale = 1.0f; _sapp.fullscreen = _sapp.desc.fullscreen; _sapp.mouse.shown = true; - _sapp.native_render = _sapp.desc.native_render; } _SOKOL_PRIVATE void _sapp_discard_state(void) { @@ -2360,6 +2240,10 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) { SOKOL_ASSERT(_sapp.clipboard.buffer); SOKOL_FREE((void*)_sapp.clipboard.buffer); } + if (_sapp.drop.enabled) { + SOKOL_ASSERT(_sapp.drop.buffer); + SOKOL_FREE((void*)_sapp.drop.buffer); + } _SAPP_CLEAR(_sapp_t, _sapp); } @@ -2392,6 +2276,13 @@ _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { } } +_SOKOL_PRIVATE void _sapp_clear_drop_buffer(void) { + if (_sapp.drop.enabled) { + SOKOL_ASSERT(_sapp.drop.buffer); + memset(_sapp.drop.buffer, 0, (size_t)_sapp.drop.buf_size); + } +} + _SOKOL_PRIVATE void _sapp_frame(void) { if (_sapp.first_frame) { _sapp.first_frame = false; @@ -2604,11 +2495,15 @@ _SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { } } +/* NOTE: unlike the iOS version of this function, the macOS version + can dynamically update the DPI scaling factor when a window is moved + between HighDPI / LowDPI screens. +*/ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { #if defined(SOKOL_METAL) - const CGSize fb_size = [_sapp.macos.view drawableSize]; - _sapp.framebuffer_width = fb_size.width; - _sapp.framebuffer_height = fb_size.height; + const NSRect fb_rect = [_sapp.macos.view bounds]; + _sapp.framebuffer_width = fb_rect.size.width * _sapp.dpi_scale; + _sapp.framebuffer_height = fb_rect.size.height * _sapp.dpi_scale; #elif defined(SOKOL_GLCORE33) const NSRect fb_rect = [_sapp.macos.view convertRectToBacking:[_sapp.macos.view frame]]; _sapp.framebuffer_width = fb_rect.size.width; @@ -2630,6 +2525,16 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { _sapp.window_height = 1; } _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width; + + /* NOTE: _sapp_macos_update_dimensions() isn't called each frame, but only + when the window size actually changes, so resizing the MTKView's + in each call is fine even when MTKView doesn't ignore setting an + identical drawableSize. + */ + #if defined(SOKOL_METAL) + CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height }; + _sapp.macos.view.drawableSize = drawable_size; + #endif } _SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(void) { @@ -2670,9 +2575,9 @@ _SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { [_sapp.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window_title]]; } -_SOKOL_PRIVATE void _sapp_macos_update_mouse(void) { +_SOKOL_PRIVATE void _sapp_macos_update_mouse(NSEvent* event) { if (!_sapp.mouse.locked) { - const NSPoint mouse_pos = [_sapp.macos.window mouseLocationOutsideOfEventStream]; + const NSPoint mouse_pos = event.locationInWindow; float new_x = mouse_pos.x * _sapp.dpi_scale; float new_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1; /* don't update dx/dy in the very first update */ @@ -2714,19 +2619,16 @@ _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { stack with calls to sapp_show_mouse() */ if (_sapp.mouse.locked) { - [NSEvent setMouseCoalescingEnabled:NO]; CGAssociateMouseAndMouseCursorPosition(NO); CGDisplayHideCursor(kCGDirectMainDisplay); } else { CGDisplayShowCursor(kCGDirectMainDisplay); CGAssociateMouseAndMouseCursorPosition(YES); - [NSEvent setMouseCoalescingEnabled:YES]; } } _SOKOL_PRIVATE void _sapp_macos_frame(void) { - _sapp_macos_update_mouse(); _sapp_frame(); if (_sapp.quit_requested || _sapp.quit_ordered) { [_sapp.macos.window performClose:nil]; @@ -2740,23 +2642,23 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { NSRect screen_rect = NSScreen.mainScreen.frame; _sapp.window_width = screen_rect.size.width; _sapp.window_height = screen_rect.size.height; - if (_sapp.desc.high_dpi) { - _sapp.framebuffer_width = 2 * _sapp.window_width; - _sapp.framebuffer_height = 2 * _sapp.window_height; - } - else { - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; - } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; } - const NSUInteger style = _sapp.desc.fullscreen ? NSWindowStyleMaskBorderless : + if (_sapp.desc.high_dpi) { + _sapp.framebuffer_width = 2 * _sapp.window_width; + _sapp.framebuffer_height = 2 * _sapp.window_height; + } + else { + _sapp.framebuffer_width = _sapp.window_width; + _sapp.framebuffer_height = _sapp.window_height; + } + _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; + const NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; NSRect window_rect = NSMakeRect(0, 0, _sapp.window_width, _sapp.window_height); - _sapp.macos.window = [[SokolWindow alloc] + _sapp.macos.window = [[_sapp_macos_window alloc] initWithContentRect:window_rect styleMask:style backing:NSBackingStoreBuffered @@ -2765,27 +2667,6 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp.macos.window.title = [NSString stringWithUTF8String:_sapp.window_title]; _sapp.macos.window.acceptsMouseMovedEvents = YES; _sapp.macos.window.restorable = YES; - _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 ); _sapp.macos.win_dlg = [[_sapp_macos_window_delegate alloc] init]; _sapp.macos.window.delegate = _sapp.macos.win_dlg; @@ -2797,13 +2678,10 @@ _SAPP_OBJC_RELEASE( menu_bar ); _sapp.macos.view.device = _sapp.macos.mtl_device; _sapp.macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; _sapp.macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.macos.view.sampleCount = _sapp.sample_count; + _sapp.macos.view.sampleCount = (NSUInteger) _sapp.sample_count; + _sapp.macos.view.autoResizeDrawable = false; _sapp.macos.window.contentView = _sapp.macos.view; [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - if (!_sapp.desc.high_dpi) { - CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height }; - _sapp.macos.view.drawableSize = drawable_size; - } _sapp.macos.view.layer.magnificationFilter = kCAFilterNearest; #elif defined(SOKOL_GLCORE33) NSOpenGLPixelFormatAttribute attrs[32]; @@ -2818,7 +2696,7 @@ _SAPP_OBJC_RELEASE( menu_bar ); if (_sapp.sample_count > 1) { attrs[i++] = NSOpenGLPFAMultisample; attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1; - attrs[i++] = NSOpenGLPFASamples; attrs[i++] = _sapp.sample_count; + attrs[i++] = NSOpenGLPFASamples; attrs[i++] = (NSOpenGLPixelFormatAttribute)_sapp.sample_count; } else { attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; @@ -2842,7 +2720,6 @@ _SAPP_OBJC_RELEASE( menu_bar ); _sapp.macos.window.contentView = _sapp.macos.view; [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 target:_sapp.macos.view selector:@selector(timerFired:) @@ -2852,49 +2729,16 @@ _SAPP_OBJC_RELEASE( menu_bar ); timer_obj = nil; #endif _sapp.valid = true; - /* if (_sapp.fullscreen) { - // on GL, this already toggles a rendered frame, so set the valid flag before + /* on GL, this already toggles a rendered frame, so set the valid flag before */ [_sapp.macos.window toggleFullScreen:self]; } else { [_sapp.macos.window center]; } - */ - - - /////////////////////////////////////////////////////// - // Create a child view for native rendering - - CGRect wRect = _sapp.macos.window.frame; - NSView *contentView =_sapp.macos.window.contentView; - CGRect cRect = contentView.frame; - - CGRect rect = CGRectMake(wRect.origin.x, wRect.origin.y, cRect.size.width, cRect.size.height); - NSWindow *overlayWindow = [[NSWindow alloc]initWithContentRect:rect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - //overlayWindow.backgroundColor = [NSColor whiteColor]; - - //overlayWindow.backgroundColor = [[NSColor whiteColor] colorWithAlphaComponent:0]; - [overlayWindow setOpaque:YES]; - [_sapp.macos.window setIgnoresMouseEvents:NO]; - //[_sapp.macos.window setOpaque:NO]; - - //overlayWindow.alphaValue =0.1f;///.1f; - - g_view = [[MyView2 alloc] init]; - overlayWindow.contentView = g_view; - - [ contentView addSubview:g_view]; -//[ _sapp.macos.window addChildWindow:overlayWindow ordered:NSWindowAbove]; - - ////////////////////////////////// - - [_sapp.macos.window center]; [_sapp.macos.window makeKeyAndOrderFront:nil]; _sapp_macos_update_dimensions(); + [NSEvent setMouseCoalescingEnabled:NO]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -2910,9 +2754,6 @@ _SAPP_OBJC_RELEASE( menu_bar ); } @end -//#include "/Users/alex/code/v/thirdparty/sokol/sokol_app2.h" -#include "sokol_app2.h" - @implementation _sapp_macos_window_delegate - (BOOL)windowShouldClose:(id)sender { _SOKOL_UNUSED(sender); @@ -2965,6 +2806,58 @@ _SAPP_OBJC_RELEASE( menu_bar ); } @end +@implementation _sapp_macos_window +- (instancetype)initWithContentRect:(NSRect)contentRect + styleMask:(NSWindowStyleMask)style + backing:(NSBackingStoreType)backingStoreType + defer:(BOOL)flag { + if (self = [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:flag]) { + #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]]; + #endif + } + return self; +} + +- (NSDragOperation)draggingEntered:(id)sender { + return NSDragOperationCopy; +} + +- (NSDragOperation)draggingUpdated:(id)sender { + return NSDragOperationCopy; +} + +- (BOOL)performDragOperation:(id)sender { + #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + NSPasteboard *pboard = [sender draggingPasteboard]; + if ([pboard.types containsObject:NSPasteboardTypeFileURL]) { + _sapp_clear_drop_buffer(); + _sapp.drop.num_files = ((int)pboard.pasteboardItems.count > _sapp.drop.max_files) ? _sapp.drop.max_files : pboard.pasteboardItems.count; + bool drop_failed = false; + for (int i = 0; i < _sapp.drop.num_files; i++) { + NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]]; + if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { + SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); + drop_failed = true; + break; + } + } + if (!drop_failed) { + if (_sapp_events_enabled()) { + _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_call_event(&_sapp.event); + } + } + else { + _sapp_clear_drop_buffer(); + _sapp.drop.num_files = 0; + } + return YES; + } + #endif + return NO; +} +@end @implementation _sapp_macos_view #if defined(SOKOL_GLCORE33) @@ -2994,13 +2887,54 @@ _SAPP_OBJC_RELEASE( menu_bar ); } #endif -//int g_is_native = 0; +_SOKOL_PRIVATE void _sapp_macos_poll_input_events() { + /* + + NOTE: late event polling temporarily out-commented to check if this + causes infrequent and almost impossible to reproduce probelms with the + window close events, see: + https://github.com/floooh/sokol/pull/483#issuecomment-805148815 + + + const NSEventMask mask = NSEventMaskLeftMouseDown | + NSEventMaskLeftMouseUp| + NSEventMaskRightMouseDown | + NSEventMaskRightMouseUp | + NSEventMaskMouseMoved | + NSEventMaskLeftMouseDragged | + NSEventMaskRightMouseDragged | + NSEventMaskMouseEntered | + NSEventMaskMouseExited | + NSEventMaskKeyDown | + NSEventMaskKeyUp | + NSEventMaskCursorUpdate | + NSEventMaskScrollWheel | + NSEventMaskTabletPoint | + NSEventMaskTabletProximity | + NSEventMaskOtherMouseDown | + NSEventMaskOtherMouseUp | + NSEventMaskOtherMouseDragged | + NSEventMaskPressure | + NSEventMaskDirectTouch; + @autoreleasepool { + for (;;) { + // NOTE: using NSDefaultRunLoopMode here causes stuttering in the GL backend, + // see: https://github.com/floooh/sokol/issues/486 + NSEvent* event = [NSApp nextEventMatchingMask:mask untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES]; + if (event == nil) { + break; + } + [NSApp sendEvent:event]; + } + } + */ +} - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); + /* Catch any last-moment input events */ + _sapp_macos_poll_input_events(); _sapp_macos_frame(); -// puts("drawRect() metal"); -// NSLog(@"rect %@", NSStringFromRect(rect)); #if !defined(SOKOL_METAL) [[_sapp.macos.view openGLContext] flushBuffer]; #endif @@ -3015,10 +2949,6 @@ _SAPP_OBJC_RELEASE( menu_bar ); - (BOOL)acceptsFirstResponder { return YES; } - - - (BOOL)acceptsFirstMouse:(NSEvent *)event { - return YES; - } - (void)updateTrackingAreas { if (_sapp.macos.tracking_area != nil) { [self removeTrackingArea:_sapp.macos.tracking_area]; @@ -3035,6 +2965,7 @@ _SAPP_OBJC_RELEASE( menu_bar ); [super updateTrackingAreas]; } - (void)mouseEntered:(NSEvent*)event { + _sapp_macos_update_mouse(event); /* don't send mouse enter/leave while dragging (so that it behaves the same as on Windows while SetCapture is active */ @@ -3043,40 +2974,47 @@ _SAPP_OBJC_RELEASE( menu_bar ); } } - (void)mouseExited:(NSEvent*)event { - // NSLog(@"mouse exited"); + _sapp_macos_update_mouse(event); if (0 == _sapp.macos.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } } - (void)mouseDown:(NSEvent*)event { + _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons |= (1<MIDDLE macos bug - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_LEFT , _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); } - (void)rightMouseDragged:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (_sapp.mouse.locked) { _sapp.mouse.dx = [event deltaX]; _sapp.mouse.dy = [event deltaY]; } - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } - (void)scrollWheel:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (_sapp_events_enabled()) { float dx = (float) event.scrollingDeltaX; float dy = (float) event.scrollingDeltaY; @@ -3268,8 +3208,10 @@ _SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet _SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) { CGRect screen_rect = UIScreen.mainScreen.bounds; - _sapp.window_width = (int) screen_rect.size.width; - _sapp.window_height = (int) screen_rect.size.height; + _sapp.framebuffer_width = (int)(screen_rect.size.width * _sapp.dpi_scale); + _sapp.framebuffer_height = (int)(screen_rect.size.height * _sapp.dpi_scale); + _sapp.window_width = (int)screen_rect.size.width; + _sapp.window_height = (int)screen_rect.size.height; int cur_fb_width, cur_fb_height; #if defined(SOKOL_METAL) const CGSize fb_size = _sapp.ios.view.drawableSize; @@ -3279,15 +3221,18 @@ _SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) { cur_fb_width = (int) _sapp.ios.view.drawableWidth; cur_fb_height = (int) _sapp.ios.view.drawableHeight; #endif - const bool dim_changed = - (_sapp.framebuffer_width != cur_fb_width) || - (_sapp.framebuffer_height != cur_fb_height); - _sapp.framebuffer_width = cur_fb_width; - _sapp.framebuffer_height = cur_fb_height; - SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0)); - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; - if (dim_changed && !_sapp.first_frame) { - _sapp_ios_app_event(SAPP_EVENTTYPE_RESIZED); + const bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || + (_sapp.framebuffer_height != cur_fb_height); + if (dim_changed) { + #if defined(SOKOL_METAL) + const CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height }; + _sapp.ios.view.drawableSize = drawable_size; + #else + // nothing to do here, GLKView correctly respects the view's contentScaleFactor + #endif + if (!_sapp.first_frame) { + _sapp_ios_app_event(SAPP_EVENTTYPE_RESIZED); + } } } @@ -3337,14 +3282,13 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { _sapp.window_width = screen_rect.size.width; _sapp.window_height = screen_rect.size.height; if (_sapp.desc.high_dpi) { - _sapp.framebuffer_width = 2 * _sapp.window_width; - _sapp.framebuffer_height = 2 * _sapp.window_height; + _sapp.dpi_scale = (float) UIScreen.mainScreen.nativeScale; } else { - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; + _sapp.dpi_scale = 1.0f; } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; + _sapp.framebuffer_width = _sapp.window_width * _sapp.dpi_scale; + _sapp.framebuffer_height = _sapp.window_height * _sapp.dpi_scale; #if defined(SOKOL_METAL) _sapp.ios.mtl_device = MTLCreateSystemDefaultDevice(); _sapp.ios.view = [[_sapp_ios_view alloc] init]; @@ -3352,13 +3296,12 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { _sapp.ios.view.device = _sapp.ios.mtl_device; _sapp.ios.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; _sapp.ios.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.ios.view.sampleCount = _sapp.sample_count; - if (_sapp.desc.high_dpi) { - _sapp.ios.view.contentScaleFactor = 2.0; - } - else { - _sapp.ios.view.contentScaleFactor = 1.0; - } + _sapp.ios.view.sampleCount = (NSUInteger)_sapp.sample_count; + /* NOTE: iOS MTKView seems to ignore thew view's contentScaleFactor + and automatically renders at Retina resolution. We'll disable + autoResize and instead do the resizing in _sapp_ios_update_dimensions() + */ + _sapp.ios.view.autoResizeDrawable = false; _sapp.ios.view.userInteractionEnabled = YES; _sapp.ios.view.multipleTouchEnabled = YES; _sapp.ios.view_ctrl = [[UIViewController alloc] init]; @@ -3381,11 +3324,13 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { _sapp.ios.view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; _sapp.ios.view.drawableDepthFormat = GLKViewDrawableDepthFormat24; _sapp.ios.view.drawableStencilFormat = GLKViewDrawableStencilFormatNone; - _sapp.ios.view.drawableMultisample = GLKViewDrawableMultisampleNone; /* FIXME */ + GLKViewDrawableMultisample msaa = _sapp.sample_count > 1 ? GLKViewDrawableMultisample4X : GLKViewDrawableMultisampleNone; + _sapp.ios.view.drawableMultisample = msaa; _sapp.ios.view.context = _sapp.ios.eagl_ctx; _sapp.ios.view.enableSetNeedsDisplay = NO; _sapp.ios.view.userInteractionEnabled = YES; _sapp.ios.view.multipleTouchEnabled = YES; + // on GLKView, contentScaleFactor appears to work just fine! if (_sapp.desc.high_dpi) { _sapp.ios.view.contentScaleFactor = 2.0; } @@ -3535,6 +3480,8 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { extern "C" { #endif +typedef void (*_sapp_html5_fetch_callback) (const sapp_html5_fetch_response*); + /* this function is called from a JS event handler when the user hides the onscreen keyboard pressing the 'dismiss keyboard key' */ @@ -3557,6 +3504,71 @@ EMSCRIPTEN_KEEPALIVE int _sapp_html5_get_ask_leave_site(void) { return _sapp.html5_ask_leave_site ? 1 : 0; } +EMSCRIPTEN_KEEPALIVE void _sapp_emsc_begin_drop(int num) { + if (!_sapp.drop.enabled) { + return; + } + if (num < 0) { + num = 0; + } + if (num > _sapp.drop.max_files) { + num = _sapp.drop.max_files; + } + _sapp.drop.num_files = num; + _sapp_clear_drop_buffer(); +} + +EMSCRIPTEN_KEEPALIVE void _sapp_emsc_drop(int i, const char* name) { + /* NOTE: name is only the filename part, not a path */ + if (!_sapp.drop.enabled) { + return; + } + if (0 == name) { + return; + } + SOKOL_ASSERT(_sapp.drop.num_files <= _sapp.drop.max_files); + if ((i < 0) || (i >= _sapp.drop.num_files)) { + return; + } + if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { + SOKOL_LOG("sokol_app.h: dropped file path too long!\n"); + _sapp.drop.num_files = 0; + } +} + +EMSCRIPTEN_KEEPALIVE void _sapp_emsc_end_drop(int x, int y) { + if (!_sapp.drop.enabled) { + return; + } + if (0 == _sapp.drop.num_files) { + /* there was an error copying the filenames */ + _sapp_clear_drop_buffer(); + return; + + } + if (_sapp_events_enabled()) { + _sapp.mouse.x = (float)x * _sapp.dpi_scale; + _sapp.mouse.y = (float)y * _sapp.dpi_scale; + _sapp.mouse.dx = 0.0f; + _sapp.mouse.dy = 0.0f; + _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_call_event(&_sapp.event); + } +} + +EMSCRIPTEN_KEEPALIVE void _sapp_emsc_invoke_fetch_cb(int index, int success, int error_code, _sapp_html5_fetch_callback callback, uint32_t fetched_size, void* buf_ptr, uint32_t buf_size, void* user_data) { + sapp_html5_fetch_response response; + memset(&response, 0, sizeof(response)); + response.succeeded = (0 != success); + response.error_code = (sapp_html5_fetch_error) error_code; + response.file_index = index; + response.fetched_size = fetched_size; + response.buffer_ptr = buf_ptr; + response.buffer_size = buf_size; + response.user_data = user_data; + callback(&response); +} + #ifdef __cplusplus } /* extern "C" */ #endif @@ -3582,21 +3594,21 @@ EM_JS(void, sapp_js_unfocus_textfield, (void), { document.getElementById("_sokol_app_input_element").blur(); }); -EM_JS(void, sapp_js_add_hook_beforeunload, (void), { - Module.sokol_beforeunload = function(_sapp_event) { +EM_JS(void, sapp_js_add_beforeunload_listener, (void), { + Module.sokol_beforeunload = function(event) { if (__sapp_html5_get_ask_leave_site() != 0) { - _sapp_event.preventDefault(); - _sapp_event.returnValue = ' '; + event.preventDefault(); + event.returnValue = ' '; } }; window.addEventListener('beforeunload', Module.sokol_beforeunload); }); -EM_JS(void, sapp_js_remove_hook_beforeunload, (void), { +EM_JS(void, sapp_js_remove_beforeunload_listener, (void), { window.removeEventListener('beforeunload', Module.sokol_beforeunload); }); -EM_JS(void, sapp_js_add_hook_clipboard, (void), { +EM_JS(void, sapp_js_add_clipboard_listener, (void), { Module.sokol_paste = function(event) { var pasted_str = event.clipboardData.getData('text'); ccall('_sapp_emsc_onpaste', 'void', ['string'], [pasted_str]); @@ -3604,7 +3616,7 @@ EM_JS(void, sapp_js_add_hook_clipboard, (void), { window.addEventListener('paste', Module.sokol_paste); }); -EM_JS(void, sapp_js_remove_hook_clipboard, (void), { +EM_JS(void, sapp_js_remove_clipboard_listener, (void), { window.removeEventListener('paste', Module.sokol_paste); }); @@ -3630,6 +3642,79 @@ _SOKOL_PRIVATE void _sapp_emsc_set_clipboard_string(const char* str) { sapp_js_write_clipboard(str); } +EM_JS(void, sapp_js_add_dragndrop_listeners, (const char* canvas_name_cstr), { + Module.sokol_drop_files = []; + var canvas_name = UTF8ToString(canvas_name_cstr); + var canvas = document.getElementById(canvas_name); + Module.sokol_dragenter = function(event) { + event.stopPropagation(); + event.preventDefault(); + }; + Module.sokol_dragleave = function(event) { + event.stopPropagation(); + event.preventDefault(); + }; + Module.sokol_dragover = function(event) { + event.stopPropagation(); + event.preventDefault(); + }; + Module.sokol_drop = function(event) { + event.stopPropagation(); + event.preventDefault(); + var files = event.dataTransfer.files; + Module.sokol_dropped_files = files; + __sapp_emsc_begin_drop(files.length); + var i; + for (i = 0; i < files.length; i++) { + ccall('_sapp_emsc_drop', 'void', ['number', 'string'], [i, files[i].name]); + } + // FIXME? see computation of targetX/targetY in emscripten via getClientBoundingRect + __sapp_emsc_end_drop(event.clientX, event.clientY); + }; + canvas.addEventListener('dragenter', Module.sokol_dragenter, false); + canvas.addEventListener('dragleave', Module.sokol_dragleave, false); + canvas.addEventListener('dragover', Module.sokol_dragover, false); + canvas.addEventListener('drop', Module.sokol_drop, false); +}); + +EM_JS(uint32_t, sapp_js_dropped_file_size, (int index), { + if ((index < 0) || (index >= Module.sokol_dropped_files.length)) { + return 0; + } + else { + return Module.sokol_dropped_files[index].size; + } +}); + +EM_JS(void, sapp_js_fetch_dropped_file, (int index, _sapp_html5_fetch_callback callback, void* buf_ptr, uint32_t buf_size, void* user_data), { + var reader = new FileReader(); + reader.onload = function(loadEvent) { + var content = loadEvent.target.result; + if (content.byteLength > buf_size) { + // SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL + __sapp_emsc_invoke_fetch_cb(index, 0, 1, callback, 0, buf_ptr, buf_size, user_data); + } + else { + HEAPU8.set(new Uint8Array(content), buf_ptr); + __sapp_emsc_invoke_fetch_cb(index, 1, 0, callback, content.byteLength, buf_ptr, buf_size, user_data); + } + }; + reader.onerror = function() { + // SAPP_HTML5_FETCH_ERROR_OTHER + __sapp_emsc_invoke_fetch_cb(index, 0, 2, callback, 0, buf_ptr, buf_size, user_data); + }; + reader.readAsArrayBuffer(Module.sokol_dropped_files[index]); +}); + +EM_JS(void, sapp_js_remove_dragndrop_listeners, (const char* canvas_name_cstr), { + var canvas_name = UTF8ToString(canvas_name_cstr); + var canvas = document.getElementById(canvas_name); + canvas.removeEventListener('dragenter', Module.sokol_dragenter); + canvas.removeEventListener('dragleave', Module.sokol_dragleave); + canvas.removeEventListener('dragover', Module.sokol_dragover); + canvas.removeEventListener('drop', Module.sokol_drop); +}); + /* called from the emscripten event handler to update the keyboard visibility state, this must happen from an JS input event handler, otherwise the request will be ignored by the browser @@ -3742,7 +3827,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU _SOKOL_UNUSED(event_type); _SOKOL_UNUSED(user_data); double w, h; - emscripten_get_element_css_size(_sapp.html5_canvas_name, &w, &h); + emscripten_get_element_css_size(_sapp.html5_canvas_selector, &w, &h); /* The above method might report zero when toggling HTML5 fullscreen, in that case use the window's inner width reported by the emscripten event. This works ok when toggling *into* fullscreen @@ -3781,7 +3866,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU _sapp.framebuffer_width = (int) (w * _sapp.dpi_scale); _sapp.framebuffer_height = (int) (h * _sapp.dpi_scale); SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0)); - emscripten_set_canvas_element_size(_sapp.html5_canvas_name, _sapp.framebuffer_width, _sapp.framebuffer_height); + emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height); #if defined(SOKOL_WGPU) /* on WebGPU: recreate size-dependent rendering surfaces */ _sapp_emsc_wgpu_surfaces_discard(); @@ -3949,7 +4034,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard } } else { - _sapp.event.key_code = _sapp_translate_key(emsc_event->keyCode); + _sapp.event.key_code = _sapp_translate_key((int)emsc_event->keyCode); /* Special hack for macOS: if the Super key is pressed, macOS doesn't send keyUp events. As a workaround, to prevent keys from "sticking", we'll send a keyup event following a keydown @@ -4088,7 +4173,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchE for (int i = 0; i < _sapp.event.num_touches; i++) { const EmscriptenTouchPoint* src = &emsc_event->touches[i]; sapp_touchpoint* dst = &_sapp.event.touches[i]; - dst->identifier = src->identifier; + dst->identifier = (uintptr_t)src->identifier; dst->pos_x = src->targetX * _sapp.dpi_scale; dst->pos_y = src->targetY * _sapp.dpi_scale; dst->changed = src->isChanged; @@ -4240,10 +4325,10 @@ _SOKOL_PRIVATE void _sapp_emsc_webgl_init(void) { attrs.majorVersion = 2; } #endif - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(_sapp.html5_canvas_name, &attrs); + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(_sapp.html5_canvas_selector, &attrs); if (!ctx) { attrs.majorVersion = 1; - ctx = emscripten_webgl_create_context(_sapp.html5_canvas_name, &attrs); + ctx = emscripten_webgl_create_context(_sapp.html5_canvas_selector, &attrs); _sapp.gles2_fallback = true; } emscripten_webgl_make_context_current(ctx); @@ -4364,54 +4449,60 @@ _SOKOL_PRIVATE void _sapp_emsc_wgpu_next_frame(void) { #endif _SOKOL_PRIVATE void _sapp_emsc_register_eventhandlers(void) { - emscripten_set_mousedown_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mouseup_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mousemove_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mouseenter_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_mouseleave_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb); - emscripten_set_wheel_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_wheel_cb); + emscripten_set_mousedown_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); + emscripten_set_mouseup_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); + emscripten_set_mousemove_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); + emscripten_set_mouseenter_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); + emscripten_set_mouseleave_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb); + emscripten_set_wheel_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_wheel_cb); emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb); emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb); emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb); - emscripten_set_touchstart_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb); - emscripten_set_touchmove_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb); - emscripten_set_touchend_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb); - emscripten_set_touchcancel_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb); + emscripten_set_touchstart_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); + emscripten_set_touchmove_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); + emscripten_set_touchend_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); + emscripten_set_touchcancel_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_touch_cb); emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, _sapp_emsc_pointerlockchange_cb); emscripten_set_pointerlockerror_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, _sapp_emsc_pointerlockerror_cb); - sapp_js_add_hook_beforeunload(); + sapp_js_add_beforeunload_listener(); if (_sapp.clipboard.enabled) { - sapp_js_add_hook_clipboard(); + sapp_js_add_clipboard_listener(); + } + if (_sapp.drop.enabled) { + sapp_js_add_dragndrop_listeners(&_sapp.html5_canvas_selector[1]); } #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) - emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_webgl_context_cb); - emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_webgl_context_cb); + emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_webgl_context_cb); + emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_webgl_context_cb); #endif } _SOKOL_PRIVATE void _sapp_emsc_unregister_eventhandlers() { - emscripten_set_mousedown_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_mouseup_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_mousemove_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_mouseenter_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_mouseleave_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_wheel_callback(_sapp.html5_canvas_name, 0, true, 0); + emscripten_set_mousedown_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_mouseup_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_mousemove_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_mouseenter_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_mouseleave_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_wheel_callback(_sapp.html5_canvas_selector, 0, true, 0); emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, 0); - emscripten_set_touchstart_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_touchmove_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_touchend_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_touchcancel_callback(_sapp.html5_canvas_name, 0, true, 0); + emscripten_set_touchstart_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_touchmove_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_touchend_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_touchcancel_callback(_sapp.html5_canvas_selector, 0, true, 0); emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, 0); emscripten_set_pointerlockerror_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, 0); - sapp_js_remove_hook_beforeunload(); + sapp_js_remove_beforeunload_listener(); if (_sapp.clipboard.enabled) { - sapp_js_remove_hook_clipboard(); + sapp_js_remove_clipboard_listener(); + } + if (_sapp.drop.enabled) { + sapp_js_remove_dragndrop_listeners(&_sapp.html5_canvas_selector[1]); } #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) - emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_name, 0, true, 0); - emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_name, 0, true, 0); + emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_selector, 0, true, 0); + emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_selector, 0, true, 0); #endif } @@ -4464,7 +4555,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) { _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { _sapp_init_state(desc); - sapp_js_pointer_init(_sapp.html5_canvas_name); + sapp_js_pointer_init(&_sapp.html5_canvas_selector[1]); _sapp_emsc_keytable_init(); double w, h; if (_sapp.desc.html5_canvas_resize) { @@ -4472,7 +4563,7 @@ _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { h = (double) _sapp.desc.height; } else { - emscripten_get_element_css_size(_sapp.html5_canvas_name, &w, &h); + emscripten_get_element_css_size(_sapp.html5_canvas_selector, &w, &h); emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, false, _sapp_emsc_size_changed); } if (_sapp.desc.high_dpi) { @@ -4482,7 +4573,7 @@ _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { _sapp.window_height = (int) h; _sapp.framebuffer_width = (int) (w * _sapp.dpi_scale); _sapp.framebuffer_height = (int) (h * _sapp.dpi_scale); - emscripten_set_canvas_element_size(_sapp.html5_canvas_name, _sapp.framebuffer_width, _sapp.framebuffer_height); + emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height); #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) _sapp_emsc_webgl_init(); #elif defined(SOKOL_WGPU) @@ -4534,14 +4625,13 @@ _SOKOL_PRIVATE void _sapp_gl_init_fbconfig(_sapp_gl_fbconfig* fbconfig) { fbconfig->samples = -1; } -_SOKOL_PRIVATE const _sapp_gl_fbconfig* _sapp_gl_choose_fbconfig(const _sapp_gl_fbconfig* desired, const _sapp_gl_fbconfig* alternatives, unsigned int count) { - unsigned int i; - unsigned int missing, least_missing = 1000000; - unsigned int color_diff, least_color_diff = 10000000; - unsigned int extra_diff, least_extra_diff = 10000000; +_SOKOL_PRIVATE const _sapp_gl_fbconfig* _sapp_gl_choose_fbconfig(const _sapp_gl_fbconfig* desired, const _sapp_gl_fbconfig* alternatives, int count) { + int missing, least_missing = 1000000; + int color_diff, least_color_diff = 10000000; + int extra_diff, least_extra_diff = 10000000; const _sapp_gl_fbconfig* current; - const _sapp_gl_fbconfig* closest = NULL; - for (i = 0; i < count; i++) { + const _sapp_gl_fbconfig* closest = 0; + for (int i = 0; i < count; i++) { current = alternatives + i; if (desired->doublebuffer != current->doublebuffer) { continue; @@ -4622,8 +4712,8 @@ _SOKOL_PRIVATE const _sapp_gl_fbconfig* _sapp_gl_choose_fbconfig(const _sapp_gl_ #if defined(_SAPP_WIN32) || defined(_SAPP_UWP) _SOKOL_PRIVATE bool _sapp_win32_uwp_utf8_to_wide(const char* src, wchar_t* dst, int dst_num_bytes) { SOKOL_ASSERT(src && dst && (dst_num_bytes > 1)); - memset(dst, 0, dst_num_bytes); - const int dst_chars = dst_num_bytes / sizeof(wchar_t); + memset(dst, 0, (size_t)dst_num_bytes); + const int dst_chars = dst_num_bytes / (int)sizeof(wchar_t); const int dst_needed = MultiByteToWideChar(CP_UTF8, 0, src, -1, 0, 0); if ((dst_needed > 0) && (dst_needed < dst_chars)) { MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars); @@ -4776,7 +4866,7 @@ _SOKOL_PRIVATE void _sapp_win32_uwp_init_keytable(void) { #define _sapp_d3d11_Release(self) (self)->lpVtbl->Release(self) #endif -#define _SAPP_SAFE_RELEASE(class, obj) if (obj) { _sapp_d3d11_Release(obj); obj=0; } +#define _SAPP_SAFE_RELEASE(obj) if (obj) { _sapp_d3d11_Release(obj); obj=0; } static inline HRESULT _sapp_dxgi_GetBuffer(IDXGISwapChain* self, UINT Buffer, REFIID riid, void** ppSurface) { #if defined(__cplusplus) @@ -4810,6 +4900,14 @@ static inline HRESULT _sapp_d3d11_CreateDepthStencilView(ID3D11Device* self, ID3 #endif } +static inline void _sapp_d3d11_ResolveSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, ID3D11Resource* pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) { + #if defined(__cplusplus) + self->ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); + #else + self->lpVtbl->ResolveSubresource(self, pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); + #endif +} + static inline HRESULT _sapp_dxgi_ResizeBuffers(IDXGISwapChain* self, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) { #if defined(__cplusplus) return self->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); @@ -4828,19 +4926,25 @@ static inline HRESULT _sapp_dxgi_Present(IDXGISwapChain* self, UINT SyncInterval _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 = _sapp.framebuffer_width; - sc_desc->BufferDesc.Height = _sapp.framebuffer_height; + sc_desc->BufferDesc.Width = (UINT)_sapp.framebuffer_width; + sc_desc->BufferDesc.Height = (UINT)_sapp.framebuffer_height; sc_desc->BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; sc_desc->BufferDesc.RefreshRate.Numerator = 60; sc_desc->BufferDesc.RefreshRate.Denominator = 1; sc_desc->OutputWindow = _sapp.win32.hwnd; sc_desc->Windowed = true; - sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - sc_desc->BufferCount = 1; - sc_desc->SampleDesc.Count = _sapp.sample_count; - sc_desc->SampleDesc.Quality = _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0; + if (_sapp.win32.is_win10_or_greater) { + sc_desc->BufferCount = 2; + sc_desc->SwapEffect = (DXGI_SWAP_EFFECT) _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD; + } + else { + sc_desc->BufferCount = 1; + sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + } + sc_desc->SampleDesc.Count = 1; + sc_desc->SampleDesc.Quality = 0; sc_desc->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - int create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT; + UINT create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT; #if defined(SOKOL_DEBUG) create_flags |= D3D11_CREATE_DEVICE_DEBUG; #endif @@ -4863,13 +4967,22 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) { } _SOKOL_PRIVATE void _sapp_d3d11_destroy_device_and_swapchain(void) { - _SAPP_SAFE_RELEASE(IDXGISwapChain, _sapp.d3d11.swap_chain); - _SAPP_SAFE_RELEASE(ID3D11DeviceContext, _sapp.d3d11.device_context); - _SAPP_SAFE_RELEASE(ID3D11Device, _sapp.d3d11.device); + _SAPP_SAFE_RELEASE(_sapp.d3d11.swap_chain); + _SAPP_SAFE_RELEASE(_sapp.d3d11.device_context); + _SAPP_SAFE_RELEASE(_sapp.d3d11.device); } _SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(void) { + SOKOL_ASSERT(0 == _sapp.d3d11.rt); + SOKOL_ASSERT(0 == _sapp.d3d11.rtv); + SOKOL_ASSERT(0 == _sapp.d3d11.msaa_rt); + SOKOL_ASSERT(0 == _sapp.d3d11.msaa_rtv); + SOKOL_ASSERT(0 == _sapp.d3d11.ds); + SOKOL_ASSERT(0 == _sapp.d3d11.dsv); + HRESULT hr; + + /* view for the swapchain-created framebuffer */ #ifdef __cplusplus hr = _sapp_dxgi_GetBuffer(_sapp.d3d11.swap_chain, 0, IID_ID3D11Texture2D, (void**)&_sapp.d3d11.rt); #else @@ -4878,40 +4991,64 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(void) { SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.rt); hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.rt, NULL, &_sapp.d3d11.rtv); SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.rtv); - D3D11_TEXTURE2D_DESC ds_desc; - memset(&ds_desc, 0, sizeof(ds_desc)); - ds_desc.Width = _sapp.framebuffer_width; - ds_desc.Height = _sapp.framebuffer_height; - ds_desc.MipLevels = 1; - ds_desc.ArraySize = 1; - ds_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - ds_desc.SampleDesc = _sapp.d3d11.swap_chain_desc.SampleDesc; - ds_desc.Usage = D3D11_USAGE_DEFAULT; - ds_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &ds_desc, NULL, &_sapp.d3d11.ds); + + /* common desc for MSAA and depth-stencil texture */ + D3D11_TEXTURE2D_DESC tex_desc; + memset(&tex_desc, 0, sizeof(tex_desc)); + tex_desc.Width = (UINT)_sapp.framebuffer_width; + tex_desc.Height = (UINT)_sapp.framebuffer_height; + tex_desc.MipLevels = 1; + tex_desc.ArraySize = 1; + tex_desc.Usage = D3D11_USAGE_DEFAULT; + tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; + tex_desc.SampleDesc.Count = (UINT) _sapp.sample_count; + tex_desc.SampleDesc.Quality = (UINT) (_sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0); + + /* create MSAA texture and view if antialiasing requested */ + if (_sapp.sample_count > 1) { + tex_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &_sapp.d3d11.msaa_rt); + SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.msaa_rt); + hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.msaa_rt, NULL, &_sapp.d3d11.msaa_rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.msaa_rtv); + } + + /* texture and view for the depth-stencil-surface */ + tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &_sapp.d3d11.ds); SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.ds); - D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc; - memset(&dsv_desc, 0, sizeof(dsv_desc)); - dsv_desc.Format = ds_desc.Format; - dsv_desc.ViewDimension = _sapp.sample_count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; - hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.ds, &dsv_desc, &_sapp.d3d11.dsv); + hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.ds, NULL, &_sapp.d3d11.dsv); SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.dsv); } _SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(void) { - _SAPP_SAFE_RELEASE(ID3D11Texture2D, _sapp.d3d11.rt); - _SAPP_SAFE_RELEASE(ID3D11RenderTargetView, _sapp.d3d11.rtv); - _SAPP_SAFE_RELEASE(ID3D11Texture2D, _sapp.d3d11.ds); - _SAPP_SAFE_RELEASE(ID3D11DepthStencilView, _sapp.d3d11.dsv); + _SAPP_SAFE_RELEASE(_sapp.d3d11.rt); + _SAPP_SAFE_RELEASE(_sapp.d3d11.rtv); + _SAPP_SAFE_RELEASE(_sapp.d3d11.msaa_rt); + _SAPP_SAFE_RELEASE(_sapp.d3d11.msaa_rtv); + _SAPP_SAFE_RELEASE(_sapp.d3d11.ds); + _SAPP_SAFE_RELEASE(_sapp.d3d11.dsv); } _SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(void) { if (_sapp.d3d11.swap_chain) { _sapp_d3d11_destroy_default_render_target(); - _sapp_dxgi_ResizeBuffers(_sapp.d3d11.swap_chain, 1, _sapp.framebuffer_width, _sapp.framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); + _sapp_dxgi_ResizeBuffers(_sapp.d3d11.swap_chain, _sapp.d3d11.swap_chain_desc.BufferCount, (UINT)_sapp.framebuffer_width, (UINT)_sapp.framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); _sapp_d3d11_create_default_render_target(); } } + +_SOKOL_PRIVATE void _sapp_d3d11_present(void) { + /* do MSAA resolve if needed */ + if (_sapp.sample_count > 1) { + SOKOL_ASSERT(_sapp.d3d11.rt); + SOKOL_ASSERT(_sapp.d3d11.msaa_rt); + _sapp_d3d11_ResolveSubresource(_sapp.d3d11.device_context, (ID3D11Resource*)_sapp.d3d11.rt, 0, (ID3D11Resource*)_sapp.d3d11.msaa_rt, 0, DXGI_FORMAT_B8G8R8A8_UNORM); + } + _sapp_dxgi_Present(_sapp.d3d11.swap_chain, (UINT)_sapp.swap_interval, 0); +} + #endif /* SOKOL_D3D11 */ #if defined(SOKOL_GLCORE33) @@ -4921,15 +5058,15 @@ _SOKOL_PRIVATE void _sapp_wgl_init(void) { _sapp_fail("Failed to load opengl32.dll\n"); } SOKOL_ASSERT(_sapp.wgl.opengl32); - _sapp.wgl.CreateContext = (PFN_wglCreateContext) GetProcAddress(_sapp.wgl.opengl32, "wglCreateContext"); + _sapp.wgl.CreateContext = (PFN_wglCreateContext)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglCreateContext"); SOKOL_ASSERT(_sapp.wgl.CreateContext); - _sapp.wgl.DeleteContext = (PFN_wglDeleteContext) GetProcAddress(_sapp.wgl.opengl32, "wglDeleteContext"); + _sapp.wgl.DeleteContext = (PFN_wglDeleteContext)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglDeleteContext"); SOKOL_ASSERT(_sapp.wgl.DeleteContext); - _sapp.wgl.GetProcAddress = (PFN_wglGetProcAddress) GetProcAddress(_sapp.wgl.opengl32, "wglGetProcAddress"); + _sapp.wgl.GetProcAddress = (PFN_wglGetProcAddress)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglGetProcAddress"); SOKOL_ASSERT(_sapp.wgl.GetProcAddress); - _sapp.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) GetProcAddress(_sapp.wgl.opengl32, "wglGetCurrentDC"); + _sapp.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglGetCurrentDC"); SOKOL_ASSERT(_sapp.wgl.GetCurrentDC); - _sapp.wgl.MakeCurrent = (PFN_wglMakeCurrent) GetProcAddress(_sapp.wgl.opengl32, "wglMakeCurrent"); + _sapp.wgl.MakeCurrent = (PFN_wglMakeCurrent)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglMakeCurrent"); SOKOL_ASSERT(_sapp.wgl.MakeCurrent); _sapp.wgl.msg_hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, @@ -4943,6 +5080,7 @@ _SOKOL_PRIVATE void _sapp_wgl_init(void) { if (!_sapp.wgl.msg_hwnd) { _sapp_fail("Win32: failed to create helper window!\n"); } + SOKOL_ASSERT(_sapp.wgl.msg_hwnd); ShowWindow(_sapp.wgl.msg_hwnd, SW_HIDE); MSG msg; while (PeekMessageW(&msg, _sapp.wgl.msg_hwnd, 0, 0, PM_REMOVE)) { @@ -5020,11 +5158,11 @@ _SOKOL_PRIVATE void _sapp_wgl_load_extensions(void) { if (!_sapp.wgl.MakeCurrent(_sapp.wgl.msg_dc, rc)) { _sapp_fail("WGL: Failed to make context current\n"); } - _sapp.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) _sapp.wgl.GetProcAddress("wglGetExtensionsStringEXT"); - _sapp.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) _sapp.wgl.GetProcAddress("wglGetExtensionsStringARB"); - _sapp.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) _sapp.wgl.GetProcAddress("wglCreateContextAttribsARB"); - _sapp.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) _sapp.wgl.GetProcAddress("wglSwapIntervalEXT"); - _sapp.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) _sapp.wgl.GetProcAddress("wglGetPixelFormatAttribivARB"); + _sapp.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void*) _sapp.wgl.GetProcAddress("wglGetExtensionsStringEXT"); + _sapp.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)(void*) _sapp.wgl.GetProcAddress("wglGetExtensionsStringARB"); + _sapp.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)(void*) _sapp.wgl.GetProcAddress("wglCreateContextAttribsARB"); + _sapp.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(void*) _sapp.wgl.GetProcAddress("wglSwapIntervalEXT"); + _sapp.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(void*) _sapp.wgl.GetProcAddress("wglGetPixelFormatAttribivARB"); _sapp.wgl.arb_multisample = _sapp_wgl_ext_supported("WGL_ARB_multisample"); _sapp.wgl.arb_create_context = _sapp_wgl_ext_supported("WGL_ARB_create_context"); _sapp.wgl.arb_create_context_profile = _sapp_wgl_ext_supported("WGL_ARB_create_context_profile"); @@ -5049,7 +5187,8 @@ _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { const _sapp_gl_fbconfig* closest; int native_count = _sapp_wgl_attrib(1, WGL_NUMBER_PIXEL_FORMATS_ARB); - _sapp_gl_fbconfig* usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig)); + _sapp_gl_fbconfig* usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC((size_t)native_count, sizeof(_sapp_gl_fbconfig)); + SOKOL_ASSERT(usable_configs); int usable_count = 0; for (int i = 0; i < native_count; i++) { const int n = i + 1; @@ -5076,7 +5215,7 @@ _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { if (_sapp.wgl.arb_multisample) { u->samples = _sapp_wgl_attrib(n, WGL_SAMPLES_ARB); } - u->handle = n; + u->handle = (uintptr_t)n; usable_count++; } SOKOL_ASSERT(usable_count > 0); @@ -5162,8 +5301,15 @@ _SOKOL_PRIVATE void _sapp_wgl_swap_buffers(void) { _SOKOL_PRIVATE bool _sapp_win32_wide_to_utf8(const wchar_t* src, char* dst, int dst_num_bytes) { SOKOL_ASSERT(src && dst && (dst_num_bytes > 1)); - memset(dst, 0, dst_num_bytes); - return 0 != WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_num_bytes, NULL, NULL); + memset(dst, 0, (size_t)dst_num_bytes); + const int bytes_needed = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL); + if (bytes_needed <= dst_num_bytes) { + WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_num_bytes, NULL, NULL); + return true; + } + else { + return false; + } } _SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(void) { @@ -5380,6 +5526,37 @@ _SOKOL_PRIVATE void _sapp_win32_char_event(uint32_t c, bool repeat) { } } +_SOKOL_PRIVATE void _sapp_win32_files_dropped(HDROP hdrop) { + if (!_sapp.drop.enabled) { + return; + } + _sapp_clear_drop_buffer(); + bool drop_failed = false; + const int count = (int) DragQueryFileW(hdrop, 0xffffffff, NULL, 0); + _sapp.drop.num_files = (count > _sapp.drop.max_files) ? _sapp.drop.max_files : count; + for (UINT i = 0; i < (UINT)_sapp.drop.num_files; i++) { + const UINT num_chars = DragQueryFileW(hdrop, i, NULL, 0) + 1; + WCHAR* buffer = (WCHAR*) SOKOL_CALLOC(num_chars, sizeof(WCHAR)); + DragQueryFileW(hdrop, i, buffer, num_chars); + if (!_sapp_win32_wide_to_utf8(buffer, _sapp_dropped_file_path_ptr((int)i), _sapp.drop.max_path_length)) { + SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); + drop_failed = true; + } + SOKOL_FREE(buffer); + } + DragFinish(hdrop); + if (!drop_failed) { + if (_sapp_events_enabled()) { + _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_call_event(&_sapp.event); + } + } + else { + _sapp_clear_drop_buffer(); + _sapp.drop.num_files = 0; + } +} + _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (!_sapp.win32.in_create_window) { switch (uMsg) { @@ -5492,7 +5669,8 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM if (_sapp.mouse.locked) { HRAWINPUT ri = (HRAWINPUT) lParam; UINT size = sizeof(_sapp.win32.raw_input_data); - if (-1 == GetRawInputData(ri, RID_INPUT, &_sapp.win32.raw_input_data, &size, sizeof(RAWINPUTHEADER))) { + // see: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdata + if ((UINT)-1 == GetRawInputData(ri, RID_INPUT, &_sapp.win32.raw_input_data, &size, sizeof(RAWINPUTHEADER))) { SOKOL_LOG("GetRawInputData() failed\n"); break; } @@ -5554,7 +5732,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM case WM_TIMER: _sapp_frame(); #if defined(SOKOL_D3D11) - _sapp_dxgi_Present(_sapp.d3d11.swap_chain, _sapp.swap_interval, 0); + _sapp_d3d11_present(); #endif #if defined(SOKOL_GLCORE33) _sapp_wgl_swap_buffers(); @@ -5570,6 +5748,9 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM } */ break; + case WM_DROPFILES: + _sapp_win32_files_dropped((HDROP)wParam); + break; default: break; } @@ -5623,6 +5804,8 @@ _SOKOL_PRIVATE void _sapp_win32_create_window(void) { _sapp.win32.dc = GetDC(_sapp.win32.hwnd); SOKOL_ASSERT(_sapp.win32.dc); _sapp_win32_update_dimensions(); + + DragAcceptFiles(_sapp.win32.hwnd, 1); } _SOKOL_PRIVATE void _sapp_win32_destroy_window(void) { @@ -5630,6 +5813,35 @@ _SOKOL_PRIVATE void _sapp_win32_destroy_window(void) { UnregisterClassW(L"SOKOLAPP", GetModuleHandleW(NULL)); } +_SOKOL_PRIVATE void _sapp_win32_init_console(void) { + if (_sapp.desc.win32_console_create || _sapp.desc.win32_console_attach) { + BOOL con_valid = FALSE; + if (_sapp.desc.win32_console_create) { + con_valid = AllocConsole(); + } + else if (_sapp.desc.win32_console_attach) { + con_valid = AttachConsole(ATTACH_PARENT_PROCESS); + } + if (con_valid) { + FILE* res_fp = 0; + errno_t err; + err = freopen_s(&res_fp, "CON", "w", stdout); + err = freopen_s(&res_fp, "CON", "w", stderr); + (void)err; + } + } + if (_sapp.desc.win32_console_utf8) { + _sapp.win32.orig_codepage = GetConsoleOutputCP(); + SetConsoleOutputCP(CP_UTF8); + } +} + +_SOKOL_PRIVATE void _sapp_win32_restore_console(void) { + if (_sapp.desc.win32_console_utf8) { + SetConsoleOutputCP(_sapp.win32.orig_codepage); + } +} + _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { typedef BOOL(WINAPI * SETPROCESSDPIAWARE_T)(void); @@ -5641,12 +5853,12 @@ _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { GETDPIFORMONITOR_T fn_getdpiformonitor = 0; HINSTANCE user32 = LoadLibraryA("user32.dll"); if (user32) { - fn_setprocessdpiaware = (SETPROCESSDPIAWARE_T) GetProcAddress(user32, "SetProcessDPIAware"); + fn_setprocessdpiaware = (SETPROCESSDPIAWARE_T)(void*) GetProcAddress(user32, "SetProcessDPIAware"); } HINSTANCE shcore = LoadLibraryA("shcore.dll"); if (shcore) { - fn_setprocessdpiawareness = (SETPROCESSDPIAWARENESS_T) GetProcAddress(shcore, "SetProcessDpiAwareness"); - fn_getdpiformonitor = (GETDPIFORMONITOR_T) GetProcAddress(shcore, "GetDpiForMonitor"); + fn_setprocessdpiawareness = (SETPROCESSDPIAWARENESS_T)(void*) GetProcAddress(shcore, "SetProcessDpiAwareness"); + fn_getdpiformonitor = (GETDPIFORMONITOR_T)(void*) GetProcAddress(shcore, "GetDpiForMonitor"); } if (fn_setprocessdpiawareness) { /* if the app didn't request HighDPI rendering, let Windows do the upscaling */ @@ -5699,7 +5911,7 @@ _SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) { SOKOL_ASSERT(_sapp.clipboard.enabled && (_sapp.clipboard.buf_size > 0)); wchar_t* wchar_buf = 0; - const int wchar_buf_size = _sapp.clipboard.buf_size * sizeof(wchar_t); + const SIZE_T wchar_buf_size = (SIZE_T)_sapp.clipboard.buf_size * sizeof(wchar_t); HANDLE object = GlobalAlloc(GMEM_MOVEABLE, wchar_buf_size); if (!object) { goto error; @@ -5708,7 +5920,7 @@ _SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) { if (!wchar_buf) { goto error; } - if (!_sapp_win32_uwp_utf8_to_wide(str, wchar_buf, wchar_buf_size)) { + if (!_sapp_win32_uwp_utf8_to_wide(str, wchar_buf, (int)wchar_buf_size)) { goto error; } GlobalUnlock(wchar_buf); @@ -5750,7 +5962,9 @@ _SOKOL_PRIVATE const char* _sapp_win32_get_clipboard_string(void) { CloseClipboard(); return _sapp.clipboard.buffer; } - _sapp_win32_wide_to_utf8(wchar_buf, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + if (!_sapp_win32_wide_to_utf8(wchar_buf, _sapp.clipboard.buffer, _sapp.clipboard.buf_size)) { + SOKOL_LOG("sokol_app.h: clipboard string didn't fit into clipboard buffer\n"); + } GlobalUnlock(object); CloseClipboard(); return _sapp.clipboard.buffer; @@ -5761,8 +5975,25 @@ _SOKOL_PRIVATE void _sapp_win32_update_window_title(void) { SetWindowTextW(_sapp.win32.hwnd, _sapp.window_title_wide); } +/* don't laugh, but this seems to be the easiest and most robust + way to check if we're running on Win10 + + From: https://github.com/videolan/vlc/blob/232fb13b0d6110c4d1b683cde24cf9a7f2c5c2ea/modules/video_output/win32/d3d11_swapchain.c#L263 +*/ +_SOKOL_PRIVATE bool _sapp_win32_is_win10_or_greater(void) { + HMODULE h = GetModuleHandleW(L"kernel32.dll"); + if (NULL != h) { + return (NULL != GetProcAddress(h, "GetSystemCpuSetInformation")); + } + else { + return false; + } +} + _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_init_state(desc); + _sapp_win32_init_console(); + _sapp.win32.is_win10_or_greater = _sapp_win32_is_win10_or_greater(); _sapp_win32_uwp_init_keytable(); _sapp_win32_uwp_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide)); _sapp_win32_init_dpi(); @@ -5775,9 +6006,6 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_wgl_init(); _sapp_wgl_load_extensions(); _sapp_wgl_create_context(); - #if !defined(SOKOL_WIN32_NO_GL_LOADER) - _sapp_win32_gl_loadfuncs(); - #endif #endif _sapp.valid = true; @@ -5796,9 +6024,9 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { } _sapp_frame(); #if defined(SOKOL_D3D11) - _sapp_dxgi_Present(_sapp.d3d11.swap_chain, _sapp.swap_interval, 0); + _sapp_d3d11_present(); if (IsIconic(_sapp.win32.hwnd)) { - Sleep(16 * _sapp.swap_interval); + Sleep((DWORD)(16 * _sapp.swap_interval)); } #endif #if defined(SOKOL_GLCORE33) @@ -5825,6 +6053,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_wgl_shutdown(); #endif _sapp_win32_destroy_window(); + _sapp_win32_restore_console(); _sapp_discard_state(); } @@ -5838,8 +6067,9 @@ _SOKOL_PRIVATE char** _sapp_win32_command_line_to_utf8_argv(LPWSTR w_command_lin _sapp_fail("Win32: failed to parse command line"); } else { size_t size = wcslen(w_command_line) * 4; - argv = (char**) SOKOL_CALLOC(1, (argc + 1) * sizeof(char*) + size); - args = (char*)&argv[argc + 1]; + argv = (char**) SOKOL_CALLOC(1, ((size_t)argc + 1) * sizeof(char*) + size); + SOKOL_ASSERT(argv); + args = (char*) &argv[argc + 1]; int n; for (int i = 0; i < argc; ++i) { n = WideCharToMultiByte(CP_UTF8, 0, w_argv[i], -1, args, (int)size, NULL, NULL); @@ -5848,7 +6078,7 @@ _SOKOL_PRIVATE char** _sapp_win32_command_line_to_utf8_argv(LPWSTR w_command_lin break; } argv[i] = args; - size -= n; + size -= (size_t)n; args += n; } LocalFree(w_argv); @@ -6063,16 +6293,6 @@ public: void RegisterDeviceNotify(IDeviceNotify* deviceNotify); void Trim(); void Present(); - winrt::Windows::Foundation::Size GetOutputSize() const { return m_outputSize; } - winrt::Windows::Foundation::Size GetLogicalSize() const { return m_logicalSize; } - ID3D11Device3* GetD3DDevice() const { return m_d3dDevice.get(); } - ID3D11DeviceContext3* GetD3DDeviceContext() const { return m_d3dContext.get(); } - IDXGISwapChain3* GetSwapChain() const { return m_swapChain.get(); } - D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; } - ID3D11RenderTargetView1* GetBackBufferRenderTargetView() const { return m_d3dRenderTargetView.get(); } - ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.get(); } - D3D11_VIEWPORT GetScreenViewport() const { return m_screenViewport; } - DirectX::XMFLOAT4X4 GetOrientationTransform3D() const { return m_orientationTransform3D; } private: @@ -6116,6 +6336,8 @@ private: // Direct3D rendering objects. Required for 3D. winrt::com_ptr m_d3dRenderTarget; winrt::com_ptr m_d3dRenderTargetView; + winrt::com_ptr m_d3dMSAARenderTarget; + winrt::com_ptr m_d3dMSAARenderTargetView; winrt::com_ptr m_d3dDepthStencil; winrt::com_ptr m_d3dDepthStencilView; D3D11_VIEWPORT m_screenViewport = { }; @@ -6273,17 +6495,22 @@ void DeviceResources::CreateDeviceResources() { } void DeviceResources::CreateWindowSizeDependentResources() { - // Cleanup Sokol Context + // Cleanup Sokol Context (these are non-owning raw pointers) _sapp.d3d11.rt = nullptr; _sapp.d3d11.rtv = nullptr; + _sapp.d3d11.msaa_rt = nullptr; + _sapp.d3d11.msaa_rtv = nullptr; _sapp.d3d11.ds = nullptr; _sapp.d3d11.dsv = nullptr; // Clear the previous window size specific context. ID3D11RenderTargetView* nullViews[] = { nullptr }; m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); + // these are smart pointers, setting to nullptr will delete the objects m_d3dRenderTarget = nullptr; m_d3dRenderTargetView = nullptr; + m_d3dMSAARenderTarget = nullptr; + m_d3dMSAARenderTargetView = nullptr; m_d3dDepthStencilView = nullptr; m_d3dDepthStencil = nullptr; m_d3dContext->Flush1(D3D11_CONTEXT_TYPE_ALL, nullptr); @@ -6386,6 +6613,24 @@ void DeviceResources::CreateWindowSizeDependentResources() { winrt::check_hresult(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&m_d3dRenderTarget))); winrt::check_hresult(m_d3dDevice->CreateRenderTargetView1(m_d3dRenderTarget.get(), nullptr, m_d3dRenderTargetView.put())); + // Create MSAA texture and view if needed + if (_sapp.sample_count > 1) { + CD3D11_TEXTURE2D_DESC1 msaaTexDesc( + DXGI_FORMAT_B8G8R8A8_UNORM, + lround(m_d3dRenderTargetSize.Width), + lround(m_d3dRenderTargetSize.Height), + 1, // arraySize + 1, // mipLevels + D3D11_BIND_RENDER_TARGET, + D3D11_USAGE_DEFAULT, + 0, // cpuAccessFlags + _sapp.sample_count, + _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0 + ); + winrt::check_hresult(m_d3dDevice->CreateTexture2D1(&msaaTexDesc, nullptr, m_d3dMSAARenderTarget.put())); + winrt::check_hresult(m_d3dDevice->CreateRenderTargetView1(m_d3dMSAARenderTarget.get(), nullptr, m_d3dMSAARenderTargetView.put())); + } + // Create a depth stencil view for use with 3D rendering if needed. CD3D11_TEXTURE2D_DESC1 depthStencilDesc( DXGI_FORMAT_D24_UNORM_S8_UINT, @@ -6393,18 +6638,16 @@ void DeviceResources::CreateWindowSizeDependentResources() { lround(m_d3dRenderTargetSize.Height), 1, // This depth stencil view has only one texture. 1, // Use a single mipmap level. - D3D11_BIND_DEPTH_STENCIL + D3D11_BIND_DEPTH_STENCIL, + D3D11_USAGE_DEFAULT, + 0, // cpuAccessFlag + _sapp.sample_count, + _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0 ); winrt::check_hresult(m_d3dDevice->CreateTexture2D1(&depthStencilDesc, nullptr, m_d3dDepthStencil.put())); CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D); - winrt::check_hresult( - m_d3dDevice->CreateDepthStencilView( - m_d3dDepthStencil.get(), - &depthStencilViewDesc, - m_d3dDepthStencilView.put() - ) - ); + winrt::check_hresult(m_d3dDevice->CreateDepthStencilView(m_d3dDepthStencil.get(), nullptr, m_d3dDepthStencilView.put())); // Set sokol window and framebuffer sizes _sapp.window_width = (int) m_logicalSize.Width; @@ -6417,6 +6660,10 @@ void DeviceResources::CreateWindowSizeDependentResources() { _sapp.d3d11.rtv = m_d3dRenderTargetView.as().get(); _sapp.d3d11.ds = m_d3dDepthStencil.as().get(); _sapp.d3d11.dsv = m_d3dDepthStencilView.get(); + if (_sapp.sample_count > 1) { + _sapp.d3d11.msaa_rt = m_d3dMSAARenderTarget.as().get(); + _sapp.d3d11.msaa_rtv = m_d3dMSAARenderTargetView.as().get(); + } // Sokol app is now valid _sapp.valid = true; @@ -6540,6 +6787,13 @@ void DeviceResources::Trim() { // Present the contents of the swap chain to the screen. void DeviceResources::Present() { + + // MSAA resolve if needed + if (_sapp.sample_count > 1) { + m_d3dContext->ResolveSubresource(m_d3dRenderTarget.get(), 0, m_d3dMSAARenderTarget.get(), 0, DXGI_FORMAT_B8G8R8A8_UNORM); + m_d3dContext->DiscardView1(m_d3dMSAARenderTargetView.get(), nullptr, 0); + } + // The first argument instructs DXGI to block until VSync, putting the application // to sleep until the next VSync. This ensures we don't waste any cycles rendering // frames that will never be displayed to the screen. @@ -7109,19 +7363,19 @@ _SOKOL_PRIVATE bool _sapp_android_touch_event(const AInputEvent* e) { } int32_t idx = action_idx >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; _sapp_init_event(type); - _sapp.event.num_touches = AMotionEvent_getPointerCount(e); + _sapp.event.num_touches = (int)AMotionEvent_getPointerCount(e); if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) { _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS; } for (int32_t i = 0; i < _sapp.event.num_touches; i++) { sapp_touchpoint* dst = &_sapp.event.touches[i]; - dst->identifier = AMotionEvent_getPointerId(e, i); - dst->pos_x = (AMotionEvent_getRawX(e, i) / _sapp.window_width) * _sapp.framebuffer_width; - dst->pos_y = (AMotionEvent_getRawY(e, i) / _sapp.window_height) * _sapp.framebuffer_height; + dst->identifier = (uintptr_t)AMotionEvent_getPointerId(e, (size_t)i); + dst->pos_x = (AMotionEvent_getRawX(e, (size_t)i) / _sapp.window_width) * _sapp.framebuffer_width; + dst->pos_y = (AMotionEvent_getRawY(e, (size_t)i) / _sapp.window_height) * _sapp.framebuffer_height; if (action == AMOTION_EVENT_ACTION_POINTER_DOWN || action == AMOTION_EVENT_ACTION_POINTER_UP) { - dst->changed = i == idx; + dst->changed = (i == idx); } else { dst->changed = true; } @@ -8378,6 +8632,18 @@ _SOKOL_PRIVATE void _sapp_x11_init_extensions(void) { _sapp.x11.NET_WM_ICON_NAME = XInternAtom(_sapp.x11.display, "_NET_WM_ICON_NAME", False); _sapp.x11.NET_WM_STATE = XInternAtom(_sapp.x11.display, "_NET_WM_STATE", False); _sapp.x11.NET_WM_STATE_FULLSCREEN = XInternAtom(_sapp.x11.display, "_NET_WM_STATE_FULLSCREEN", False); + if (_sapp.drop.enabled) { + _sapp.x11.xdnd.XdndAware = XInternAtom(_sapp.x11.display, "XdndAware", False); + _sapp.x11.xdnd.XdndEnter = XInternAtom(_sapp.x11.display, "XdndEnter", False); + _sapp.x11.xdnd.XdndPosition = XInternAtom(_sapp.x11.display, "XdndPosition", False); + _sapp.x11.xdnd.XdndStatus = XInternAtom(_sapp.x11.display, "XdndStatus", False); + _sapp.x11.xdnd.XdndActionCopy = XInternAtom(_sapp.x11.display, "XdndActionCopy", False); + _sapp.x11.xdnd.XdndDrop = XInternAtom(_sapp.x11.display, "XdndDrop", False); + _sapp.x11.xdnd.XdndFinished = XInternAtom(_sapp.x11.display, "XdndFinished", False); + _sapp.x11.xdnd.XdndSelection = XInternAtom(_sapp.x11.display, "XdndSelection", False); + _sapp.x11.xdnd.XdndTypeList = XInternAtom(_sapp.x11.display, "XdndTypeList", False); + _sapp.x11.xdnd.text_uri_list = XInternAtom(_sapp.x11.display, "text/uri-list", False); + } /* check Xi extension for raw mouse input */ if (XQueryExtension(_sapp.x11.display, "XInputExtension", &_sapp.x11.xi.major_opcode, &_sapp.x11.xi.event_base, &_sapp.x11.xi.error_base)) { @@ -8449,10 +8715,10 @@ _SOKOL_PRIVATE bool _sapp_glx_extsupported(const char* ext, const char* extensio _SOKOL_PRIVATE void* _sapp_glx_getprocaddr(const char* procname) { if (_sapp.glx.GetProcAddress) { - return (void*) _sapp.glx.GetProcAddress((const GLubyte*) procname); + return (void*) _sapp.glx.GetProcAddress(procname); } else if (_sapp.glx.GetProcAddressARB) { - return (void*) _sapp.glx.GetProcAddressARB((const GLubyte*) procname); + return (void*) _sapp.glx.GetProcAddressARB(procname); } else { return dlsym(_sapp.glx.libgl, procname); @@ -8555,7 +8821,7 @@ _SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig() { _sapp_fail("GLX: No GLXFBConfigs returned"); } - usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig)); + usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC((size_t)native_count, sizeof(_sapp_gl_fbconfig)); usable_count = 0; for (i = 0; i < native_count; i++) { const GLXFBConfig n = native_configs[i]; @@ -8735,7 +9001,7 @@ _SOKOL_PRIVATE void _sapp_x11_create_hidden_cursor(void) { SOKOL_ASSERT(img && (img->width == 16) && (img->height == 16) && img->pixels); img->xhot = 0; img->yhot = 0; - const size_t num_bytes = w * h * sizeof(XcursorPixel); + const size_t num_bytes = (size_t)(w * h) * sizeof(XcursorPixel); memset(img->pixels, 0, num_bytes); _sapp.x11.hidden_cursor = XcursorImageLoadCursor(_sapp.x11.display, img); XcursorImageDestroy(img); @@ -8831,8 +9097,8 @@ _SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) { _sapp.x11.window = XCreateWindow(_sapp.x11.display, _sapp.x11.root, 0, 0, - _sapp.window_width, - _sapp.window_height, + (uint32_t)_sapp.window_width, + (uint32_t)_sapp.window_height, 0, /* border width */ depth, /* color depth */ InputOutput, @@ -8854,6 +9120,12 @@ _SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) { XSetWMNormalHints(_sapp.x11.display, _sapp.x11.window, hints); XFree(hints); + /* announce support for drag'n'drop */ + if (_sapp.drop.enabled) { + const Atom version = _SAPP_X11_XDND_VERSION; + XChangeProperty(_sapp.x11.display, _sapp.x11.window, _sapp.x11.xdnd.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1); + } + _sapp_x11_update_window_title(); } @@ -8889,12 +9161,12 @@ _SOKOL_PRIVATE void _sapp_x11_hide_window(void) { XFlush(_sapp.x11.display); } -_SOKOL_PRIVATE unsigned long _sapp_x11_get_window_property(Atom property, Atom type, unsigned char** value) { +_SOKOL_PRIVATE unsigned long _sapp_x11_get_window_property(Window window, Atom property, Atom type, unsigned char** value) { Atom actualType; int actualFormat; unsigned long itemCount, bytesAfter; XGetWindowProperty(_sapp.x11.display, - _sapp.x11.window, + window, property, 0, LONG_MAX, @@ -8915,8 +9187,8 @@ _SOKOL_PRIVATE int _sapp_x11_get_window_state(void) { Window icon; } *state = NULL; - if (_sapp_x11_get_window_property(_sapp.x11.WM_STATE, _sapp.x11.WM_STATE, (unsigned char**)&state) >= 2) { - result = state->state; + if (_sapp_x11_get_window_property(_sapp.x11.window, _sapp.x11.WM_STATE, _sapp.x11.WM_STATE, (unsigned char**)&state) >= 2) { + result = (int)state->state; } if (state) { XFree(state); @@ -8924,7 +9196,7 @@ _SOKOL_PRIVATE int _sapp_x11_get_window_state(void) { return result; } -_SOKOL_PRIVATE uint32_t _sapp_x11_mod(int x11_mods) { +_SOKOL_PRIVATE uint32_t _sapp_x11_mod(uint32_t x11_mods) { uint32_t mods = 0; if (x11_mods & ShiftMask) { mods |= SAPP_MODIFIER_SHIFT; @@ -9177,11 +9449,91 @@ _SOKOL_PRIVATE int32_t _sapp_x11_keysym_to_unicode(KeySym keysym) { return -1; } +_SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { + SOKOL_ASSERT(src); + SOKOL_ASSERT(_sapp.drop.buffer); + + _sapp_clear_drop_buffer(); + _sapp.drop.num_files = 0; + + /* + src is (potentially percent-encoded) string made of one or multiple paths + separated by \r\n, each path starting with 'file://' + */ + bool err = false; + int src_count = 0; + char src_chr = 0; + char* dst_ptr = _sapp.drop.buffer; + const char* dst_end_ptr = dst_ptr + (_sapp.drop.max_path_length - 1); // room for terminating 0 + while (0 != (src_chr = *src++)) { + src_count++; + char dst_chr = 0; + /* check leading 'file://' */ + if (src_count <= 7) { + if (((src_count == 1) && (src_chr != 'f')) || + ((src_count == 2) && (src_chr != 'i')) || + ((src_count == 3) && (src_chr != 'l')) || + ((src_count == 4) && (src_chr != 'e')) || + ((src_count == 5) && (src_chr != ':')) || + ((src_count == 6) && (src_chr != '/')) || + ((src_count == 7) && (src_chr != '/'))) + { + SOKOL_LOG("sokol_app.h: dropped file URI doesn't start with file://"); + err = true; + break; + } + } + else if (src_chr == '\r') { + // skip + } + else if (src_chr == '\n') { + src_chr = 0; + src_count = 0; + _sapp.drop.num_files++; + // too many files is not an error + if (_sapp.drop.num_files >= _sapp.drop.max_files) { + break; + } + dst_ptr = _sapp.drop.buffer + _sapp.drop.num_files * _sapp.drop.max_path_length; + dst_end_ptr = dst_ptr + (_sapp.drop.max_path_length - 1); + } + else if ((src_chr == '%') && src[0] && src[1]) { + // a percent-encoded byte (most like UTF-8 multibyte sequence) + const char digits[3] = { src[0], src[1], 0 }; + src += 2; + dst_chr = (char) strtol(digits, 0, 16); + } + else { + dst_chr = src_chr; + } + if (dst_chr) { + // dst_end_ptr already has adjustment for terminating zero + if (dst_ptr < dst_end_ptr) { + *dst_ptr++ = dst_chr; + } + else { + SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)"); + err = true; + break; + } + } + } + if (err) { + _sapp_clear_drop_buffer(); + _sapp.drop.num_files = 0; + return false; + } + else { + return true; + } +} + // XLib manual says keycodes are in the range [8, 255] inclusive. // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html static bool _sapp_x11_keycodes[256]; _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { + Bool filtered = XFilterEvent(event, None); switch (event->type) { case GenericEvent: if (_sapp.mouse.locked && _sapp.x11.xi.available) { @@ -9214,7 +9566,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { break; case KeyPress: { - int keycode = event->xkey.keycode; + int keycode = (int)event->xkey.keycode; const sapp_keycode key = _sapp_x11_translate_key(keycode); bool repeat = _sapp_x11_keycodes[keycode & 0xFF]; _sapp_x11_keycodes[keycode & 0xFF] = true; @@ -9232,7 +9584,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { break; case KeyRelease: { - int keycode = event->xkey.keycode; + int keycode = (int)event->xkey.keycode; const sapp_keycode key = _sapp_x11_translate_key(keycode); _sapp_x11_keycodes[keycode & 0xFF] = false; if (key != SAPP_KEYCODE_INVALID) { @@ -9320,12 +9672,127 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { } break; case ClientMessage: + if (filtered) { + return; + } if (event->xclient.message_type == _sapp.x11.WM_PROTOCOLS) { - const Atom protocol = event->xclient.data.l[0]; + const Atom protocol = (Atom)event->xclient.data.l[0]; if (protocol == _sapp.x11.WM_DELETE_WINDOW) { _sapp.quit_requested = true; } } + else if (event->xclient.message_type == _sapp.x11.xdnd.XdndEnter) { + const bool is_list = 0 != (event->xclient.data.l[1] & 1); + _sapp.x11.xdnd.source = (Window)event->xclient.data.l[0]; + _sapp.x11.xdnd.version = event->xclient.data.l[1] >> 24; + _sapp.x11.xdnd.format = None; + if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { + return; + } + uint32_t count = 0; + Atom* formats = 0; + if (is_list) { + count = _sapp_x11_get_window_property(_sapp.x11.xdnd.source, _sapp.x11.xdnd.XdndTypeList, XA_ATOM, (unsigned char**)&formats); + } + else { + count = 3; + formats = (Atom*) event->xclient.data.l + 2; + } + for (uint32_t i = 0; i < count; i++) { + if (formats[i] == _sapp.x11.xdnd.text_uri_list) { + _sapp.x11.xdnd.format = _sapp.x11.xdnd.text_uri_list; + break; + } + } + if (is_list && formats) { + XFree(formats); + } + } + else if (event->xclient.message_type == _sapp.x11.xdnd.XdndDrop) { + if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { + return; + } + Time time = CurrentTime; + if (_sapp.x11.xdnd.format) { + if (_sapp.x11.xdnd.version >= 1) { + time = (Time)event->xclient.data.l[2]; + } + XConvertSelection(_sapp.x11.display, + _sapp.x11.xdnd.XdndSelection, + _sapp.x11.xdnd.format, + _sapp.x11.xdnd.XdndSelection, + _sapp.x11.window, + time); + } + else if (_sapp.x11.xdnd.version >= 2) { + XEvent reply; + memset(&reply, 0, sizeof(reply)); + reply.type = ClientMessage; + reply.xclient.window = _sapp.x11.window; + reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)_sapp.x11.window; + reply.xclient.data.l[1] = 0; // drag was rejected + reply.xclient.data.l[2] = None; + XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); + XFlush(_sapp.x11.display); + } + } + else if (event->xclient.message_type == _sapp.x11.xdnd.XdndPosition) { + /* drag operation has moved over the window + FIXME: we could track the mouse position here, but + this isn't implemented on other platforms either so far + */ + if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { + return; + } + XEvent reply; + memset(&reply, 0, sizeof(reply)); + reply.type = ClientMessage; + reply.xclient.window = _sapp.x11.xdnd.source; + reply.xclient.message_type = _sapp.x11.xdnd.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)_sapp.x11.window; + if (_sapp.x11.xdnd.format) { + /* reply that we are ready to copy the dragged data */ + reply.xclient.data.l[1] = 1; // accept with no rectangle + if (_sapp.x11.xdnd.version >= 2) { + reply.xclient.data.l[4] = (long)_sapp.x11.xdnd.XdndActionCopy; + } + } + XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); + XFlush(_sapp.x11.display); + } + break; + case SelectionNotify: + if (event->xselection.property == _sapp.x11.xdnd.XdndSelection) { + char* data = 0; + uint32_t result = _sapp_x11_get_window_property(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); + if (_sapp.drop.enabled && result) { + if (_sapp_x11_parse_dropped_files_list(data)) { + if (_sapp_events_enabled()) { + _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_call_event(&_sapp.event); + } + } + } + if (_sapp.x11.xdnd.version >= 2) { + XEvent reply; + memset(&reply, 0, sizeof(reply)); + reply.type = ClientMessage; + reply.xclient.window = _sapp.x11.window; + reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)_sapp.x11.window; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = (long)_sapp.x11.xdnd.XdndActionCopy; + XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); + XFlush(_sapp.x11.display); + } + } break; case DestroyNotify: break; @@ -9333,6 +9800,14 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { } _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { + /* The following lines are here to trigger a linker error instead of an + obscure runtime error if the user has forgotten to add -pthread to + the compiler or linker options. They have no other purpose. + */ + pthread_attr_t pthread_attr; + pthread_attr_init(&pthread_attr); + pthread_attr_destroy(&pthread_attr); + _sapp_init_state(desc); _sapp.x11.window_state = NormalState; @@ -9402,7 +9877,7 @@ int main(int argc, char* argv[]) { /*== PUBLIC API FUNCTIONS ====================================================*/ #if defined(SOKOL_NO_ENTRY) -SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) { +SOKOL_API_IMPL void sapp_run(const sapp_desc* desc) { SOKOL_ASSERT(desc); #if defined(_SAPP_MACOS) _sapp_macos_run(desc); @@ -9420,7 +9895,6 @@ SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) { // calling sapp_run() directly is not supported on Android) _sapp_fail("sapp_run() not supported on this platform!"); #endif - return 0; } /* this is just a stub so the linker doesn't complain */ @@ -9433,9 +9907,8 @@ sapp_desc sokol_main(int argc, char* argv[]) { } #else /* likewise, in normal mode, sapp_run() is just an empty stub */ -SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) { +SOKOL_API_IMPL void sapp_run(const sapp_desc* desc) { _SOKOL_UNUSED(desc); - return 0; } #endif @@ -9459,6 +9932,18 @@ SOKOL_API_IMPL int sapp_width(void) { return (_sapp.framebuffer_width > 0) ? _sapp.framebuffer_width : 1; } +SOKOL_API_IMPL float sapp_widthf(void) { + return (float)sapp_width(); +} + +SOKOL_API_IMPL int sapp_height(void) { + return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1; +} + +SOKOL_API_IMPL float sapp_heightf(void) { + return (float)sapp_height(); +} + SOKOL_API_IMPL int sapp_color_format(void) { #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) switch (_sapp.emsc.wgpu.render_format) { @@ -9485,10 +9970,6 @@ SOKOL_API_IMPL int sapp_sample_count(void) { return _sapp.sample_count; } -SOKOL_API_IMPL int sapp_height(void) { - return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1; -} - SOKOL_API_IMPL bool sapp_high_dpi(void) { return _sapp.desc.high_dpi && (_sapp.dpi_scale >= 1.5f); } @@ -9517,11 +9998,11 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { return _sapp.onscreen_keyboard_shown; } -SOKOL_API_DECL bool sapp_is_fullscreen(void) { +SOKOL_APP_API_DECL bool sapp_is_fullscreen(void) { return _sapp.fullscreen; } -SOKOL_API_DECL void sapp_toggle_fullscreen(void) { +SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { #if defined(_SAPP_MACOS) _sapp_macos_toggle_fullscreen(); #elif defined(_SAPP_WIN32) @@ -9589,6 +10070,7 @@ SOKOL_API_IMPL void sapp_consume_event(void) { /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { + SOKOL_ASSERT(_sapp.clipboard.enabled); if (!_sapp.clipboard.enabled) { return; } @@ -9606,6 +10088,7 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { + SOKOL_ASSERT(_sapp.clipboard.enabled); if (!_sapp.clipboard.enabled) { return ""; } @@ -9633,6 +10116,75 @@ SOKOL_API_IMPL void sapp_set_window_title(const char* title) { #endif } +SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { + SOKOL_ASSERT(_sapp.drop.enabled); + return _sapp.drop.num_files; +} + +SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { + SOKOL_ASSERT(_sapp.drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); + SOKOL_ASSERT(_sapp.drop.buffer); + if (!_sapp.drop.enabled) { + return ""; + } + if ((index < 0) || (index >= _sapp.drop.max_files)) { + return ""; + } + return (const char*) _sapp_dropped_file_path_ptr(index); +} + +SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { + SOKOL_ASSERT(_sapp.drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); + #if defined(_SAPP_EMSCRIPTEN) + if (!_sapp.drop.enabled) { + return 0; + } + return sapp_js_dropped_file_size(index); + #else + (void)index; + return 0; + #endif +} + +SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { + SOKOL_ASSERT(_sapp.drop.enabled); + SOKOL_ASSERT(request); + SOKOL_ASSERT(request->callback); + SOKOL_ASSERT(request->buffer_ptr); + SOKOL_ASSERT(request->buffer_size > 0); + #if defined(_SAPP_EMSCRIPTEN) + const int index = request->dropped_file_index; + sapp_html5_fetch_error error_code = SAPP_HTML5_FETCH_ERROR_NO_ERROR; + if ((index < 0) || (index >= _sapp.drop.num_files)) { + error_code = SAPP_HTML5_FETCH_ERROR_OTHER; + } + if (sapp_html5_get_dropped_file_size(index) > request->buffer_size) { + error_code = SAPP_HTML5_FETCH_ERROR_BUFFER_TOO_SMALL; + } + if (SAPP_HTML5_FETCH_ERROR_NO_ERROR != error_code) { + _sapp_emsc_invoke_fetch_cb(index, + false, // success + (int)error_code, + request->callback, + 0, // fetched_size + request->buffer_ptr, + request->buffer_size, + request->user_data); + } + else { + sapp_js_fetch_dropped_file(index, + request->callback, + request->buffer_ptr, + request->buffer_size, + request->user_data); + } + #else + (void)request; + #endif +} + SOKOL_API_IMPL const void* sapp_metal_get_device(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) @@ -9696,7 +10248,6 @@ SOKOL_API_IMPL const void* sapp_ios_get_window(void) { #else return 0; #endif - } SOKOL_API_IMPL const void* sapp_d3d11_get_device(void) { @@ -9720,7 +10271,12 @@ SOKOL_API_IMPL const void* sapp_d3d11_get_device_context(void) { SOKOL_API_IMPL const void* sapp_d3d11_get_render_target_view(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_D3D11) - return _sapp.d3d11.rtv; + if (_sapp.d3d11.msaa_rtv) { + return _sapp.d3d11.msaa_rtv; + } + else { + return _sapp.d3d11.rtv; + } #else return 0; #endif @@ -9803,4 +10359,4 @@ SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { _sapp.html5_ask_leave_site = ask; } -#endif /* SOKOL_IMPL */ +#endif /* SOKOL_APP_IMPL */ diff --git a/thirdparty/sokol/sokol_audio.h b/thirdparty/sokol/sokol_audio.h index 22b8ebd998..faea817726 100644 --- a/thirdparty/sokol/sokol_audio.h +++ b/thirdparty/sokol/sokol_audio.h @@ -1,3 +1,6 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_AUDIO_IMPL) +#define SOKOL_AUDIO_IMPL +#endif #ifndef SOKOL_AUDIO_INCLUDED /* sokol_audio.h -- cross-platform audio-streaming API @@ -5,7 +8,8 @@ Project URL: https://github.com/floooh/sokol Do this: - #define SOKOL_IMPL + #define SOKOL_IMPL or + #define SOKOL_AUDIO_IMPL before you include this file in *one* C or C++ file to create the implementation. @@ -16,29 +20,42 @@ SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_MALLOC(s) - your own malloc() implementation (default: malloc(s)) SOKOL_FREE(p) - your own free() implementation (default: free(p)) - SOKOL_API_DECL - public function declaration prefix (default: extern) + SOKOL_AUDIO_API_DECL- public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) - SAUDIO_RING_MAX_SLOTS - max number of slots in the push-audio ring buffer (default 1024) + SAUDIO_RING_MAX_SLOTS - max number of slots in the push-audio ring buffer (default 1024) + SAUDIO_OSX_USE_SYSTEM_HEADERS - define this to force inclusion of system headers on + macOS instead of using embedded CoreAudio declarations If sokol_audio.h is compiled as a DLL, define the following before including the declaration or implementation: SOKOL_DLL - On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport) + On Windows, SOKOL_DLL will define SOKOL_AUDIO_API_DECL as __declspec(dllexport) or __declspec(dllimport) as needed. + Link with the following libraries: + + - on macOS: AudioToolbox + - on iOS: AudioToolbox, AVFoundation + - on Linux: asound + - on Android: link with OpenSLES + - on Windows with MSVC or Clang toolchain: no action needed, libs are defined in-source via pragma-comment-lib + - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' and link with -lole32 + FEATURE OVERVIEW ================ You provide a mono- or stereo-stream of 32-bit float samples, which Sokol Audio feeds into platform-specific audio backends: - Windows: WASAPI - - Linux: ALSA (link with asound) - - macOS/iOS: CoreAudio (link with AudioToolbox) + - Linux: ALSA + - macOS: CoreAudio + - iOS: CoreAudio+AVAudioSession - emscripten: WebAudio with ScriptProcessorNode - - Android: OpenSLES (link with OpenSLES) + - Android: OpenSLES Sokol Audio will not do any buffer mixing or volume control, if you have multiple independent input streams of sample data you need to perform the @@ -302,9 +319,13 @@ THE COREAUDIO BACKEND ===================== The CoreAudio backend is selected on macOS and iOS (__APPLE__ is defined). - Since the CoreAudio API is implemented in C (not Objective-C) the + Since the CoreAudio API is implemented in C (not Objective-C) on macOS the implementation part of Sokol Audio can be included into a C source file. + However on iOS, Sokol Audio must be compiled as Objective-C due to it's + reliance on the AVAudioSession object. The iOS code path support both + being compiled with or without ARC (Automatic Reference Counting). + For thread synchronisation, the CoreAudio backend will use the pthread_mutex_* functions. @@ -374,13 +395,16 @@ #include #include -#ifndef SOKOL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) -#define SOKOL_API_DECL __declspec(dllexport) +#if defined(SOKOL_API_DECL) && !defined(SOKOL_AUDIO_API_DECL) +#define SOKOL_AUDIO_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_AUDIO_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_AUDIO_IMPL) +#define SOKOL_AUDIO_API_DECL __declspec(dllexport) #elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_API_DECL __declspec(dllimport) +#define SOKOL_AUDIO_API_DECL __declspec(dllimport) #else -#define SOKOL_API_DECL extern +#define SOKOL_AUDIO_API_DECL extern #endif #endif @@ -400,25 +424,25 @@ typedef struct saudio_desc { } saudio_desc; /* setup sokol-audio */ -SOKOL_API_DECL void saudio_setup(const saudio_desc* desc); +SOKOL_AUDIO_API_DECL void saudio_setup(const saudio_desc* desc); /* shutdown sokol-audio */ -SOKOL_API_DECL void saudio_shutdown(void); +SOKOL_AUDIO_API_DECL void saudio_shutdown(void); /* true after setup if audio backend was successfully initialized */ -SOKOL_API_DECL bool saudio_isvalid(void); +SOKOL_AUDIO_API_DECL bool saudio_isvalid(void); /* return the saudio_desc.user_data pointer */ -SOKOL_API_DECL void* saudio_userdata(void); +SOKOL_AUDIO_API_DECL void* saudio_userdata(void); /* return a copy of the original saudio_desc struct */ -SOKOL_API_DECL saudio_desc saudio_query_desc(void); +SOKOL_AUDIO_API_DECL saudio_desc saudio_query_desc(void); /* actual sample rate */ -SOKOL_API_DECL int saudio_sample_rate(void); +SOKOL_AUDIO_API_DECL int saudio_sample_rate(void); /* return actual backend buffer size in number of frames */ -SOKOL_API_DECL int saudio_buffer_frames(void); +SOKOL_AUDIO_API_DECL int saudio_buffer_frames(void); /* actual number of channels */ -SOKOL_API_DECL int saudio_channels(void); +SOKOL_AUDIO_API_DECL int saudio_channels(void); /* get current number of frames to fill packet queue */ -SOKOL_API_DECL int saudio_expect(void); +SOKOL_AUDIO_API_DECL int saudio_expect(void); /* push sample frames from main thread, returns number of frames actually pushed */ -SOKOL_API_DECL int saudio_push(const float* frames, int num_frames); +SOKOL_AUDIO_API_DECL int saudio_push(const float* frames, int num_frames); #ifdef __cplusplus } /* extern "C" */ @@ -430,9 +454,10 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #endif // SOKOL_AUDIO_INCLUDED /*=== IMPLEMENTATION =========================================================*/ -#ifdef SOKOL_IMPL +#ifdef SOKOL_AUDIO_IMPL #define SOKOL_AUDIO_IMPL_INCLUDED (1) -#include /* memset, memcpy */ +#include // memset, memcpy +#include // size_t #ifndef SOKOL_API_IMPL #define SOKOL_API_IMPL @@ -472,11 +497,40 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #define _SOKOL_UNUSED(x) (void)(x) #endif +// platform detection defines #if defined(SOKOL_DUMMY_BACKEND) - // No threads needed for SOKOL_DUMMY_BACKEND -#elif (defined(__APPLE__) || defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) - #include + // nothing +#elif defined(__APPLE__) + #define _SAUDIO_APPLE (1) + #include + #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE + #define _SAUDIO_IOS (1) + #else + #define _SAUDIO_MACOS (1) + #endif +#elif defined(__EMSCRIPTEN__) + #define _SAUDIO_EMSCRIPTEN #elif defined(_WIN32) + #define _SAUDIO_WINDOWS (1) + #include + #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) + #define _SAUDIO_UWP (1) + #else + #define _SAUDIO_WIN32 (1) + #endif +#elif defined(__ANDROID__) + #define _SAUDIO_ANDROID (1) +#elif defined(__linux__) || defined(__unix__) + #define _SAUDIO_LINUX (1) +#else +#error "sokol_audio.h: Unknown platform" +#endif + +// platform-specific headers and definitions +#if defined(SOKOL_DUMMY_BACKEND) + #define _SAUDIO_NOTHREADS (1) +#elif defined(_SAUDIO_WINDOWS) + #define _SAUDIO_WINTHREADS (1) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -485,28 +539,12 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #endif #include #include - #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) - #define SOKOL_WIN32_NO_MMDEVICE + #if defined(_SAUDIO_UWP) #pragma comment (lib, "WindowsApp") #else #pragma comment (lib, "kernel32") #pragma comment (lib, "ole32") - #if defined(SOKOL_WIN32_NO_MMDEVICE) - #pragma comment (lib, "mmdevapi") - #endif #endif -#endif - -#if defined(SOKOL_DUMMY_BACKEND) - // No audio API needed for SOKOL_DUMMY_BACKEND -#elif defined(__APPLE__) - #include -#elif (defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) - #define ALSA_PCM_NEW_HW_PARAMS_API - #include -#elif defined(__ANDROID__) - #include "SLES/OpenSLES_Android.h" -#elif defined(_WIN32) #ifndef CINTERFACE #define CINTERFACE #endif @@ -536,15 +574,44 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY #define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000 #endif + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4505) /* unreferenced local function has been removed */ + #endif +#elif defined(_SAUDIO_APPLE) + #define _SAUDIO_PTHREADS (1) + #include + #if defined(_SAUDIO_IOS) + // always use system headers on iOS (for now at least) + #if !defined(SAUDIO_OSX_USE_SYSTEM_HEADERS) + #define SAUDIO_OSX_USE_SYSTEM_HEADERS (1) + #endif + #if !defined(__cplusplus) + #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) + #error "sokol_audio.h on iOS requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" + #endif + #endif + #include + #include + #else + #if defined(SAUDIO_OSX_USE_SYSTEM_HEADERS) + #include + #endif + #endif +#elif defined(_SAUDIO_ANDROID) + #define _SAUDIO_PTHREADS (1) + #include + #include "SLES/OpenSLES_Android.h" +#elif defined(_SAUDIO_LINUX) + #define _SAUDIO_PTHREADS (1) + #include + #define ALSA_PCM_NEW_HW_PARAMS_API + #include #elif defined(__EMSCRIPTEN__) + #define _SAUDIO_NOTHREADS (1) #include #endif -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4505) /* unreferenced local function has been removed */ -#endif - #define _saudio_def(val, def) (((val) == 0) ? (def) : (val)) #define _saudio_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) @@ -558,40 +625,134 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #endif /*=== MUTEX WRAPPER DECLARATIONS =============================================*/ -#if defined(SOKOL_DUMMY_BACKEND) - -typedef struct { int dummy_mutex; } _saudio_mutex_t; - -#elif (defined(__APPLE__) || defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) +#if defined(_SAUDIO_PTHREADS) typedef struct { pthread_mutex_t mutex; } _saudio_mutex_t; -#elif defined(_WIN32) +#elif defined(_SAUDIO_WINTHREADS) typedef struct { CRITICAL_SECTION critsec; } _saudio_mutex_t; -#else -typedef struct { int dummy_mutex; } _saudio_mutex_t; +#elif defined(_SAUDIO_NOTHREADS) + +typedef struct { + int dummy_mutex; +} _saudio_mutex_t; + #endif /*=== DUMMY BACKEND DECLARATIONS =============================================*/ #if defined(SOKOL_DUMMY_BACKEND) + typedef struct { int dummy_backend; } _saudio_backend_t; + /*=== COREAUDIO BACKEND DECLARATIONS =========================================*/ -#elif defined(__APPLE__) +#elif defined(_SAUDIO_APPLE) + +#if defined(SAUDIO_OSX_USE_SYSTEM_HEADERS) + +typedef AudioQueueRef _saudio_AudioQueueRef; +typedef AudioQueueBufferRef _saudio_AudioQueueBufferRef; +typedef AudioStreamBasicDescription _saudio_AudioStreamBasicDescription; +typedef OSStatus _saudio_OSStatus; + +#define _saudio_kAudioFormatLinearPCM (kAudioFormatLinearPCM) +#define _saudio_kLinearPCMFormatFlagIsFloat (kLinearPCMFormatFlagIsFloat) +#define _saudio_kAudioFormatFlagIsPacked (kAudioFormatFlagIsPacked) + +#else + +// embedded AudioToolbox declarations +typedef uint32_t _saudio_AudioFormatID; +typedef uint32_t _saudio_AudioFormatFlags; +typedef int32_t _saudio_OSStatus; +typedef uint32_t _saudio_SMPTETimeType; +typedef uint32_t _saudio_SMPTETimeFlags; +typedef uint32_t _saudio_AudioTimeStampFlags; +typedef void* _saudio_CFRunLoopRef; +typedef void* _saudio_CFStringRef; +typedef void* _saudio_AudioQueueRef; + +#define _saudio_kAudioFormatLinearPCM ('lpcm') +#define _saudio_kLinearPCMFormatFlagIsFloat (1U << 0) +#define _saudio_kAudioFormatFlagIsPacked (1U << 3) + +typedef struct _saudio_AudioStreamBasicDescription { + double mSampleRate; + _saudio_AudioFormatID mFormatID; + _saudio_AudioFormatFlags mFormatFlags; + uint32_t mBytesPerPacket; + uint32_t mFramesPerPacket; + uint32_t mBytesPerFrame; + uint32_t mChannelsPerFrame; + uint32_t mBitsPerChannel; + uint32_t mReserved; +} _saudio_AudioStreamBasicDescription; + +typedef struct _saudio_AudioStreamPacketDescription { + int64_t mStartOffset; + uint32_t mVariableFramesInPacket; + uint32_t mDataByteSize; +} _saudio_AudioStreamPacketDescription; + +typedef struct _saudio_SMPTETime { + int16_t mSubframes; + int16_t mSubframeDivisor; + uint32_t mCounter; + _saudio_SMPTETimeType mType; + _saudio_SMPTETimeFlags mFlags; + int16_t mHours; + int16_t mMinutes; + int16_t mSeconds; + int16_t mFrames; +} _saudio_SMPTETime; + +typedef struct _saudio_AudioTimeStamp { + double mSampleTime; + uint64_t mHostTime; + double mRateScalar; + uint64_t mWordClockTime; + _saudio_SMPTETime mSMPTETime; + _saudio_AudioTimeStampFlags mFlags; + uint32_t mReserved; +} _saudio_AudioTimeStamp; + +typedef struct _saudio_AudioQueueBuffer { + const uint32_t mAudioDataBytesCapacity; + void* const mAudioData; + uint32_t mAudioDataByteSize; + void * mUserData; + const uint32_t mPacketDescriptionCapacity; + _saudio_AudioStreamPacketDescription* const mPacketDescriptions; + uint32_t mPacketDescriptionCount; +} _saudio_AudioQueueBuffer; +typedef _saudio_AudioQueueBuffer* _saudio_AudioQueueBufferRef; + +typedef void (*_saudio_AudioQueueOutputCallback)(void* user_data, _saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer); + +extern _saudio_OSStatus AudioQueueNewOutput(const _saudio_AudioStreamBasicDescription* inFormat, _saudio_AudioQueueOutputCallback inCallbackProc, void* inUserData, _saudio_CFRunLoopRef inCallbackRunLoop, _saudio_CFStringRef inCallbackRunLoopMode, uint32_t inFlags, _saudio_AudioQueueRef* outAQ); +extern _saudio_OSStatus AudioQueueDispose(_saudio_AudioQueueRef inAQ, bool inImmediate); +extern _saudio_OSStatus AudioQueueAllocateBuffer(_saudio_AudioQueueRef inAQ, uint32_t inBufferByteSize, _saudio_AudioQueueBufferRef* outBuffer); +extern _saudio_OSStatus AudioQueueEnqueueBuffer(_saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer, uint32_t inNumPacketDescs, const _saudio_AudioStreamPacketDescription* inPacketDescs); +extern _saudio_OSStatus AudioQueueStart(_saudio_AudioQueueRef inAQ, const _saudio_AudioTimeStamp * inStartTime); +extern _saudio_OSStatus AudioQueueStop(_saudio_AudioQueueRef inAQ, bool inImmediate); +#endif // SAUDIO_OSX_USE_SYSTEM_HEADERS typedef struct { - AudioQueueRef ca_audio_queue; + _saudio_AudioQueueRef ca_audio_queue; + #if defined(_SAUDIO_IOS) + id ca_interruption_handler; + #endif } _saudio_backend_t; /*=== ALSA BACKEND DECLARATIONS ==============================================*/ -#elif (defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) +#elif defined(_SAUDIO_LINUX) typedef struct { snd_pcm_t* device; @@ -603,7 +764,7 @@ typedef struct { } _saudio_backend_t; /*=== OpenSLES BACKEND DECLARATIONS ==============================================*/ -#elif defined(__ANDROID__) +#elif defined(_SAUDIO_ANDROID) #define SAUDIO_NUM_BUFFERS 2 @@ -635,7 +796,7 @@ typedef struct { } _saudio_backend_t; /*=== WASAPI BACKEND DECLARATIONS ============================================*/ -#elif defined(_WIN32) +#elif defined(_SAUDIO_WINDOWS) typedef struct { HANDLE thread_handle; @@ -649,15 +810,15 @@ typedef struct { } _saudio_wasapi_thread_data_t; typedef struct { -#if defined(SOKOL_WIN32_NO_MMDEVICE) - LPOLESTR interface_activation_audio_interface_uid_string; - IActivateAudioInterfaceAsyncOperation* interface_activation_operation; - BOOL interface_activation_success; - HANDLE interface_activation_mutex; -#else - IMMDeviceEnumerator* device_enumerator; - IMMDevice* device; -#endif + #if defined(_SAUDIO_UWP) + LPOLESTR interface_activation_audio_interface_uid_string; + IActivateAudioInterfaceAsyncOperation* interface_activation_operation; + BOOL interface_activation_success; + HANDLE interface_activation_mutex; + #else + IMMDeviceEnumerator* device_enumerator; + IMMDevice* device; + #endif IAudioClient* audio_client; IAudioRenderClient* render_client; int si16_bytes_per_frame; @@ -665,24 +826,24 @@ typedef struct { } _saudio_backend_t; /*=== WEBAUDIO BACKEND DECLARATIONS ==========================================*/ -#elif defined(__EMSCRIPTEN__) +#elif defined(_SAUDIO_EMSCRIPTEN) typedef struct { uint8_t* buffer; } _saudio_backend_t; -/*=== DUMMY BACKEND DECLARATIONS =============================================*/ #else -typedef struct { } _saudio_backend_t; +#error "unknown platform" #endif + /*=== GENERAL DECLARATIONS ===================================================*/ /* a ringbuffer structure */ typedef struct { - uint32_t head; /* next slot to write to */ - uint32_t tail; /* next slot to read from */ - uint32_t num; /* number of slots in queue */ - uint32_t queue[SAUDIO_RING_MAX_SLOTS]; + int head; // next slot to write to + int tail; // next slot to read from + int num; // number of slots in queue + int queue[SAUDIO_RING_MAX_SLOTS]; } _saudio_ring_t; /* a packet FIFO structure */ @@ -731,12 +892,15 @@ _SOKOL_PRIVATE void _saudio_stream_callback(float* buffer, int num_frames, int n } /*=== MUTEX IMPLEMENTATION ===================================================*/ -#if defined(SOKOL_DUMMY_BACKEND) +#if defined(_SAUDIO_NOTHREADS) + _SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { (void)m; } _SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) { (void)m; } _SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { (void)m; } _SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { (void)m; } -#elif (defined(__APPLE__) || defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) + +#elif defined(_SAUDIO_PTHREADS) + _SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); @@ -755,7 +919,8 @@ _SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { pthread_mutex_unlock(&m->mutex); } -#elif defined(_WIN32) +#elif defined(_SAUDIO_WINTHREADS) + _SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { InitializeCriticalSection(&m->critsec); } @@ -772,18 +937,15 @@ _SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { LeaveCriticalSection(&m->critsec); } #else -_SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) { (void)m; } -_SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) { (void)m; } -_SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) { (void)m; } -_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) { (void)m; } +#error "unknown platform!" #endif /*=== RING-BUFFER QUEUE IMPLEMENTATION =======================================*/ -_SOKOL_PRIVATE uint16_t _saudio_ring_idx(_saudio_ring_t* ring, uint32_t i) { - return (uint16_t) (i % ring->num); +_SOKOL_PRIVATE int _saudio_ring_idx(_saudio_ring_t* ring, int i) { + return (i % ring->num); } -_SOKOL_PRIVATE void _saudio_ring_init(_saudio_ring_t* ring, uint32_t num_slots) { +_SOKOL_PRIVATE void _saudio_ring_init(_saudio_ring_t* ring, int num_slots) { SOKOL_ASSERT((num_slots + 1) <= SAUDIO_RING_MAX_SLOTS); ring->head = 0; ring->tail = 0; @@ -800,7 +962,7 @@ _SOKOL_PRIVATE bool _saudio_ring_empty(_saudio_ring_t* ring) { } _SOKOL_PRIVATE int _saudio_ring_count(_saudio_ring_t* ring) { - uint32_t count; + int count; if (ring->head >= ring->tail) { count = ring->head - ring->tail; } @@ -811,15 +973,15 @@ _SOKOL_PRIVATE int _saudio_ring_count(_saudio_ring_t* ring) { return count; } -_SOKOL_PRIVATE void _saudio_ring_enqueue(_saudio_ring_t* ring, uint32_t val) { +_SOKOL_PRIVATE void _saudio_ring_enqueue(_saudio_ring_t* ring, int val) { SOKOL_ASSERT(!_saudio_ring_full(ring)); ring->queue[ring->head] = val; ring->head = _saudio_ring_idx(ring, ring->head + 1); } -_SOKOL_PRIVATE uint32_t _saudio_ring_dequeue(_saudio_ring_t* ring) { +_SOKOL_PRIVATE int _saudio_ring_dequeue(_saudio_ring_t* ring) { SOKOL_ASSERT(!_saudio_ring_empty(ring)); - uint32_t val = ring->queue[ring->tail]; + int val = ring->queue[ring->tail]; ring->tail = _saudio_ring_idx(ring, ring->tail + 1); return val; } @@ -839,7 +1001,7 @@ _SOKOL_PRIVATE void _saudio_fifo_init(_saudio_fifo_t* fifo, int packet_size, int SOKOL_ASSERT((packet_size > 0) && (num_packets > 0)); fifo->packet_size = packet_size; fifo->num_packets = num_packets; - fifo->base_ptr = (uint8_t*) SOKOL_MALLOC(packet_size * num_packets); + fifo->base_ptr = (uint8_t*) SOKOL_MALLOC((size_t)(packet_size * num_packets)); SOKOL_ASSERT(fifo->base_ptr); fifo->cur_packet = -1; fifo->cur_offset = 0; @@ -899,7 +1061,7 @@ _SOKOL_PRIVATE int _saudio_fifo_write(_saudio_fifo_t* fifo, const uint8_t* ptr, to_copy = max_copy; } uint8_t* dst = fifo->base_ptr + fifo->cur_packet * fifo->packet_size + fifo->cur_offset; - memcpy(dst, ptr, to_copy); + memcpy(dst, ptr, (size_t)to_copy); ptr += to_copy; fifo->cur_offset += to_copy; all_to_copy -= to_copy; @@ -941,7 +1103,7 @@ _SOKOL_PRIVATE int _saudio_fifo_read(_saudio_fifo_t* fifo, uint8_t* ptr, int num int packet_index = _saudio_ring_dequeue(&fifo->read_queue); _saudio_ring_enqueue(&fifo->write_queue, packet_index); const uint8_t* src = fifo->base_ptr + packet_index * fifo->packet_size; - memcpy(dst, src, fifo->packet_size); + memcpy(dst, src, (size_t)fifo->packet_size); dst += fifo->packet_size; num_bytes_copied += fifo->packet_size; } @@ -955,19 +1117,70 @@ _SOKOL_PRIVATE int _saudio_fifo_read(_saudio_fifo_t* fifo, uint8_t* ptr, int num /*=== DUMMY BACKEND IMPLEMENTATION ===========================================*/ #if defined(SOKOL_DUMMY_BACKEND) _SOKOL_PRIVATE bool _saudio_backend_init(void) { - _saudio.bytes_per_frame = _saudio.num_channels * sizeof(float); + _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); return true; }; _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { }; /*=== COREAUDIO BACKEND IMPLEMENTATION =======================================*/ -#elif defined(__APPLE__) +#elif defined(_SAUDIO_APPLE) + +#if defined(_SAUDIO_IOS) +#if __has_feature(objc_arc) +#define _SAUDIO_OBJC_RELEASE(obj) { obj = nil; } +#else +#define _SAUDIO_OBJC_RELEASE(obj) { [obj release]; obj = nil; } +#endif + +@interface _saudio_interruption_handler : NSObject { } +@end + +@implementation _saudio_interruption_handler +-(id)init { + self = [super init]; + AVAudioSession* session = [AVAudioSession sharedInstance]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:session]; + return self; +} + +-(void)dealloc { + [self remove_handler]; + #if !__has_feature(objc_arc) + [super dealloc]; + #endif +} + +-(void)remove_handler { + [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVAudioSessionInterruptionNotification" object:nil]; +} + +-(void)handle_interruption:(NSNotification*)notification { + AVAudioSession* session = [AVAudioSession sharedInstance]; + SOKOL_ASSERT(session); + NSDictionary* dict = notification.userInfo; + SOKOL_ASSERT(dict); + NSInteger type = [[dict valueForKey:AVAudioSessionInterruptionTypeKey] integerValue]; + switch (type) { + case AVAudioSessionInterruptionTypeBegan: + AudioQueuePause(_saudio.backend.ca_audio_queue); + [session setActive:false error:nil]; + break; + case AVAudioSessionInterruptionTypeEnded: + [session setActive:true error:nil]; + AudioQueueStart(_saudio.backend.ca_audio_queue, NULL); + break; + default: + break; + } +} +@end +#endif // _SAUDIO_IOS /* NOTE: the buffer data callback is called on a separate thread! */ -_SOKOL_PRIVATE void _sapp_ca_callback(void* user_data, AudioQueueRef queue, AudioQueueBufferRef buffer) { +_SOKOL_PRIVATE void _saudio_coreaudio_callback(void* user_data, _saudio_AudioQueueRef queue, _saudio_AudioQueueBufferRef buffer) { _SOKOL_UNUSED(user_data); if (_saudio_has_callback()) { - const int num_frames = buffer->mAudioDataByteSize / _saudio.bytes_per_frame; + const int num_frames = (int)buffer->mAudioDataByteSize / _saudio.bytes_per_frame; const int num_channels = _saudio.num_channels; _saudio_stream_callback((float*)buffer->mAudioData, num_frames, num_channels); } @@ -976,7 +1189,7 @@ _SOKOL_PRIVATE void _sapp_ca_callback(void* user_data, AudioQueueRef queue, Audi int num_bytes = (int) buffer->mAudioDataByteSize; if (0 == _saudio_fifo_read(&_saudio.fifo, ptr, num_bytes)) { /* not enough read data available, fill the entire buffer with silence */ - memset(ptr, 0, num_bytes); + memset(ptr, 0, (size_t)num_bytes); } } AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); @@ -985,24 +1198,35 @@ _SOKOL_PRIVATE void _sapp_ca_callback(void* user_data, AudioQueueRef queue, Audi _SOKOL_PRIVATE bool _saudio_backend_init(void) { SOKOL_ASSERT(0 == _saudio.backend.ca_audio_queue); + #if defined(_SAUDIO_IOS) + /* activate audio session */ + AVAudioSession* session = [AVAudioSession sharedInstance]; + SOKOL_ASSERT(session != nil); + [session setCategory: AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil]; + [session setActive:true error:nil]; + + /* create interruption handler */ + _saudio.backend.ca_interruption_handler = [[_saudio_interruption_handler alloc] init]; + #endif // _SAUDIO_IOS + /* create an audio queue with fp32 samples */ - AudioStreamBasicDescription fmt; + _saudio_AudioStreamBasicDescription fmt; memset(&fmt, 0, sizeof(fmt)); - fmt.mSampleRate = (Float64) _saudio.sample_rate; - fmt.mFormatID = kAudioFormatLinearPCM; - fmt.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsPacked; + fmt.mSampleRate = (double) _saudio.sample_rate; + fmt.mFormatID = _saudio_kAudioFormatLinearPCM; + fmt.mFormatFlags = _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked; fmt.mFramesPerPacket = 1; - fmt.mChannelsPerFrame = _saudio.num_channels; - fmt.mBytesPerFrame = sizeof(float) * _saudio.num_channels; + fmt.mChannelsPerFrame = (uint32_t) _saudio.num_channels; + fmt.mBytesPerFrame = (uint32_t)sizeof(float) * (uint32_t)_saudio.num_channels; fmt.mBytesPerPacket = fmt.mBytesPerFrame; fmt.mBitsPerChannel = 32; - OSStatus res = AudioQueueNewOutput(&fmt, _sapp_ca_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue); + _saudio_OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue); SOKOL_ASSERT((res == 0) && _saudio.backend.ca_audio_queue); /* create 2 audio buffers */ for (int i = 0; i < 2; i++) { - AudioQueueBufferRef buf = NULL; - const uint32_t buf_byte_size = _saudio.buffer_frames * fmt.mBytesPerFrame; + _saudio_AudioQueueBufferRef buf = NULL; + const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame; res = AudioQueueAllocateBuffer(_saudio.backend.ca_audio_queue, buf_byte_size, &buf); SOKOL_ASSERT((res == 0) && buf); buf->mAudioDataByteSize = buf_byte_size; @@ -1011,7 +1235,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { } /* init or modify actual playback parameters */ - _saudio.bytes_per_frame = fmt.mBytesPerFrame; + _saudio.bytes_per_frame = (int)fmt.mBytesPerFrame; /* ...and start playback */ res = AudioQueueStart(_saudio.backend.ca_audio_queue, NULL); @@ -1024,17 +1248,28 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { AudioQueueStop(_saudio.backend.ca_audio_queue, true); AudioQueueDispose(_saudio.backend.ca_audio_queue, false); _saudio.backend.ca_audio_queue = NULL; + #if defined(_SAUDIO_IOS) + /* remove interruption handler */ + if (_saudio.backend.ca_interruption_handler != nil) { + [_saudio.backend.ca_interruption_handler remove_handler]; + _SAUDIO_OBJC_RELEASE(_saudio.backend.ca_interruption_handler); + } + /* deactivate audio session */ + AVAudioSession* session = [AVAudioSession sharedInstance]; + SOKOL_ASSERT(session); + [session setActive:false error:nil];; + #endif // _SAUDIO_IOS } /*=== ALSA BACKEND IMPLEMENTATION ============================================*/ -#elif (defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) +#elif defined(_SAUDIO_LINUX) /* the streaming callback runs in a separate thread */ _SOKOL_PRIVATE void* _saudio_alsa_cb(void* param) { _SOKOL_UNUSED(param); while (!_saudio.backend.thread_stop) { /* snd_pcm_writei() will be blocking until it needs data */ - int write_res = snd_pcm_writei(_saudio.backend.device, _saudio.backend.buffer, _saudio.backend.buffer_frames); + int write_res = snd_pcm_writei(_saudio.backend.device, _saudio.backend.buffer, (snd_pcm_uframes_t)_saudio.backend.buffer_frames); if (write_res < 0) { /* underrun occurred */ snd_pcm_prepare(_saudio.backend.device); @@ -1047,7 +1282,7 @@ _SOKOL_PRIVATE void* _saudio_alsa_cb(void* param) { else { if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) { /* not enough read data available, fill the entire buffer with silence */ - memset(_saudio.backend.buffer, 0, _saudio.backend.buffer_byte_size); + memset(_saudio.backend.buffer, 0, (size_t)_saudio.backend.buffer_byte_size); } } } @@ -1056,47 +1291,58 @@ _SOKOL_PRIVATE void* _saudio_alsa_cb(void* param) { } _SOKOL_PRIVATE bool _saudio_backend_init(void) { - int dir; unsigned int val; + int dir; uint32_t rate; int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { + SOKOL_LOG("sokol_audio.h: snd_pcm_open() failed"); return false; } + + /* configuration works by restricting the 'configuration space' step + by step, we require all parameters except the sample rate to + match perfectly + */ snd_pcm_hw_params_t* params = 0; snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(_saudio.backend.device, params); snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_channels(_saudio.backend.device, params, _saudio.num_channels); - snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, _saudio.buffer_frames); - if (0 > snd_pcm_hw_params_test_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) { + if (0 > snd_pcm_hw_params_set_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) { + SOKOL_LOG("sokol_audio.h: float samples not supported"); goto error; } - else { - snd_pcm_hw_params_set_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE); + if (0 > snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, (snd_pcm_uframes_t)_saudio.buffer_frames)) { + SOKOL_LOG("sokol_audio.h: requested buffer size not supported"); + goto error; } - val = _saudio.sample_rate; + if (0 > snd_pcm_hw_params_set_channels(_saudio.backend.device, params, (uint32_t)_saudio.num_channels)) { + SOKOL_LOG("sokol_audio.h: requested channel count not supported"); + goto error; + } + /* let ALSA pick a nearby sampling rate */ + rate = (uint32_t) _saudio.sample_rate; dir = 0; - if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &val, &dir)) { + if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &rate, &dir)) { + SOKOL_LOG("sokol_audio.h: snd_pcm_hw_params_set_rate_near() failed"); goto error; } if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) { + SOKOL_LOG("sokol_audio.h: snd_pcm_hw_params() failed"); goto error; } /* read back actual sample rate and channels */ - snd_pcm_hw_params_get_rate(params, &val, &dir); - _saudio.sample_rate = val; - snd_pcm_hw_params_get_channels(params, &val); - SOKOL_ASSERT((int)val == _saudio.num_channels); - _saudio.bytes_per_frame = _saudio.num_channels * sizeof(float); + _saudio.sample_rate = (int)rate; + _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); /* allocate the streaming buffer */ _saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame; _saudio.backend.buffer_frames = _saudio.buffer_frames; - _saudio.backend.buffer = (float*) SOKOL_MALLOC(_saudio.backend.buffer_byte_size); - memset(_saudio.backend.buffer, 0, _saudio.backend.buffer_byte_size); + _saudio.backend.buffer = (float*) SOKOL_MALLOC((size_t)_saudio.backend.buffer_byte_size); + memset(_saudio.backend.buffer, 0, (size_t)_saudio.backend.buffer_byte_size); /* create the buffer-streaming start thread */ if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_alsa_cb, 0)) { + SOKOL_LOG("sokol_audio.h: pthread_create() failed"); goto error; } @@ -1119,9 +1365,9 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { }; /*=== WASAPI BACKEND IMPLEMENTATION ==========================================*/ -#elif defined(_WIN32) +#elif defined(_SAUDIO_WINDOWS) -#if defined(SOKOL_WIN32_NO_MMDEVICE) +#if defined(_SAUDIO_UWP) /* Minimal implementation of an IActivateAudioInterfaceCompletionHandler COM object in plain C. Meant to be a static singleton (always one reference when add/remove reference) and implements IUnknown and IActivateAudioInterfaceCompletionHandler when queryinterface'd @@ -1161,7 +1407,7 @@ _SOKOL_PRIVATE HRESULT STDMETHODCALLTYPE _saudio_backend_activate_audio_interfac ReleaseMutex(_saudio.backend.interface_activation_mutex); return S_OK; } -#endif +#endif // _SAUDIO_UWP /* fill intermediate buffer with new data and reset buffer_pos */ _SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) { @@ -1171,12 +1417,12 @@ _SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) { else { if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.thread.src_buffer, _saudio.backend.thread.src_buffer_byte_size)) { /* not enough read data available, fill the entire buffer with silence */ - memset(_saudio.backend.thread.src_buffer, 0, _saudio.backend.thread.src_buffer_byte_size); + memset(_saudio.backend.thread.src_buffer, 0, (size_t)_saudio.backend.thread.src_buffer_byte_size); } } } -_SOKOL_PRIVATE void _saudio_wasapi_submit_buffer(UINT32 num_frames) { +_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))) { return; @@ -1186,8 +1432,8 @@ _SOKOL_PRIVATE void _saudio_wasapi_submit_buffer(UINT32 num_frames) { /* 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; - uint32_t buffer_pos = _saudio.backend.thread.src_buffer_pos; - const uint32_t buffer_float_size = _saudio.backend.thread.src_buffer_byte_size / sizeof(float); + 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++) { if (0 == buffer_pos) { @@ -1215,7 +1461,7 @@ _SOKOL_PRIVATE DWORD WINAPI _saudio_wasapi_thread_fn(LPVOID param) { continue; } SOKOL_ASSERT(_saudio.backend.thread.dst_buffer_frames >= padding); - UINT32 num_frames = _saudio.backend.thread.dst_buffer_frames - padding; + int num_frames = (int)_saudio.backend.thread.dst_buffer_frames - (int)padding; if (num_frames > 0) { _saudio_wasapi_submit_buffer(num_frames); } @@ -1236,25 +1482,25 @@ _SOKOL_PRIVATE void _saudio_wasapi_release(void) { IAudioClient_Release(_saudio.backend.audio_client); _saudio.backend.audio_client = 0; } -#if defined(SOKOL_WIN32_NO_MMDEVICE) - if (_saudio.backend.interface_activation_audio_interface_uid_string) { - CoTaskMemFree(_saudio.backend.interface_activation_audio_interface_uid_string); - _saudio.backend.interface_activation_audio_interface_uid_string = 0; - } - if (_saudio.backend.interface_activation_operation) { - IActivateAudioInterfaceAsyncOperation_Release(_saudio.backend.interface_activation_operation); - _saudio.backend.interface_activation_operation = 0; - } -#else - if (_saudio.backend.device) { - IMMDevice_Release(_saudio.backend.device); - _saudio.backend.device = 0; - } - if (_saudio.backend.device_enumerator) { - IMMDeviceEnumerator_Release(_saudio.backend.device_enumerator); - _saudio.backend.device_enumerator = 0; - } -#endif + #if defined(_SAUDIO_UWP) + if (_saudio.backend.interface_activation_audio_interface_uid_string) { + CoTaskMemFree(_saudio.backend.interface_activation_audio_interface_uid_string); + _saudio.backend.interface_activation_audio_interface_uid_string = 0; + } + if (_saudio.backend.interface_activation_operation) { + IActivateAudioInterfaceAsyncOperation_Release(_saudio.backend.interface_activation_operation); + _saudio.backend.interface_activation_operation = 0; + } + #else + if (_saudio.backend.device) { + IMMDevice_Release(_saudio.backend.device); + _saudio.backend.device = 0; + } + if (_saudio.backend.device_enumerator) { + IMMDeviceEnumerator_Release(_saudio.backend.device_enumerator); + _saudio.backend.device_enumerator = 0; + } + #endif if (0 != _saudio.backend.thread.buffer_end_event) { CloseHandle(_saudio.backend.thread.buffer_end_event); _saudio.backend.thread.buffer_end_event = 0; @@ -1265,83 +1511,83 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { REFERENCE_TIME dur; /* UWP Threads are CoInitialized by default with a different threading model, and this call fails See https://github.com/Microsoft/cppwinrt/issues/6#issuecomment-253930637 */ -#if (defined(WINAPI_FAMILY_PARTITION) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) - /* CoInitializeEx could have been called elsewhere already, in which - case the function returns with S_FALSE (thus it doesn't make much - sense to check the result) - */ - HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED); - _SOKOL_UNUSED(hr); -#endif + #if defined(_SAUDIO_WIN32) + /* CoInitializeEx could have been called elsewhere already, in which + case the function returns with S_FALSE (thus it does not make much + sense to check the result) + */ + HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED); + _SOKOL_UNUSED(hr); + #endif _saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0); if (0 == _saudio.backend.thread.buffer_end_event) { SOKOL_LOG("sokol_audio wasapi: failed to create buffer_end_event"); goto error; } -#if defined(SOKOL_WIN32_NO_MMDEVICE) - _saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex"); - if (_saudio.backend.interface_activation_mutex == NULL) { - SOKOL_LOG("sokol_audio wasapi: failed to create interface activation mutex"); - goto error; - } - if (FAILED(StringFromIID(_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_Devinterface_Audio_Render), &_saudio.backend.interface_activation_audio_interface_uid_string))) { - SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string"); - goto error; - } - - /* static instance of the fake COM object */ - static IActivateAudioInterfaceCompletionHandlerVtbl completion_handler_interface_vtable = { - _saudio_interface_completion_handler_queryinterface, - _saudio_interface_completion_handler_addref_release, - _saudio_interface_completion_handler_addref_release, - _saudio_backend_activate_audio_interface_cb - }; - static IActivateAudioInterfaceCompletionHandler completion_handler_interface = { &completion_handler_interface_vtable }; - - if (FAILED(ActivateAudioInterfaceAsync(_saudio.backend.interface_activation_audio_interface_uid_string, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), NULL, &completion_handler_interface, &_saudio.backend.interface_activation_operation))) { - SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string"); - goto error; - } - while (!(_saudio.backend.audio_client)) { - if (WaitForSingleObject(_saudio.backend.interface_activation_mutex, 10) != WAIT_TIMEOUT) { - ReleaseMutex(_saudio.backend.interface_activation_mutex); + #if defined(_SAUDIO_UWP) + _saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex"); + if (_saudio.backend.interface_activation_mutex == NULL) { + SOKOL_LOG("sokol_audio wasapi: failed to create interface activation mutex"); + goto error; + } + if (FAILED(StringFromIID(_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_Devinterface_Audio_Render), &_saudio.backend.interface_activation_audio_interface_uid_string))) { + SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string"); + goto error; } - } - if (!(_saudio.backend.interface_activation_success)) { - SOKOL_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client"); - goto error; - } + /* static instance of the fake COM object */ + static IActivateAudioInterfaceCompletionHandlerVtbl completion_handler_interface_vtable = { + _saudio_interface_completion_handler_queryinterface, + _saudio_interface_completion_handler_addref_release, + _saudio_interface_completion_handler_addref_release, + _saudio_backend_activate_audio_interface_cb + }; + static IActivateAudioInterfaceCompletionHandler completion_handler_interface = { &completion_handler_interface_vtable }; -#else - if (FAILED(CoCreateInstance(_SOKOL_AUDIO_WIN32COM_ID(_saudio_CLSID_IMMDeviceEnumerator), - 0, CLSCTX_ALL, - _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator), - (void**)&_saudio.backend.device_enumerator))) - { - SOKOL_LOG("sokol_audio wasapi: failed to create device enumerator"); - goto error; - } - if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator, - eRender, eConsole, - &_saudio.backend.device))) - { - SOKOL_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed"); - goto error; - } - if (FAILED(IMMDevice_Activate(_saudio.backend.device, - _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), - CLSCTX_ALL, 0, - (void**)&_saudio.backend.audio_client))) - { - SOKOL_LOG("sokol_audio wasapi: device activate failed"); - goto error; - } -#endif + if (FAILED(ActivateAudioInterfaceAsync(_saudio.backend.interface_activation_audio_interface_uid_string, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), NULL, &completion_handler_interface, &_saudio.backend.interface_activation_operation))) { + SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string"); + goto error; + } + while (!(_saudio.backend.audio_client)) { + if (WaitForSingleObject(_saudio.backend.interface_activation_mutex, 10) != WAIT_TIMEOUT) { + ReleaseMutex(_saudio.backend.interface_activation_mutex); + } + } + + if (!(_saudio.backend.interface_activation_success)) { + SOKOL_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client"); + goto error; + } + + #else + if (FAILED(CoCreateInstance(_SOKOL_AUDIO_WIN32COM_ID(_saudio_CLSID_IMMDeviceEnumerator), + 0, CLSCTX_ALL, + _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator), + (void**)&_saudio.backend.device_enumerator))) + { + SOKOL_LOG("sokol_audio wasapi: failed to create device enumerator"); + goto error; + } + if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator, + eRender, eConsole, + &_saudio.backend.device))) + { + SOKOL_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed"); + goto error; + } + if (FAILED(IMMDevice_Activate(_saudio.backend.device, + _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), + CLSCTX_ALL, 0, + (void**)&_saudio.backend.audio_client))) + { + SOKOL_LOG("sokol_audio wasapi: device activate failed"); + goto error; + } + #endif WAVEFORMATEX fmt; memset(&fmt, 0, sizeof(fmt)); - fmt.nChannels = (WORD) _saudio.num_channels; - fmt.nSamplesPerSec = _saudio.sample_rate; + 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; @@ -1371,13 +1617,13 @@ _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 * sizeof(int16_t); - _saudio.bytes_per_frame = _saudio.num_channels * sizeof(float); + _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; /* allocate an intermediate buffer for sample format conversion */ - _saudio.backend.thread.src_buffer = (float*) SOKOL_MALLOC(_saudio.backend.thread.src_buffer_byte_size); + _saudio.backend.thread.src_buffer = (float*) SOKOL_MALLOC((size_t)_saudio.backend.thread.src_buffer_byte_size); SOKOL_ASSERT(_saudio.backend.thread.src_buffer); /* create streaming thread */ @@ -1405,13 +1651,13 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { } _saudio_wasapi_release(); -#if (defined(WINAPI_FAMILY_PARTITION) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) - CoUninitialize(); -#endif + #if defined(_SAUDIO_WIN32) + CoUninitialize(); + #endif } /*=== EMSCRIPTEN BACKEND IMPLEMENTATION ======================================*/ -#elif defined(__EMSCRIPTEN__) +#elif defined(_SAUDIO_EMSCRIPTEN) #ifdef __cplusplus extern "C" { @@ -1427,7 +1673,7 @@ EMSCRIPTEN_KEEPALIVE int _saudio_emsc_pull(int num_frames) { const int num_bytes = num_frames * _saudio.bytes_per_frame; if (0 == _saudio_fifo_read(&_saudio.fifo, _saudio.backend.buffer, num_bytes)) { /* not enough read data available, fill the entire buffer with silence */ - memset(_saudio.backend.buffer, 0, num_bytes); + memset(_saudio.backend.buffer, 0, (size_t)num_bytes); } } int res = (int) _saudio.backend.buffer; @@ -1532,10 +1778,10 @@ EM_JS(int, saudio_js_buffer_frames, (void), { _SOKOL_PRIVATE bool _saudio_backend_init(void) { if (saudio_js_init(_saudio.sample_rate, _saudio.num_channels, _saudio.buffer_frames)) { - _saudio.bytes_per_frame = sizeof(float) * _saudio.num_channels; + _saudio.bytes_per_frame = (int)sizeof(float) * _saudio.num_channels; _saudio.sample_rate = saudio_js_sample_rate(); _saudio.buffer_frames = saudio_js_buffer_frames(); - const int buf_size = _saudio.buffer_frames * _saudio.bytes_per_frame; + const size_t buf_size = (size_t) (_saudio.buffer_frames * _saudio.bytes_per_frame); _saudio.backend.buffer = (uint8_t*) SOKOL_MALLOC(buf_size); return true; } @@ -1553,7 +1799,7 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { } /*=== ANDROID BACKEND IMPLEMENTATION ======================================*/ -#elif defined(__ANDROID__) +#elif defined(_SAUDIO_ANDROID) #ifdef __cplusplus extern "C" { @@ -1618,10 +1864,10 @@ _SOKOL_PRIVATE void _saudio_opensles_fill_buffer(void) { _saudio_stream_callback(_saudio.backend.src_buffer, src_buffer_frames, _saudio.num_channels); } else { - const int src_buffer_byte_size = src_buffer_frames * _saudio.num_channels * sizeof(float); + const int src_buffer_byte_size = src_buffer_frames * _saudio.num_channels * (int)sizeof(float); if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.src_buffer, src_buffer_byte_size)) { /* not enough read data available, fill the entire buffer with silence */ - memset(_saudio.backend.src_buffer, 0x0, src_buffer_byte_size); + memset(_saudio.backend.src_buffer, 0x0, (size_t)src_buffer_byte_size); } } } @@ -1643,8 +1889,8 @@ _SOKOL_PRIVATE void* _saudio_opensles_thread_fn(void* param) { int16_t* next_buffer = _saudio.backend.output_buffers[_saudio.backend.active_buffer]; /* queue this buffer */ - const int buffer_size_bytes = _saudio.buffer_frames * _saudio.num_channels * sizeof(short); - (*_saudio.backend.player_buffer_queue)->Enqueue(_saudio.backend.player_buffer_queue, out_buffer, buffer_size_bytes); + const int buffer_size_bytes = _saudio.buffer_frames * _saudio.num_channels * (int)sizeof(short); + (*_saudio.backend.player_buffer_queue)->Enqueue(_saudio.backend.player_buffer_queue, out_buffer, (SLuint32)buffer_size_bytes); /* fill the next buffer */ _saudio_opensles_fill_buffer(); @@ -1682,23 +1928,22 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) { } _SOKOL_PRIVATE bool _saudio_backend_init(void) { - _saudio.bytes_per_frame = sizeof(float) * _saudio.num_channels; + _saudio.bytes_per_frame = (int)sizeof(float) * _saudio.num_channels; for (int i = 0; i < SAUDIO_NUM_BUFFERS; ++i) { - const int buffer_size_bytes = sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames; - _saudio.backend.output_buffers[i] = (int16_t*) SOKOL_MALLOC(buffer_size_bytes); + const int buffer_size_bytes = (int)sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames; + _saudio.backend.output_buffers[i] = (int16_t*) SOKOL_MALLOC((size_t)buffer_size_bytes); SOKOL_ASSERT(_saudio.backend.output_buffers[i]); - memset(_saudio.backend.output_buffers[i], 0x0, buffer_size_bytes); + memset(_saudio.backend.output_buffers[i], 0x0, (size_t)buffer_size_bytes); } { const int buffer_size_bytes = _saudio.bytes_per_frame * _saudio.buffer_frames; - _saudio.backend.src_buffer = (float*) SOKOL_MALLOC(buffer_size_bytes); + _saudio.backend.src_buffer = (float*) SOKOL_MALLOC((size_t)buffer_size_bytes); SOKOL_ASSERT(_saudio.backend.src_buffer); - memset(_saudio.backend.src_buffer, 0x0, buffer_size_bytes); + memset(_saudio.backend.src_buffer, 0x0, (size_t)buffer_size_bytes); } - /* Create engine */ const SLEngineOption opts[] = { SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE }; if (slCreateEngine(&_saudio.backend.engine_obj, 1, opts, 0, NULL, NULL ) != SL_RESULT_SUCCESS) { @@ -1739,8 +1984,8 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { /* data format */ SLDataFormat_PCM format; format.formatType = SL_DATAFORMAT_PCM; - format.numChannels = _saudio.num_channels; - format.samplesPerSec = _saudio.sample_rate * 1000; + format.numChannels = (SLuint32)_saudio.num_channels; + format.samplesPerSec = (SLuint32) (_saudio.sample_rate * 1000); format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; format.containerSize = 16; format.endianness = SL_BYTEORDER_LITTLEENDIAN; @@ -1779,8 +2024,8 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { /* begin */ { - const int buffer_size_bytes = sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames; - (*_saudio.backend.player_buffer_queue)->Enqueue(_saudio.backend.player_buffer_queue, _saudio.backend.output_buffers[0], buffer_size_bytes); + const int buffer_size_bytes = (int)sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames; + (*_saudio.backend.player_buffer_queue)->Enqueue(_saudio.backend.player_buffer_queue, _saudio.backend.output_buffers[0], (SLuint32)buffer_size_bytes); _saudio.backend.active_buffer = (_saudio.backend.active_buffer + 1) % SAUDIO_NUM_BUFFERS; (*_saudio.backend.player)->RegisterCallback(_saudio.backend.player, _saudio_opensles_play_cb, NULL); @@ -1801,9 +2046,8 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { } /* extern "C" */ #endif -#else /* dummy backend */ -_SOKOL_PRIVATE bool _saudio_backend_init(void) { return false; }; -_SOKOL_PRIVATE void _saudio_backend_shutdown(void) { }; +#else +#error "unsupported platform" #endif /*=== PUBLIC API FUNCTIONS ===================================================*/ @@ -1822,7 +2066,15 @@ SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) { _saudio.num_channels = _saudio_def(_saudio.desc.num_channels, 1); _saudio_fifo_init_mutex(&_saudio.fifo); if (_saudio_backend_init()) { - SOKOL_ASSERT(0 == (_saudio.buffer_frames % _saudio.packet_frames)); + /* the backend might not support the requested exact buffer size, + make sure the actual buffer size is still a multiple of + the requested packet size + */ + if (0 != (_saudio.buffer_frames % _saudio.packet_frames)) { + SOKOL_LOG("sokol_audio.h: actual backend buffer size isn't multiple of requested packet size"); + _saudio_backend_shutdown(); + return; + } SOKOL_ASSERT(_saudio.bytes_per_frame > 0); _saudio_fifo_init(&_saudio.fifo, _saudio.packet_frames * _saudio.bytes_per_frame, _saudio.num_packets); _saudio.valid = true; @@ -1886,8 +2138,10 @@ SOKOL_API_IMPL int saudio_push(const float* frames, int num_frames) { #undef _saudio_def #undef _saudio_def_flt +#if defined(_SAUDIO_WINDOWS) #ifdef _MSC_VER #pragma warning(pop) #endif +#endif -#endif /* SOKOL_IMPL */ +#endif /* SOKOL_AUDIO_IMPL */ diff --git a/thirdparty/sokol/sokol_gfx.h b/thirdparty/sokol/sokol_gfx.h index 897257be8d..9049ae27de 100644 --- a/thirdparty/sokol/sokol_gfx.h +++ b/thirdparty/sokol/sokol_gfx.h @@ -1,11 +1,17 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMPL) +#define SOKOL_GFX_IMPL +#endif #ifndef SOKOL_GFX_INCLUDED /* sokol_gfx.h -- simple 3D API wrapper Project URL: https://github.com/floooh/sokol + Example code: https://github.com/floooh/sokol-samples + Do this: - #define SOKOL_IMPL + #define SOKOL_IMPL or + #define SOKOL_GFX_IMPL before you include this file in *one* C or C++ file to create the implementation. @@ -33,21 +39,25 @@ Optionally provide the following defines with your own implementations: - SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) - SOKOL_FREE(p) - your own free function (default: free(p)) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) - SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) - SOKOL_API_DECL - public function declaration prefix (default: extern) - SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS) + SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) + SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) + SOKOL_FREE(p) - your own free function (default: free(p)) + SOKOL_LOG(msg) - your own logging function (default: puts(msg)) + SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) + SOKOL_GFX_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_GFX_API_DECL + SOKOL_API_IMPL - public function implementation prefix (default: -) + SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS) + SOKOL_EXTERNAL_GL_LOADER - indicates that you're using your own GL loader, in this case + sokol_gfx.h will not include any platform GL headers and disable + the integrated Win32 GL loader If sokol_gfx.h is compiled as a DLL, define the following before including the declaration or implementation: SOKOL_DLL - On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport) + On Windows, SOKOL_DLL will define SOKOL_GFX_API_DECL as __declspec(dllexport) or __declspec(dllimport) as needed. If you want to compile without deprecated structs and functions, @@ -55,21 +65,11 @@ SOKOL_NO_DEPRECATED - API usage validation macros: - - SOKOL_VALIDATE_BEGIN() - begin a validation block (default:_sg_validate_begin()) - SOKOL_VALIDATE(cond, err) - like assert but for API validation (default: _sg_validate(cond, err)) - SOKOL_VALIDATE_END() - end a validation block, return true if all checks in block passed (default: bool _sg_validate()) - - If you don't want validation errors to be fatal, define SOKOL_VALIDATE_NON_FATAL, - be aware though that this may spam SOKOL_LOG messages. - Optionally define the following to force debug checks and validations even in release mode: SOKOL_DEBUG - by default this is defined if _DEBUG is defined - sokol_gfx DOES NOT: =================== - create a window or the 3D-API context/device, you must do this @@ -80,16 +80,9 @@ on how the window and 3D-API context/device was created - provide a unified shader language, instead 3D-API-specific shader - source-code or shader-bytecode must be provided - - For complete code examples using the various backend 3D-APIs, see: - - https://github.com/floooh/sokol-samples - - For an optional shader-cross-compile solution, see: - - https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md - + source-code or shader-bytecode must be provided (for the "official" + offline shader cross-compiler, see here: + https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md) STEP BY STEP ============ @@ -109,11 +102,17 @@ --- start rendering to the default frame buffer with: - sg_begin_default_pass(const sg_pass_action* actions, int width, int height) + sg_begin_default_pass(const sg_pass_action* action, int width, int height) + + ...or alternatively with: + + sg_begin_default_passf(const sg_pass_action* action, float width, float height) + + ...which takes the framebuffer width and height as float values. --- or start rendering to an offscreen framebuffer with: - sg_begin_pass(sg_pass pass, const sg_pass_action* actions) + sg_begin_pass(sg_pass pass, const sg_pass_action* action) --- set the pipeline state for the next draw call with: @@ -136,10 +135,15 @@ sg_draw(int base_element, int num_elements, int num_instances) - In the case of no instancing: num_instances should be set to 1 and base_element/num_elements are - amounts of vertices. In the case of instancing (meaning num_instances > 1), num elements is the - number of vertices in one instance, while base_element remains unchanged. base_element is the index - of the first vertex to begin drawing from. + The sg_draw() function unifies all the different ways to render primitives + in a single call (indexed vs non-indexed rendering, and instanced vs non-instanced + rendering). In case of indexed rendering, base_element and num_element specify + indices in the currently bound index buffer. In case of non-indexed rendering + base_element and num_elements specify vertices in the currently bound + vertex-buffer(s). To perform instanced rendering, the rendering pipeline + must be setup for instancing (see sg_pipeline_desc below), a separate vertex buffer + containing per-instance data must be bound, and the num_instances parameter + must be > 1. --- finish the current rendering pass with: @@ -165,28 +169,36 @@ sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left) + ...or if you want to specifiy the viewport rectangle with float values: + + sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left) + --- to set a new scissor rect, call: sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) - both sg_apply_viewport() and sg_apply_scissor_rect() must be called + ...or with float values: + + sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left) + + Both sg_apply_viewport() and sg_apply_scissor_rect() must be called inside a rendering pass - beginning a pass will reset the viewport to the size of the framebuffer used - in the new pass, + Note that sg_begin_default_pass() and sg_begin_pass() will reset both the + viewport and scissor rectangles to cover the entire framebuffer. --- to update (overwrite) the content of buffer and image resources, call: - sg_update_buffer(sg_buffer buf, const void* ptr, int num_bytes) - sg_update_image(sg_image img, const sg_image_content* content) + sg_update_buffer(sg_buffer buf, const sg_range* data) + sg_update_image(sg_image img, const sg_image_data* data) Buffers and images to be updated must have been created with SG_USAGE_DYNAMIC or SG_USAGE_STREAM - Only one update per frame is allowed for buffer and image resources. - The rationale is to have a simple countermeasure to avoid the CPU - scribbling over data the GPU is currently using, or the CPU having to - wait for the GPU + Only one update per frame is allowed for buffer and image resources when + using the sg_update_*() functions. The rationale is to have a simple + countermeasure to avoid the CPU scribbling over data the GPU is currently + using, or the CPU having to wait for the GPU Buffer and image updates can be partial, as long as a rendering operation only references the valid (updated) data in the @@ -194,7 +206,7 @@ --- to append a chunk of data to a buffer resource, call: - int sg_append_buffer(sg_buffer buf, const void* ptr, int num_bytes) + int sg_append_buffer(sg_buffer buf, const sg_range* data) The difference to sg_update_buffer() is that sg_append_buffer() can be called multiple times per frame to append new data to the @@ -211,7 +223,7 @@ for (...) { const void* data = ...; const int num_bytes = ...; - int offset = sg_append_buffer(buf, data, num_bytes); + int offset = sg_append_buffer(buf, &(sg_range) { .ptr=data, .size=num_bytes }); bindings.vertex_buffer_offsets[0] = offset; sg_apply_pipeline(pip); sg_apply_bindings(&bindings); @@ -570,16 +582,20 @@ distribution. */ #define SOKOL_GFX_INCLUDED (1) +#include // size_t #include #include -#ifndef SOKOL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) -#define SOKOL_API_DECL __declspec(dllexport) +#if defined(SOKOL_API_DECL) && !defined(SOKOL_GFX_API_DECL) +#define SOKOL_GFX_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_GFX_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GFX_IMPL) +#define SOKOL_GFX_API_DECL __declspec(dllexport) #elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_API_DECL __declspec(dllimport) +#define SOKOL_GFX_API_DECL __declspec(dllimport) #else -#define SOKOL_API_DECL extern +#define SOKOL_GFX_API_DECL extern #endif #endif @@ -587,11 +603,6 @@ extern "C" { #endif -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ -#endif - /* Resource id typedefs: @@ -622,11 +633,31 @@ typedef struct sg_pass { uint32_t id; } sg_pass; typedef struct sg_context { uint32_t id; } sg_context; /* - various compile-time constants - - FIXME: it may make sense to convert some of those into defines so - that the user code can override them. + sg_range is a pointer-size-pair struct used to pass memory blobs into + sokol-gfx. When initialized from a value type (array or struct), you can + use the SG_RANGE() macro to build an sg_range struct. For functions which + take either a sg_range pointer, or a (C++) sg_range reference, use the + SG_RANGE_REF macro as a solution which compiles both in C and C++. */ +typedef struct sg_range { + const void* ptr; + size_t size; +} sg_range; + +// disabling this for every includer isn't great, but the warnings are also quite pointless +#if defined(_MSC_VER) +#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */ +#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */ +#endif +#if defined(__cplusplus) +#define SG_RANGE(x) sg_range{ &x, sizeof(x) } +#define SG_RANGE_REF(x) sg_range{ &x, sizeof(x) } +#else +#define SG_RANGE(x) (sg_range){ &x, sizeof(x) } +#define SG_RANGE_REF(x) &(sg_range){ &x, sizeof(x) } +#endif + +// various compile-time constants enum { SG_INVALID_ID = 0, SG_NUM_SHADER_STAGES = 2, @@ -641,16 +672,22 @@ enum { SG_MAX_TEXTUREARRAY_LAYERS = 128 }; +/* + sg_color + + An RGBA color value. +*/ +typedef struct sg_color { float r, g, b, a; } sg_color; + /* sg_backend The active 3D-API backend, use the function sg_query_backend() to get the currently active backend. - The returned value corresponds with the compile-time define to select - a backend, with the only exception of SOKOL_GLES3: this may - return SG_BACKEND_GLES2 if the backend has to fallback to GLES2 mode - because GLES3 isn't supported. + NOTE that SG_BACKEND_GLES2 will be returned if sokol-gfx was + compiled with SOKOL_GLES3, but the runtime platform doesn't support + GLES3/WebGL2 and sokol-gfx had to fallback to GLES2/WebGL. */ typedef enum sg_backend { SG_BACKEND_GLCORE33, @@ -668,9 +705,10 @@ typedef enum sg_backend { sg_pixel_format sokol_gfx.h basically uses the same pixel formats as WebGPU, since these - are supported on most newer GPUs. GLES2 and WebGL has a much smaller - subset of available pixel formats. Call sg_query_pixelformat() to check - at runtime if a pixel format supports the desired features. + are supported on most newer GPUs. GLES2 and WebGL only supports a much + smaller subset of actually available pixel formats. Call + sg_query_pixelformat() to check at runtime if a pixel format supports the + desired features. A pixelformat name consist of three parts: @@ -794,12 +832,15 @@ typedef enum sg_pixel_format { by sg_query_pixelformat(). */ typedef struct sg_pixelformat_info { - bool sample; /* pixel format can be sampled in shaders */ - bool filter; /* pixel format can be sampled with filtering */ - bool render; /* pixel format can be used as render target */ - bool blend; /* alpha-blending is supported */ - bool msaa; /* pixel format can be used as MSAA render target */ - bool depth; /* pixel format is a depth format */ + bool sample; // pixel format can be sampled in shaders + bool filter; // pixel format can be sampled with filtering + bool render; // pixel format can be used as render target + bool blend; // alpha-blending is supported + bool msaa; // pixel format can be used as MSAA render target + bool depth; // pixel format is a depth format + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[3]; + #endif } sg_pixelformat_info; /* @@ -807,25 +848,30 @@ typedef struct sg_pixelformat_info { returned by sg_query_features() */ typedef struct sg_features { - bool instancing; /* hardware instancing supported */ - bool origin_top_left; /* framebuffer and texture origin is in top left corner */ - bool multiple_render_targets; /* offscreen render passes can have multiple render targets attached */ - bool msaa_render_targets; /* offscreen render passes support MSAA antialiasing */ - bool imagetype_3d; /* creation of SG_IMAGETYPE_3D images is supported */ - bool imagetype_array; /* creation of SG_IMAGETYPE_ARRAY images is supported */ - bool image_clamp_to_border; /* border color and clamp-to-border UV-wrap mode is supported */ + bool instancing; // hardware instancing supported + bool origin_top_left; // framebuffer and texture origin is in top left corner + bool multiple_render_targets; // offscreen render passes can have multiple render targets attached + bool msaa_render_targets; // offscreen render passes support MSAA antialiasing + bool imagetype_3d; // creation of SG_IMAGETYPE_3D images is supported + bool imagetype_array; // creation of SG_IMAGETYPE_ARRAY images is supported + bool image_clamp_to_border; // border color and clamp-to-border UV-wrap mode is supported + bool mrt_independent_blend_state; // multiple-render-target rendering can use per-render-target blend state + bool mrt_independent_write_mask; // multiple-render-target rendering can use per-render-target color write masks + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[3]; + #endif } sg_features; /* Runtime information about resource limits, returned by sg_query_limit() */ typedef struct sg_limits { - uint32_t max_image_size_2d; /* max width/height of SG_IMAGETYPE_2D images */ - uint32_t max_image_size_cube; /* max width/height of SG_IMAGETYPE_CUBE images */ - uint32_t max_image_size_3d; /* max width/height/depth of SG_IMAGETYPE_3D images */ - uint32_t max_image_size_array; /* max width/height pf SG_IMAGETYPE_ARRAY images */ - uint32_t max_image_array_layers; /* max number of layers in SG_IMAGETYPE_ARRAY images */ - uint32_t max_vertex_attrs; /* <= SG_MAX_VERTEX_ATTRIBUTES (only on some GLES2 impls) */ + int max_image_size_2d; // max width/height of SG_IMAGETYPE_2D images + int max_image_size_cube; // max width/height of SG_IMAGETYPE_CUBE images + int max_image_size_3d; // max width/height/depth of SG_IMAGETYPE_3D images + int max_image_size_array; // max width/height of SG_IMAGETYPE_ARRAY images + int max_image_array_layers; // max number of layers in SG_IMAGETYPE_ARRAY images + int max_vertex_attrs; // <= SG_MAX_VERTEX_ATTRIBUTES (only on some GLES2 impls) } sg_limits; /* @@ -1170,7 +1216,7 @@ typedef enum sg_uniform_type { sg_cull_mode The face-culling mode, this is used in the - sg_pipeline_desc.rasterizer.cull_mode member when creating a + sg_pipeline_desc.cull_mode member when creating a pipeline object. The default cull mode is SG_CULLMODE_NONE @@ -1188,7 +1234,7 @@ typedef enum sg_cull_mode { sg_face_winding The vertex-winding rule that determines a front-facing primitive. This - is used in the member sg_pipeline_desc.rasterizer.face_winding + is used in the member sg_pipeline_desc.face_winding when creating a pipeline object. The default winding is SG_FACEWINDING_CW (clockwise) @@ -1208,10 +1254,11 @@ typedef enum sg_face_winding { This is used when creating pipeline objects in the members: sg_pipeline_desc - .depth_stencil - .depth_compare_func - .stencil_front.compare_func - .stencil_back.compare_func + .depth + .compare + .stencil + .front.compare + .back.compar The default compare func for depth- and stencil-tests is SG_COMPAREFUNC_ALWAYS. @@ -1238,12 +1285,12 @@ typedef enum sg_compare_func { object in the members: sg_pipeline_desc - .depth_stencil - .stencil_front + .stencil + .front .fail_op .depth_fail_op .pass_op - .stencil_back + .back .fail_op .depth_fail_op .pass_op @@ -1271,11 +1318,12 @@ typedef enum sg_stencil_op { This is used in the following members when creating a pipeline object: sg_pipeline_desc - .blend - .src_factor_rgb - .dst_factor_rgb - .src_factor_alpha - .dst_factor_alpha + .colors[i] + .blend + .src_factor_rgb + .dst_factor_rgb + .src_factor_alpha + .dst_factor_alpha The default value is SG_BLENDFACTOR_ONE for source factors, and SG_BLENDFACTOR_ZERO for destination factors. @@ -1309,9 +1357,10 @@ typedef enum sg_blend_factor { creating a pipeline object: sg_pipeline_desc - .blend - .op_rgb - .op_alpha + .colors[i] + .blend + .op_rgb + .op_alpha The default value is SG_BLENDOP_ADD. */ @@ -1327,9 +1376,9 @@ typedef enum sg_blend_op { /* sg_color_mask - Selects the color channels when writing a fragment color to the + Selects the active color channels when writing a fragment color to the framebuffer. This is used in the members - sg_pipeline_desc.blend.color_write_mask when creating a pipeline object. + sg_pipeline_desc.colors[i].write_mask when creating a pipeline object. The default colormask is SG_COLORMASK_RGBA (write all colors channels) @@ -1338,14 +1387,23 @@ typedef enum sg_blend_op { should be disabled. */ typedef enum sg_color_mask { - _SG_COLORMASK_DEFAULT = 0, /* value 0 reserved for default-init */ - SG_COLORMASK_NONE = (0x10), /* special value for 'all channels disabled */ - SG_COLORMASK_R = (1<<0), - SG_COLORMASK_G = (1<<1), - SG_COLORMASK_B = (1<<2), - SG_COLORMASK_A = (1<<3), - SG_COLORMASK_RGB = 0x7, - SG_COLORMASK_RGBA = 0xF, + _SG_COLORMASK_DEFAULT = 0, /* value 0 reserved for default-init */ + SG_COLORMASK_NONE = 0x10, /* special value for 'all channels disabled */ + SG_COLORMASK_R = 0x1, + SG_COLORMASK_G = 0x2, + SG_COLORMASK_RG = 0x3, + SG_COLORMASK_B = 0x4, + SG_COLORMASK_RB = 0x5, + SG_COLORMASK_GB = 0x6, + SG_COLORMASK_RGB = 0x7, + SG_COLORMASK_A = 0x8, + SG_COLORMASK_RA = 0x9, + SG_COLORMASK_GA = 0xA, + SG_COLORMASK_RGA = 0xB, + SG_COLORMASK_BA = 0xC, + SG_COLORMASK_RBA = 0xD, + SG_COLORMASK_GBA = 0xE, + SG_COLORMASK_RGBA = 0xF, _SG_COLORMASK_FORCE_U32 = 0x7FFFFFFF } sg_color_mask; @@ -1397,17 +1455,17 @@ typedef enum sg_action { */ typedef struct sg_color_attachment_action { sg_action action; - float val[4]; + sg_color value; } sg_color_attachment_action; typedef struct sg_depth_attachment_action { sg_action action; - float val; + float value; } sg_depth_attachment_action; typedef struct sg_stencil_attachment_action { sg_action action; - uint8_t val; + uint8_t value; } sg_stencil_attachment_action; typedef struct sg_pass_action { @@ -1460,16 +1518,28 @@ typedef struct sg_bindings { The default configuration is: - .size: 0 (this *must* be set to a valid size in bytes) + .size: 0 (*must* be >0 for buffers without data) .type: SG_BUFFERTYPE_VERTEXBUFFER .usage: SG_USAGE_IMMUTABLE - .content 0 + .data.ptr 0 (*must* be valid for immutable buffers) + .data.size 0 (*must* be > 0 for immutable buffers) .label 0 (optional string label for trace hooks) The label will be ignored by sokol_gfx.h, it is only useful when hooking into sg_make_buffer() or sg_init_buffer() via the sg_install_trace_hooks() function. + For immutable buffers which are initialized with initial data, + keep the .size item zero-initialized, and set the size together with the + pointer to the initial data in the .data item. + + For mutable buffers without initial data, keep the .data item + zero-initialized, and set the buffer size in the .size item instead. + + You can also set both size values, but currently both size values must + be identical (this may change in the future when the dynamic resource + management may become more flexible). + ADVANCED TOPIC: Injecting native 3D-API buffers: The following struct members allow to inject your own GL, Metal @@ -1479,7 +1549,7 @@ typedef struct sg_bindings { .mtl_buffers[SG_NUM_INFLIGHT_FRAMES] .d3d11_buffer - You must still provide all other members except the .content member, and + You must still provide all other struct items except the .data item, and these must match the creation parameters of the native buffers you provide. For SG_USAGE_IMMUTABLE, only provide a single native 3D-API buffer, otherwise you need to provide SG_NUM_INFLIGHT_FRAMES buffers @@ -1495,10 +1565,10 @@ typedef struct sg_bindings { */ typedef struct sg_buffer_desc { uint32_t _start_canary; - int size; + size_t size; sg_buffer_type type; sg_usage usage; - const void* content; + sg_range data; const char* label; /* GL specific */ uint32_t gl_buffers[SG_NUM_INFLIGHT_FRAMES]; @@ -1512,39 +1582,21 @@ typedef struct sg_buffer_desc { } sg_buffer_desc; /* - sg_subimage_content + sg_image_data - Pointer to and size of a subimage-surface data, this is - used to describe the initial content of immutable-usage images, - or for updating a dynamic- or stream-usage images. - - For 3D- or array-textures, one sg_subimage_content item - describes an entire mipmap level consisting of all array- or - 3D-slices of the mipmap level. It is only possible to update - an entire mipmap level, not parts of it. + Defines the content of an image through a 2D array of sg_range structs. + The first array dimension is the cubemap face, and the second array + dimension the mipmap level. */ -typedef struct sg_subimage_content { - const void* ptr; /* pointer to subimage data */ - int size; /* size in bytes of pointed-to subimage data */ -} sg_subimage_content; - -/* - sg_image_content - - Defines the content of an image through a 2D array - of sg_subimage_content structs. The first array dimension - is the cubemap face, and the second array dimension the - mipmap level. -*/ -typedef struct sg_image_content { - sg_subimage_content subimage[SG_CUBEFACE_NUM][SG_MAX_MIPMAPS]; -} sg_image_content; +typedef struct sg_image_data { + sg_range subimage[SG_CUBEFACE_NUM][SG_MAX_MIPMAPS]; +} sg_image_data; /* sg_image_desc - Creation parameters for sg_image objects, used in the - sg_make_image() call. + Creation parameters for sg_image objects, used in the sg_make_image() + call. The default configuration is: @@ -1552,11 +1604,11 @@ typedef struct sg_image_content { .render_target: false .width 0 (must be set to >0) .height 0 (must be set to >0) - .depth/.layers: 1 + .num_slices 1 (3D textures: depth; array textures: number of layers) .num_mipmaps: 1 .usage: SG_USAGE_IMMUTABLE .pixel_format: SG_PIXELFORMAT_RGBA8 for textures, or sg_desc.context.color_format for render targets - .sample_count: 1 for textures, or sg_desc.context.sample_count for render target + .sample_count: 1 for textures, or sg_desc.context.sample_count for render targets .min_filter: SG_FILTER_NEAREST .mag_filter: SG_FILTER_NEAREST .wrap_u: SG_WRAP_REPEAT @@ -1566,7 +1618,7 @@ typedef struct sg_image_content { .max_anisotropy 1 (must be 1..16) .min_lod 0.0f .max_lod FLT_MAX - .content an sg_image_content struct to define the initial content + .data an sg_image_data struct to define the initial content .label 0 (optional string label for trace hooks) Q: Why is the default sample_count for render targets identical with the @@ -1580,26 +1632,35 @@ typedef struct sg_image_content { NOTE: - SG_IMAGETYPE_ARRAY and SG_IMAGETYPE_3D are not supported on - WebGL/GLES2, use sg_query_features().imagetype_array and - sg_query_features().imagetype_3d at runtime to check - if array- and 3D-textures are supported. + SG_IMAGETYPE_ARRAY and SG_IMAGETYPE_3D are not supported on WebGL/GLES2, + use sg_query_features().imagetype_array and + sg_query_features().imagetype_3d at runtime to check if array- and + 3D-textures are supported. Images with usage SG_USAGE_IMMUTABLE must be fully initialized by - providing a valid .content member which points to - initialization data. + providing a valid .data member which points to initialization data. ADVANCED TOPIC: Injecting native 3D-API textures: - The following struct members allow to inject your own GL, Metal - or D3D11 textures into sokol_gfx: + The following struct members allow to inject your own GL, Metal or D3D11 + textures into sokol_gfx: .gl_textures[SG_NUM_INFLIGHT_FRAMES] .mtl_textures[SG_NUM_INFLIGHT_FRAMES] .d3d11_texture + .d3d11_shader_resource_view - The same rules apply as for injecting native buffers - (see sg_buffer_desc documentation for more details). + For GL, you can also specify the texture target or leave it empty to use + the default texture target for the image type (GL_TEXTURE_2D for + SG_IMAGETYPE_2D etc) + + For D3D11, you can provide either a D3D11 texture, or a + shader-resource-view, or both. If only a texture is provided, a matching + shader-resource-view will be created. If only a shader-resource-view is + provided, the texture will be looked up from the shader-resource-view. + + The same rules apply as for injecting native buffers (see sg_buffer_desc + documentation for more details). */ typedef struct sg_image_desc { uint32_t _start_canary; @@ -1607,10 +1668,7 @@ typedef struct sg_image_desc { bool render_target; int width; int height; - union { - int depth; - int layers; - }; + int num_slices; int num_mipmaps; sg_usage usage; sg_pixel_format pixel_format; @@ -1624,14 +1682,16 @@ typedef struct sg_image_desc { uint32_t max_anisotropy; float min_lod; float max_lod; - sg_image_content content; + sg_image_data data; const char* label; /* GL specific */ uint32_t gl_textures[SG_NUM_INFLIGHT_FRAMES]; + uint32_t gl_texture_target; /* Metal specific */ const void* mtl_textures[SG_NUM_INFLIGHT_FRAMES]; /* D3D11 specific */ const void* d3d11_texture; + const void* d3d11_shader_resource_view; /* WebGPU specific */ const void* wgpu_texture; uint32_t _end_canary; @@ -1640,8 +1700,8 @@ typedef struct sg_image_desc { /* sg_shader_desc - The structure sg_shader_desc defines all creation parameters - for shader programs, used as input to the sg_make_shader() function: + The structure sg_shader_desc defines all creation parameters for shader + programs, used as input to the sg_make_shader() function: - reflection information for vertex attributes (vertex shader inputs): - vertex attribute name (required for GLES2, optional for GLES3 and GL) @@ -1672,9 +1732,9 @@ typedef struct sg_image_desc { vertex shader stage and "ps_4_0" for the pixel shader stage. */ typedef struct sg_shader_attr_desc { - const char* name; /* GLSL vertex attribute name (only required for GLES2) */ - const char* sem_name; /* HLSL semantic name */ - int sem_index; /* HLSL semantic index */ + const char* name; // GLSL vertex attribute name (only strictly required for GLES2) + const char* sem_name; // HLSL semantic name + int sem_index; // HLSL semantic index } sg_shader_attr_desc; typedef struct sg_shader_uniform_desc { @@ -1684,20 +1744,19 @@ typedef struct sg_shader_uniform_desc { } sg_shader_uniform_desc; typedef struct sg_shader_uniform_block_desc { - int size; + size_t size; sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS]; } sg_shader_uniform_block_desc; typedef struct sg_shader_image_desc { const char* name; - sg_image_type type; /* FIXME: should this be renamed to 'image_type'? */ + sg_image_type image_type; sg_sampler_type sampler_type; } sg_shader_image_desc; typedef struct sg_shader_stage_desc { const char* source; - const uint8_t* byte_code; - int byte_code_size; + sg_range bytecode; const char* entry; const char* d3d11_target; sg_shader_uniform_block_desc uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; @@ -1716,27 +1775,25 @@ typedef struct sg_shader_desc { /* sg_pipeline_desc - The sg_pipeline_desc struct defines all creation parameters - for an sg_pipeline object, used as argument to the - sg_make_pipeline() function: + The sg_pipeline_desc struct defines all creation parameters for an + sg_pipeline object, used as argument to the sg_make_pipeline() function: - the vertex layout for all input vertex buffers - a shader object - the 3D primitive type (points, lines, triangles, ...) - the index type (none, 16- or 32-bit) - - depth-stencil state - - alpha-blending state - - rasterizer state + - all the fixed-function-pipeline state (depth-, stencil-, blend-state, etc...) If the vertex data has no gaps between vertex components, you can omit the .layout.buffers[].stride and layout.attrs[].offset items (leave them - default-initialized to 0), sokol-gfx will then compute the offsets and strides - from the vertex component formats (.layout.attrs[].format). Please note - that ALL vertex attribute offsets must be 0 in order for the + default-initialized to 0), sokol-gfx will then compute the offsets and + strides from the vertex component formats (.layout.attrs[].format). + Please note that ALL vertex attribute offsets must be 0 in order for the automatic offset computation to kick in. The default configuration is as follows: + .shader: 0 (must be initialized with a valid sg_shader id!) .layout: .buffers[]: vertex buffer layouts .stride: 0 (if no stride is given it will be computed) @@ -1746,54 +1803,60 @@ typedef struct sg_shader_desc { .buffer_index 0 the vertex buffer bind slot .offset 0 (offsets can be omitted if the vertex layout has no gaps) .format SG_VERTEXFORMAT_INVALID (must be initialized!) - .shader: 0 (must be initialized with a valid sg_shader id!) - .primitive_type: SG_PRIMITIVETYPE_TRIANGLES - .index_type: SG_INDEXTYPE_NONE - .depth_stencil: - .stencil_front, .stencil_back: - .fail_op: SG_STENCILOP_KEEP - .depth_fail_op: SG_STENCILOP_KEEP - .pass_op: SG_STENCILOP_KEEP - .compare_func SG_COMPAREFUNC_ALWAYS - .depth_compare_func: SG_COMPAREFUNC_ALWAYS - .depth_write_enabled: false - .stencil_enabled: false - .stencil_read_mask: 0 - .stencil_write_mask: 0 - .stencil_ref: 0 - .blend: - .enabled: false - .src_factor_rgb: SG_BLENDFACTOR_ONE - .dst_factor_rgb: SG_BLENDFACTOR_ZERO - .op_rgb: SG_BLENDOP_ADD - .src_factor_alpha: SG_BLENDFACTOR_ONE - .dst_factor_alpha: SG_BLENDFACTOR_ZERO - .op_alpha: SG_BLENDOP_ADD - .color_write_mask: SG_COLORMASK_RGBA - .color_attachment_count 1 - .color_format SG_PIXELFORMAT_RGBA8 - .depth_format SG_PIXELFORMAT_DEPTHSTENCIL - .blend_color: { 0.0f, 0.0f, 0.0f, 0.0f } - .rasterizer: - .alpha_to_coverage_enabled: false - .cull_mode: SG_CULLMODE_NONE - .face_winding: SG_FACEWINDING_CW - .sample_count: sg_desc.context.sample_count - .depth_bias: 0.0f - .depth_bias_slope_scale: 0.0f - .depth_bias_clamp: 0.0f + .depth: + .pixel_format: sg_desc.context.depth_format + .compare: SG_COMPAREFUNC_ALWAYS + .write_enabled: false + .bias: 0.0f + .bias_slope_scale: 0.0f + .bias_clamp: 0.0f + .stencil: + .enabled: false + .front/back: + .compare: SG_COMPAREFUNC_ALWAYS + .depth_fail_op: SG_STENCILOP_KEEP + .pass_op: SG_STENCILOP_KEEP + .compare: SG_COMPAREFUNC_ALWAYS + .read_mask: 0 + .write_mask: 0 + .ref: 0 + .color_count 1 + .colors[0..color_count] + .pixel_format sg_desc.context.color_format + .write_mask: SG_COLORMASK_RGBA + .blend: + .enabled: false + .src_factor_rgb: SG_BLENDFACTOR_ONE + .dst_factor_rgb: SG_BLENDFACTOR_ZERO + .op_rgb: SG_BLENDOP_ADD + .src_factor_alpha: SG_BLENDFACTOR_ONE + .dst_factor_alpha: SG_BLENDFACTOR_ZERO + .op_alpha: SG_BLENDOP_ADD + .primitive_type: SG_PRIMITIVETYPE_TRIANGLES + .index_type: SG_INDEXTYPE_NONE + .cull_mode: SG_CULLMODE_NONE + .face_winding: SG_FACEWINDING_CW + .sample_count: sg_desc.context.sample_count + .blend_color: (sg_color) { 0.0f, 0.0f, 0.0f, 0.0f } + .alpha_to_coverage_enabled: false .label 0 (optional string label for trace hooks) */ typedef struct sg_buffer_layout_desc { int stride; sg_vertex_step step_func; int step_rate; + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[2]; + #endif } sg_buffer_layout_desc; typedef struct sg_vertex_attr_desc { int buffer_index; int offset; sg_vertex_format format; + #if defined(SOKOL_ZIG_BINDINGS) + uint32_t __pad[2]; + #endif } sg_vertex_attr_desc; typedef struct sg_layout_desc { @@ -1801,23 +1864,30 @@ typedef struct sg_layout_desc { sg_vertex_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES]; } sg_layout_desc; -typedef struct sg_stencil_state { +typedef struct sg_stencil_face_state { + sg_compare_func compare; sg_stencil_op fail_op; sg_stencil_op depth_fail_op; sg_stencil_op pass_op; - sg_compare_func compare_func; +} sg_stencil_face_state; + +typedef struct sg_stencil_state { + bool enabled; + sg_stencil_face_state front; + sg_stencil_face_state back; + uint8_t read_mask; + uint8_t write_mask; + uint8_t ref; } sg_stencil_state; -typedef struct sg_depth_stencil_state { - sg_stencil_state stencil_front; - sg_stencil_state stencil_back; - sg_compare_func depth_compare_func; - bool depth_write_enabled; - bool stencil_enabled; - uint8_t stencil_read_mask; - uint8_t stencil_write_mask; - uint8_t stencil_ref; -} sg_depth_stencil_state; +typedef struct sg_depth_state { + sg_pixel_format pixel_format; + sg_compare_func compare; + bool write_enabled; + float bias; + float bias_slope_scale; + float bias_clamp; +} sg_depth_state; typedef struct sg_blend_state { bool enabled; @@ -1827,32 +1897,29 @@ typedef struct sg_blend_state { sg_blend_factor src_factor_alpha; sg_blend_factor dst_factor_alpha; sg_blend_op op_alpha; - uint8_t color_write_mask; - int color_attachment_count; - sg_pixel_format color_format; - sg_pixel_format depth_format; - float blend_color[4]; } sg_blend_state; -typedef struct sg_rasterizer_state { - bool alpha_to_coverage_enabled; - sg_cull_mode cull_mode; - sg_face_winding face_winding; - int sample_count; - float depth_bias; - float depth_bias_slope_scale; - float depth_bias_clamp; -} sg_rasterizer_state; +typedef struct sg_color_state { + sg_pixel_format pixel_format; + sg_color_mask write_mask; + sg_blend_state blend; +} sg_color_state; typedef struct sg_pipeline_desc { uint32_t _start_canary; - sg_layout_desc layout; sg_shader shader; + sg_layout_desc layout; + sg_depth_state depth; + sg_stencil_state stencil; + int color_count; + sg_color_state colors[SG_MAX_COLOR_ATTACHMENTS]; sg_primitive_type primitive_type; sg_index_type index_type; - sg_depth_stencil_state depth_stencil; - sg_blend_state blend; - sg_rasterizer_state rasterizer; + sg_cull_mode cull_mode; + sg_face_winding face_winding; + int sample_count; + sg_color blend_color; + bool alpha_to_coverage_enabled; const char* label; uint32_t _end_canary; } sg_pipeline_desc; @@ -1879,20 +1946,16 @@ typedef struct sg_pipeline_desc { In addition, all color-attachment images must have the same pixel format. */ -typedef struct sg_attachment_desc { +typedef struct sg_pass_attachment_desc { sg_image image; int mip_level; - union { - int face; - int layer; - int slice; - }; -} sg_attachment_desc; + int slice; /* cube texture: face; array texture: layer; 3D texture: slice */ +} sg_pass_attachment_desc; typedef struct sg_pass_desc { uint32_t _start_canary; - sg_attachment_desc color_attachments[SG_MAX_COLOR_ATTACHMENTS]; - sg_attachment_desc depth_stencil_attachment; + sg_pass_attachment_desc color_attachments[SG_MAX_COLOR_ATTACHMENTS]; + sg_pass_attachment_desc depth_stencil_attachment; const char* label; uint32_t _end_canary; } sg_pass_desc; @@ -1922,16 +1985,16 @@ typedef struct sg_trace_hooks { void (*destroy_shader)(sg_shader shd, void* user_data); void (*destroy_pipeline)(sg_pipeline pip, void* user_data); void (*destroy_pass)(sg_pass pass, void* user_data); - void (*update_buffer)(sg_buffer buf, const void* data_ptr, int data_size, void* user_data); - void (*update_image)(sg_image img, const sg_image_content* data, void* user_data); - void (*append_buffer)(sg_buffer buf, const void* data_ptr, int data_size, int result, void* user_data); + void (*update_buffer)(sg_buffer buf, const sg_range* data, void* user_data); + void (*update_image)(sg_image img, const sg_image_data* data, void* user_data); + void (*append_buffer)(sg_buffer buf, const sg_range* data, int result, void* user_data); void (*begin_default_pass)(const sg_pass_action* pass_action, int width, int height, void* user_data); void (*begin_pass)(sg_pass pass, const sg_pass_action* pass_action, void* user_data); void (*apply_viewport)(int x, int y, int width, int height, bool origin_top_left, void* user_data); void (*apply_scissor_rect)(int x, int y, int width, int height, bool origin_top_left, void* user_data); void (*apply_pipeline)(sg_pipeline pip, void* user_data); void (*apply_bindings)(const sg_bindings* bindings, void* user_data); - void (*apply_uniforms)(sg_shader_stage stage, int ub_index, const void* data, int num_bytes, void* user_data); + void (*apply_uniforms)(sg_shader_stage stage, int ub_index, const sg_range* data, void* user_data); void (*draw)(int base_element, int num_elements, int num_instances, void* user_data); void (*end_pass)(void* user_data); void (*commit)(void* user_data); @@ -1940,11 +2003,21 @@ typedef struct sg_trace_hooks { void (*alloc_shader)(sg_shader result, void* user_data); void (*alloc_pipeline)(sg_pipeline result, void* user_data); void (*alloc_pass)(sg_pass result, void* user_data); + void (*dealloc_buffer)(sg_buffer buf_id, void* user_data); + void (*dealloc_image)(sg_image img_id, void* user_data); + void (*dealloc_shader)(sg_shader shd_id, void* user_data); + void (*dealloc_pipeline)(sg_pipeline pip_id, void* user_data); + void (*dealloc_pass)(sg_pass pass_id, void* user_data); void (*init_buffer)(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data); void (*init_image)(sg_image img_id, const sg_image_desc* desc, void* user_data); void (*init_shader)(sg_shader shd_id, const sg_shader_desc* desc, void* user_data); void (*init_pipeline)(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data); void (*init_pass)(sg_pass pass_id, const sg_pass_desc* desc, void* user_data); + void (*uninit_buffer)(sg_buffer buf_id, void* user_data); + void (*uninit_image)(sg_image img_id, void* user_data); + void (*uninit_shader)(sg_shader shd_id, void* user_data); + void (*uninit_pipeline)(sg_pipeline pip_id, void* user_data); + void (*uninit_pass)(sg_pass pass_id, void* user_data); void (*fail_buffer)(sg_buffer buf_id, void* user_data); void (*fail_image)(sg_image img_id, void* user_data); void (*fail_shader)(sg_shader shd_id, void* user_data); @@ -2136,7 +2209,7 @@ typedef struct sg_gl_context_desc { bool force_gles2; } sg_gl_context_desc; -typedef struct sg_mtl_context_desc { +typedef struct sg_metal_context_desc { const void* device; const void* (*renderpass_descriptor_cb)(void); const void* (*renderpass_descriptor_userdata_cb)(void*); @@ -2192,88 +2265,101 @@ typedef struct sg_desc { } sg_desc; /* setup and misc functions */ -SOKOL_API_DECL void sg_setup(const sg_desc* desc); -SOKOL_API_DECL void sg_shutdown(void); -SOKOL_API_DECL bool sg_isvalid(void); -SOKOL_API_DECL void sg_reset_state_cache(void); -SOKOL_API_DECL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks); -SOKOL_API_DECL void sg_push_debug_group(const char* name); -SOKOL_API_DECL void sg_pop_debug_group(void); +SOKOL_GFX_API_DECL void sg_setup(const sg_desc* desc); +SOKOL_GFX_API_DECL void sg_shutdown(void); +SOKOL_GFX_API_DECL bool sg_isvalid(void); +SOKOL_GFX_API_DECL void sg_reset_state_cache(void); +SOKOL_GFX_API_DECL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks); +SOKOL_GFX_API_DECL void sg_push_debug_group(const char* name); +SOKOL_GFX_API_DECL void sg_pop_debug_group(void); /* resource creation, destruction and updating */ -SOKOL_API_DECL sg_buffer sg_make_buffer(const sg_buffer_desc* desc); -SOKOL_API_DECL sg_image sg_make_image(const sg_image_desc* desc); -SOKOL_API_DECL sg_shader sg_make_shader(const sg_shader_desc* desc); -SOKOL_API_DECL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc); -SOKOL_API_DECL sg_pass sg_make_pass(const sg_pass_desc* desc); -SOKOL_API_DECL void sg_destroy_buffer(sg_buffer buf); -SOKOL_API_DECL void sg_destroy_image(sg_image img); -SOKOL_API_DECL void sg_destroy_shader(sg_shader shd); -SOKOL_API_DECL void sg_destroy_pipeline(sg_pipeline pip); -SOKOL_API_DECL void sg_destroy_pass(sg_pass pass); -SOKOL_API_DECL void sg_update_buffer(sg_buffer buf, const void* data_ptr, int data_size); -SOKOL_API_DECL void sg_update_image(sg_image img, const sg_image_content* data); -SOKOL_API_DECL int sg_append_buffer(sg_buffer buf, const void* data_ptr, int data_size); -SOKOL_API_DECL bool sg_query_buffer_overflow(sg_buffer buf); +SOKOL_GFX_API_DECL sg_buffer sg_make_buffer(const sg_buffer_desc* desc); +SOKOL_GFX_API_DECL sg_image sg_make_image(const sg_image_desc* desc); +SOKOL_GFX_API_DECL sg_shader sg_make_shader(const sg_shader_desc* desc); +SOKOL_GFX_API_DECL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc); +SOKOL_GFX_API_DECL sg_pass sg_make_pass(const sg_pass_desc* desc); +SOKOL_GFX_API_DECL void sg_destroy_buffer(sg_buffer buf); +SOKOL_GFX_API_DECL void sg_destroy_image(sg_image img); +SOKOL_GFX_API_DECL void sg_destroy_shader(sg_shader shd); +SOKOL_GFX_API_DECL void sg_destroy_pipeline(sg_pipeline pip); +SOKOL_GFX_API_DECL void sg_destroy_pass(sg_pass pass); +SOKOL_GFX_API_DECL void sg_update_buffer(sg_buffer buf, const sg_range* data); +SOKOL_GFX_API_DECL void sg_update_image(sg_image img, const sg_image_data* data); +SOKOL_GFX_API_DECL int sg_append_buffer(sg_buffer buf, const sg_range* data); +SOKOL_GFX_API_DECL bool sg_query_buffer_overflow(sg_buffer buf); /* rendering functions */ -SOKOL_API_DECL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height); -SOKOL_API_DECL void sg_begin_pass(sg_pass pass, const sg_pass_action* pass_action); -SOKOL_API_DECL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left); -SOKOL_API_DECL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left); -SOKOL_API_DECL void sg_apply_pipeline(sg_pipeline pip); -SOKOL_API_DECL void sg_apply_bindings(const sg_bindings* bindings); -SOKOL_API_DECL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const void* data, int num_bytes); -SOKOL_API_DECL void sg_draw(int base_element, int num_elements, int num_instances); -SOKOL_API_DECL void sg_end_pass(void); -SOKOL_API_DECL void sg_commit(void); +SOKOL_GFX_API_DECL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height); +SOKOL_GFX_API_DECL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height); +SOKOL_GFX_API_DECL void sg_begin_pass(sg_pass pass, const sg_pass_action* pass_action); +SOKOL_GFX_API_DECL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left); +SOKOL_GFX_API_DECL void sg_apply_pipeline(sg_pipeline pip); +SOKOL_GFX_API_DECL void sg_apply_bindings(const sg_bindings* bindings); +SOKOL_GFX_API_DECL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data); +SOKOL_GFX_API_DECL void sg_draw(int base_element, int num_elements, int num_instances); +SOKOL_GFX_API_DECL void sg_end_pass(void); +SOKOL_GFX_API_DECL void sg_commit(void); /* getting information */ -SOKOL_API_DECL sg_desc sg_query_desc(void); -SOKOL_API_DECL sg_backend sg_query_backend(void); -SOKOL_API_DECL sg_features sg_query_features(void); -SOKOL_API_DECL sg_limits sg_query_limits(void); -SOKOL_API_DECL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt); +SOKOL_GFX_API_DECL sg_desc sg_query_desc(void); +SOKOL_GFX_API_DECL sg_backend sg_query_backend(void); +SOKOL_GFX_API_DECL sg_features sg_query_features(void); +SOKOL_GFX_API_DECL sg_limits sg_query_limits(void); +SOKOL_GFX_API_DECL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt); /* get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID) */ -SOKOL_API_DECL sg_resource_state sg_query_buffer_state(sg_buffer buf); -SOKOL_API_DECL sg_resource_state sg_query_image_state(sg_image img); -SOKOL_API_DECL sg_resource_state sg_query_shader_state(sg_shader shd); -SOKOL_API_DECL sg_resource_state sg_query_pipeline_state(sg_pipeline pip); -SOKOL_API_DECL sg_resource_state sg_query_pass_state(sg_pass pass); +SOKOL_GFX_API_DECL sg_resource_state sg_query_buffer_state(sg_buffer buf); +SOKOL_GFX_API_DECL sg_resource_state sg_query_image_state(sg_image img); +SOKOL_GFX_API_DECL sg_resource_state sg_query_shader_state(sg_shader shd); +SOKOL_GFX_API_DECL sg_resource_state sg_query_pipeline_state(sg_pipeline pip); +SOKOL_GFX_API_DECL sg_resource_state sg_query_pass_state(sg_pass pass); /* get runtime information about a resource */ -SOKOL_API_DECL sg_buffer_info sg_query_buffer_info(sg_buffer buf); -SOKOL_API_DECL sg_image_info sg_query_image_info(sg_image img); -SOKOL_API_DECL sg_shader_info sg_query_shader_info(sg_shader shd); -SOKOL_API_DECL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip); -SOKOL_API_DECL sg_pass_info sg_query_pass_info(sg_pass pass); +SOKOL_GFX_API_DECL sg_buffer_info sg_query_buffer_info(sg_buffer buf); +SOKOL_GFX_API_DECL sg_image_info sg_query_image_info(sg_image img); +SOKOL_GFX_API_DECL sg_shader_info sg_query_shader_info(sg_shader shd); +SOKOL_GFX_API_DECL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip); +SOKOL_GFX_API_DECL sg_pass_info sg_query_pass_info(sg_pass pass); /* get resource creation desc struct with their default values replaced */ -SOKOL_API_DECL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc); -SOKOL_API_DECL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc); -SOKOL_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc); -SOKOL_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc); -SOKOL_API_DECL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc); +SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc); +SOKOL_GFX_API_DECL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc); +SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc); +SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc); +SOKOL_GFX_API_DECL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc); /* separate resource allocation and initialization (for async setup) */ -SOKOL_API_DECL sg_buffer sg_alloc_buffer(void); -SOKOL_API_DECL sg_image sg_alloc_image(void); -SOKOL_API_DECL sg_shader sg_alloc_shader(void); -SOKOL_API_DECL sg_pipeline sg_alloc_pipeline(void); -SOKOL_API_DECL sg_pass sg_alloc_pass(void); -SOKOL_API_DECL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc); -SOKOL_API_DECL void sg_init_image(sg_image img_id, const sg_image_desc* desc); -SOKOL_API_DECL void sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc); -SOKOL_API_DECL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc); -SOKOL_API_DECL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc); -SOKOL_API_DECL void sg_fail_buffer(sg_buffer buf_id); -SOKOL_API_DECL void sg_fail_image(sg_image img_id); -SOKOL_API_DECL void sg_fail_shader(sg_shader shd_id); -SOKOL_API_DECL void sg_fail_pipeline(sg_pipeline pip_id); -SOKOL_API_DECL void sg_fail_pass(sg_pass pass_id); +SOKOL_GFX_API_DECL sg_buffer sg_alloc_buffer(void); +SOKOL_GFX_API_DECL sg_image sg_alloc_image(void); +SOKOL_GFX_API_DECL sg_shader sg_alloc_shader(void); +SOKOL_GFX_API_DECL sg_pipeline sg_alloc_pipeline(void); +SOKOL_GFX_API_DECL sg_pass sg_alloc_pass(void); +SOKOL_GFX_API_DECL void sg_dealloc_buffer(sg_buffer buf_id); +SOKOL_GFX_API_DECL void sg_dealloc_image(sg_image img_id); +SOKOL_GFX_API_DECL void sg_dealloc_shader(sg_shader shd_id); +SOKOL_GFX_API_DECL void sg_dealloc_pipeline(sg_pipeline pip_id); +SOKOL_GFX_API_DECL void sg_dealloc_pass(sg_pass pass_id); +SOKOL_GFX_API_DECL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc); +SOKOL_GFX_API_DECL void sg_init_image(sg_image img_id, const sg_image_desc* desc); +SOKOL_GFX_API_DECL void sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc); +SOKOL_GFX_API_DECL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc); +SOKOL_GFX_API_DECL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc); +SOKOL_GFX_API_DECL bool sg_uninit_buffer(sg_buffer buf_id); +SOKOL_GFX_API_DECL bool sg_uninit_image(sg_image img_id); +SOKOL_GFX_API_DECL bool sg_uninit_shader(sg_shader shd_id); +SOKOL_GFX_API_DECL bool sg_uninit_pipeline(sg_pipeline pip_id); +SOKOL_GFX_API_DECL bool sg_uninit_pass(sg_pass pass_id); +SOKOL_GFX_API_DECL void sg_fail_buffer(sg_buffer buf_id); +SOKOL_GFX_API_DECL void sg_fail_image(sg_image img_id); +SOKOL_GFX_API_DECL void sg_fail_shader(sg_shader shd_id); +SOKOL_GFX_API_DECL void sg_fail_pipeline(sg_pipeline pip_id); +SOKOL_GFX_API_DECL void sg_fail_pass(sg_pass pass_id); /* rendering contexts (optional) */ -SOKOL_API_DECL sg_context sg_setup_context(void); -SOKOL_API_DECL void sg_activate_context(sg_context ctx_id); -SOKOL_API_DECL void sg_discard_context(sg_context ctx_id); +SOKOL_GFX_API_DECL sg_context sg_setup_context(void); +SOKOL_GFX_API_DECL void sg_activate_context(sg_context ctx_id); +SOKOL_GFX_API_DECL void sg_discard_context(sg_context ctx_id); /* Backend-specific helper functions, these may come in handy for mixing sokol-gfx rendering with 'native backend' rendering functions. @@ -2281,12 +2367,15 @@ SOKOL_API_DECL void sg_discard_context(sg_context ctx_id); This group of functions will be expanded as needed. */ -/* Metal: return __bridge-casted MTLRenderCommandEncoder in current pass (or zero if outside pass) */ -SOKOL_API_DECL const void* sg_mtl_render_command_encoder(void); +/* D3D11: return ID3D11Device */ +SOKOL_GFX_API_DECL const void* sg_d3d11_device(void); + +/* Metal: return __bridge-casted MTLDevice */ +SOKOL_GFX_API_DECL const void* sg_mtl_device(void); + +/* Metal: return __bridge-casted MTLRenderCommandEncoder in current pass (or zero if outside pass) */ +SOKOL_GFX_API_DECL const void* sg_mtl_render_command_encoder(void); -#ifdef _MSC_VER -#pragma warning(pop) -#endif #ifdef __cplusplus } /* extern "C" */ @@ -2298,11 +2387,13 @@ inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image( inline sg_shader sg_make_shader(const sg_shader_desc& desc) { return sg_make_shader(&desc); } inline sg_pipeline sg_make_pipeline(const sg_pipeline_desc& desc) { return sg_make_pipeline(&desc); } inline sg_pass sg_make_pass(const sg_pass_desc& desc) { return sg_make_pass(&desc); } -inline void sg_update_image(sg_image img, const sg_image_content& data) { return sg_update_image(img, &data); } +inline void sg_update_image(sg_image img, const sg_image_data& data) { return sg_update_image(img, &data); } inline void sg_begin_default_pass(const sg_pass_action& pass_action, int width, int height) { return sg_begin_default_pass(&pass_action, width, height); } +inline void sg_begin_default_passf(const sg_pass_action& pass_action, float width, float height) { return sg_begin_default_passf(&pass_action, width, height); } inline void sg_begin_pass(sg_pass pass, const sg_pass_action& pass_action) { return sg_begin_pass(pass, &pass_action); } inline void sg_apply_bindings(const sg_bindings& bindings) { return sg_apply_bindings(&bindings); } +inline void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range& data) { return sg_apply_uniforms(stage, ub_index, &data); } inline sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc& desc) { return sg_query_buffer_defaults(&desc); } inline sg_image_desc sg_query_image_defaults(const sg_image_desc& desc) { return sg_query_image_defaults(&desc); } @@ -2316,11 +2407,13 @@ inline void sg_init_shader(sg_shader shd_id, const sg_shader_desc& desc) { retur inline void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc& desc) { return sg_init_pipeline(pip_id, &desc); } inline void sg_init_pass(sg_pass pass_id, const sg_pass_desc& desc) { return sg_init_pass(pass_id, &desc); } +inline void sg_update_buffer(sg_buffer buf_id, const sg_range& data) { return sg_update_buffer(buf_id, &data); } +inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_append_buffer(buf_id, &data); } #endif #endif // SOKOL_GFX_INCLUDED /*--- IMPLEMENTATION ---------------------------------------------------------*/ -#ifdef SOKOL_IMPL +#ifdef SOKOL_GFX_IMPL #define SOKOL_GFX_IMPL_INCLUDED (1) #if !(defined(SOKOL_GLCORE33)||defined(SOKOL_GLES2)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND)) @@ -2409,14 +2502,337 @@ inline void sg_init_pass(sg_pass pass_id, const sg_pass_desc& desc) { return sg_ #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ #pragma warning(disable:4115) /* named type definition in parentheses */ #pragma warning(disable:4505) /* unreferenced local function has been removed */ +#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union (needed by d3d11.h) */ +#pragma warning(disable:4054) /* 'type cast': from function pointer */ +#pragma warning(disable:4055) /* 'type cast': from data pointer */ #endif -#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) +#if defined(SOKOL_D3D11) + #ifndef D3D11_NO_HELPERS + #define D3D11_NO_HELPERS + #endif + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include + #include + #ifdef _MSC_VER + #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) + #pragma comment (lib, "WindowsApp") + #else + #pragma comment (lib, "kernel32") + #pragma comment (lib, "user32") + #pragma comment (lib, "dxgi") + #pragma comment (lib, "d3d11") + #pragma comment (lib, "dxguid") + #endif + #endif +#elif defined(SOKOL_METAL) + // see https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting + #if !defined(__cplusplus) + #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) + #error "sokol_gfx.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" + #endif + #endif + #include + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + #define _SG_TARGET_MACOS (1) + #else + #define _SG_TARGET_IOS (1) + #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR + #define _SG_TARGET_IOS_SIMULATOR (1) + #endif + #endif + #import +#elif defined(SOKOL_WGPU) + #if defined(__EMSCRIPTEN__) + #include + #else + #include + #endif +#elif defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) #define _SOKOL_ANY_GL (1) + // include platform specific GL headers (or on Win32: use an embedded GL loader) + #if !defined(SOKOL_EXTERNAL_GL_LOADER) + #if defined(_WIN32) + #if defined(SOKOL_GLCORE33) && !defined(SOKOL_EXTERNAL_GL_LOADER) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include + #define _SOKOL_USE_WIN32_GL_LOADER (1) + #pragma comment (lib, "kernel32") // GetProcAddress() + #endif + #elif defined(__APPLE__) + #include + #ifndef GL_SILENCE_DEPRECATION + #define GL_SILENCE_DEPRECATION + #endif + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + #include + #else + #include + #include + #endif + #elif defined(__EMSCRIPTEN__) || defined(__ANDROID__) + #if defined(SOKOL_GLES3) + #include + #elif defined(SOKOL_GLES2) + #ifndef GL_EXT_PROTOTYPES + #define GL_GLEXT_PROTOTYPES + #endif + #include + #include + #endif + #elif defined(__linux__) || defined(__unix__) + #define GL_GLEXT_PROTOTYPES + #include + #endif + #endif + + // optional GL loader definitions (only on Win32) + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + #define __gl_h_ 1 + #define __gl32_h_ 1 + #define __gl31_h_ 1 + #define __GL_H__ 1 + #define __glext_h_ 1 + #define __GLEXT_H_ 1 + #define __gltypes_h_ 1 + #define __glcorearb_h_ 1 + #define __gl_glcorearb_h_ 1 + #define GL_APIENTRY APIENTRY + + typedef unsigned int GLenum; + typedef unsigned int GLuint; + typedef int GLsizei; + typedef char GLchar; + typedef ptrdiff_t GLintptr; + typedef ptrdiff_t GLsizeiptr; + typedef double GLclampd; + typedef unsigned short GLushort; + typedef unsigned char GLubyte; + typedef unsigned char GLboolean; + typedef uint64_t GLuint64; + typedef double GLdouble; + typedef unsigned short GLhalf; + typedef float GLclampf; + typedef unsigned int GLbitfield; + typedef signed char GLbyte; + typedef short GLshort; + typedef void GLvoid; + typedef int64_t GLint64; + typedef float GLfloat; + typedef struct __GLsync * GLsync; + typedef int GLint; + #define GL_INT_2_10_10_10_REV 0x8D9F + #define GL_R32F 0x822E + #define GL_PROGRAM_POINT_SIZE 0x8642 + #define GL_STENCIL_ATTACHMENT 0x8D20 + #define GL_DEPTH_ATTACHMENT 0x8D00 + #define GL_COLOR_ATTACHMENT2 0x8CE2 + #define GL_COLOR_ATTACHMENT0 0x8CE0 + #define GL_R16F 0x822D + #define GL_COLOR_ATTACHMENT22 0x8CF6 + #define GL_DRAW_FRAMEBUFFER 0x8CA9 + #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 + #define GL_NUM_EXTENSIONS 0x821D + #define GL_INFO_LOG_LENGTH 0x8B84 + #define GL_VERTEX_SHADER 0x8B31 + #define GL_INCR 0x1E02 + #define GL_DYNAMIC_DRAW 0x88E8 + #define GL_STATIC_DRAW 0x88E4 + #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 + #define GL_TEXTURE_CUBE_MAP 0x8513 + #define GL_FUNC_SUBTRACT 0x800A + #define GL_FUNC_REVERSE_SUBTRACT 0x800B + #define GL_CONSTANT_COLOR 0x8001 + #define GL_DECR_WRAP 0x8508 + #define GL_R8 0x8229 + #define GL_LINEAR_MIPMAP_LINEAR 0x2703 + #define GL_ELEMENT_ARRAY_BUFFER 0x8893 + #define GL_SHORT 0x1402 + #define GL_DEPTH_TEST 0x0B71 + #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 + #define GL_LINK_STATUS 0x8B82 + #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 + #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E + #define GL_RGBA16F 0x881A + #define GL_CONSTANT_ALPHA 0x8003 + #define GL_READ_FRAMEBUFFER 0x8CA8 + #define GL_TEXTURE0 0x84C0 + #define GL_TEXTURE_MIN_LOD 0x813A + #define GL_CLAMP_TO_EDGE 0x812F + #define GL_UNSIGNED_SHORT_5_6_5 0x8363 + #define GL_TEXTURE_WRAP_R 0x8072 + #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 + #define GL_NEAREST_MIPMAP_NEAREST 0x2700 + #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 + #define GL_SRC_ALPHA_SATURATE 0x0308 + #define GL_STREAM_DRAW 0x88E0 + #define GL_ONE 1 + #define GL_NEAREST_MIPMAP_LINEAR 0x2702 + #define GL_RGB10_A2 0x8059 + #define GL_RGBA8 0x8058 + #define GL_COLOR_ATTACHMENT1 0x8CE1 + #define GL_RGBA4 0x8056 + #define GL_RGB8 0x8051 + #define GL_ARRAY_BUFFER 0x8892 + #define GL_STENCIL 0x1802 + #define GL_TEXTURE_2D 0x0DE1 + #define GL_DEPTH 0x1801 + #define GL_FRONT 0x0404 + #define GL_STENCIL_BUFFER_BIT 0x00000400 + #define GL_REPEAT 0x2901 + #define GL_RGBA 0x1908 + #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 + #define GL_DECR 0x1E03 + #define GL_FRAGMENT_SHADER 0x8B30 + #define GL_FLOAT 0x1406 + #define GL_TEXTURE_MAX_LOD 0x813B + #define GL_DEPTH_COMPONENT 0x1902 + #define GL_ONE_MINUS_DST_ALPHA 0x0305 + #define GL_COLOR 0x1800 + #define GL_TEXTURE_2D_ARRAY 0x8C1A + #define GL_TRIANGLES 0x0004 + #define GL_UNSIGNED_BYTE 0x1401 + #define GL_TEXTURE_MAG_FILTER 0x2800 + #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 + #define GL_NONE 0 + #define GL_SRC_COLOR 0x0300 + #define GL_BYTE 0x1400 + #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A + #define GL_LINE_STRIP 0x0003 + #define GL_TEXTURE_3D 0x806F + #define GL_CW 0x0900 + #define GL_LINEAR 0x2601 + #define GL_RENDERBUFFER 0x8D41 + #define GL_GEQUAL 0x0206 + #define GL_COLOR_BUFFER_BIT 0x00004000 + #define GL_RGBA32F 0x8814 + #define GL_BLEND 0x0BE2 + #define GL_ONE_MINUS_SRC_ALPHA 0x0303 + #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 + #define GL_TEXTURE_WRAP_T 0x2803 + #define GL_TEXTURE_WRAP_S 0x2802 + #define GL_TEXTURE_MIN_FILTER 0x2801 + #define GL_LINEAR_MIPMAP_NEAREST 0x2701 + #define GL_EXTENSIONS 0x1F03 + #define GL_NO_ERROR 0 + #define GL_REPLACE 0x1E01 + #define GL_KEEP 0x1E00 + #define GL_CCW 0x0901 + #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 + #define GL_RGB 0x1907 + #define GL_TRIANGLE_STRIP 0x0005 + #define GL_FALSE 0 + #define GL_ZERO 0 + #define GL_CULL_FACE 0x0B44 + #define GL_INVERT 0x150A + #define GL_INT 0x1404 + #define GL_UNSIGNED_INT 0x1405 + #define GL_UNSIGNED_SHORT 0x1403 + #define GL_NEAREST 0x2600 + #define GL_SCISSOR_TEST 0x0C11 + #define GL_LEQUAL 0x0203 + #define GL_STENCIL_TEST 0x0B90 + #define GL_DITHER 0x0BD0 + #define GL_DEPTH_COMPONENT16 0x81A5 + #define GL_EQUAL 0x0202 + #define GL_FRAMEBUFFER 0x8D40 + #define GL_RGB5 0x8050 + #define GL_LINES 0x0001 + #define GL_DEPTH_BUFFER_BIT 0x00000100 + #define GL_SRC_ALPHA 0x0302 + #define GL_INCR_WRAP 0x8507 + #define GL_LESS 0x0201 + #define GL_MULTISAMPLE 0x809D + #define GL_FRAMEBUFFER_BINDING 0x8CA6 + #define GL_BACK 0x0405 + #define GL_ALWAYS 0x0207 + #define GL_FUNC_ADD 0x8006 + #define GL_ONE_MINUS_DST_COLOR 0x0307 + #define GL_NOTEQUAL 0x0205 + #define GL_DST_COLOR 0x0306 + #define GL_COMPILE_STATUS 0x8B81 + #define GL_RED 0x1903 + #define GL_COLOR_ATTACHMENT3 0x8CE3 + #define GL_DST_ALPHA 0x0304 + #define GL_RGB5_A1 0x8057 + #define GL_GREATER 0x0204 + #define GL_POLYGON_OFFSET_FILL 0x8037 + #define GL_TRUE 1 + #define GL_NEVER 0x0200 + #define GL_POINTS 0x0000 + #define GL_ONE_MINUS_SRC_COLOR 0x0301 + #define GL_MIRRORED_REPEAT 0x8370 + #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D + #define GL_R11F_G11F_B10F 0x8C3A + #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B + #define GL_RGBA32UI 0x8D70 + #define GL_RGB32UI 0x8D71 + #define GL_RGBA16UI 0x8D76 + #define GL_RGB16UI 0x8D77 + #define GL_RGBA8UI 0x8D7C + #define GL_RGB8UI 0x8D7D + #define GL_RGBA32I 0x8D82 + #define GL_RGB32I 0x8D83 + #define GL_RGBA16I 0x8D88 + #define GL_RGB16I 0x8D89 + #define GL_RGBA8I 0x8D8E + #define GL_RGB8I 0x8D8F + #define GL_RED_INTEGER 0x8D94 + #define GL_RG 0x8227 + #define GL_RG_INTEGER 0x8228 + #define GL_R8 0x8229 + #define GL_R16 0x822A + #define GL_RG8 0x822B + #define GL_RG16 0x822C + #define GL_R16F 0x822D + #define GL_R32F 0x822E + #define GL_RG16F 0x822F + #define GL_RG32F 0x8230 + #define GL_R8I 0x8231 + #define GL_R8UI 0x8232 + #define GL_R16I 0x8233 + #define GL_R16UI 0x8234 + #define GL_R32I 0x8235 + #define GL_R32UI 0x8236 + #define GL_RG8I 0x8237 + #define GL_RG8UI 0x8238 + #define GL_RG16I 0x8239 + #define GL_RG16UI 0x823A + #define GL_RG32I 0x823B + #define GL_RG32UI 0x823C + #define GL_RGBA_INTEGER 0x8D99 + #define GL_R8_SNORM 0x8F94 + #define GL_RG8_SNORM 0x8F95 + #define GL_RGB8_SNORM 0x8F96 + #define GL_RGBA8_SNORM 0x8F97 + #define GL_R16_SNORM 0x8F98 + #define GL_RG16_SNORM 0x8F99 + #define GL_RGB16_SNORM 0x8F9A + #define GL_RGBA16_SNORM 0x8F9B + #define GL_RGBA16 0x805B + #define GL_MAX_TEXTURE_SIZE 0x0D33 + #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C + #define GL_MAX_3D_TEXTURE_SIZE 0x8073 + #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF + #define GL_MAX_VERTEX_ATTRIBS 0x8869 + #define GL_CLAMP_TO_BORDER 0x812D + #define GL_TEXTURE_BORDER_COLOR 0x1004 + #define GL_CURRENT_PROGRAM 0x8B8D + #endif + #ifndef GL_UNSIGNED_INT_2_10_10_10_REV #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #endif @@ -2503,72 +2919,26 @@ inline void sg_init_pass(sg_pass pass_id, const sg_pass_desc& desc) { return sg_ #endif #ifdef SOKOL_GLES2 - # ifdef GL_ANGLE_instanced_arrays - # define SOKOL_INSTANCING_ENABLED - # define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedANGLE(mode, first, count, instancecount) - # define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedANGLE(mode, count, type, indices, instancecount) - # define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorANGLE(index, divisor) - # elif defined(GL_EXT_draw_instanced) && defined(GL_EXT_instanced_arrays) - # define SOKOL_INSTANCING_ENABLED - # define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedEXT(mode, first, count, instancecount) - # define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedEXT(mode, count, type, indices, instancecount) - # define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorEXT(index, divisor) - # else - # define SOKOL_GLES2_INSTANCING_ERROR "Select GL_ANGLE_instanced_arrays or (GL_EXT_draw_instanced & GL_EXT_instanced_arrays) to enable instancing in GLES2" - # define glDrawArraysInstanced(mode, first, count, instancecount) SOKOL_ASSERT(0 && SOKOL_GLES2_INSTANCING_ERROR) - # define glDrawElementsInstanced(mode, count, type, indices, instancecount) SOKOL_ASSERT(0 && SOKOL_GLES2_INSTANCING_ERROR) - # define glVertexAttribDivisor(index, divisor) SOKOL_ASSERT(0 && SOKOL_GLES2_INSTANCING_ERROR) - # endif + #ifdef GL_ANGLE_instanced_arrays + #define _SOKOL_GL_INSTANCING_ENABLED + #define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedANGLE(mode, first, count, instancecount) + #define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedANGLE(mode, count, type, indices, instancecount) + #define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorANGLE(index, divisor) + #elif defined(GL_EXT_draw_instanced) && defined(GL_EXT_instanced_arrays) + #define _SOKOL_GL_INSTANCING_ENABLED + #define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedEXT(mode, first, count, instancecount) + #define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedEXT(mode, count, type, indices, instancecount) + #define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorEXT(index, divisor) + #else + #define _SOKOL_GLES2_INSTANCING_ERROR "Select GL_ANGLE_instanced_arrays or (GL_EXT_draw_instanced & GL_EXT_instanced_arrays) to enable instancing in GLES2" + #define glDrawArraysInstanced(mode, first, count, instancecount) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR) + #define glDrawElementsInstanced(mode, count, type, indices, instancecount) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR) + #define glVertexAttribDivisor(index, divisor) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR) + #endif #else - # define SOKOL_INSTANCING_ENABLED + #define _SOKOL_GL_INSTANCING_ENABLED #endif #define _SG_GL_CHECK_ERROR() { SOKOL_ASSERT(glGetError() == GL_NO_ERROR); } - -#elif defined(SOKOL_D3D11) - #ifndef D3D11_NO_HELPERS - #define D3D11_NO_HELPERS - #endif - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #ifndef NOMINMAX - #define NOMINMAX - #endif - #include - #include - #ifdef _MSC_VER - #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) - #pragma comment (lib, "WindowsApp") - #else - #pragma comment (lib, "user32") - #pragma comment (lib, "dxgi") - #pragma comment (lib, "d3d11") - #pragma comment (lib, "dxguid") - #endif - #endif -#elif defined(SOKOL_METAL) - // see https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting - #if !defined(__cplusplus) - #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields) - #error "sokol_app.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)" - #endif - #endif - #include - #import - #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE - #define _SG_TARGET_MACOS (1) - #else - #define _SG_TARGET_IOS (1) - #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR - #define _SG_TARGET_IOS_SIMULATOR (1) - #endif - #endif -#elif defined(SOKOL_WGPU) - #if defined(__EMSCRIPTEN__) - #include - #else - #include - #endif #endif /*=== COMMON BACKEND STUFF ===================================================*/ @@ -2623,7 +2993,7 @@ typedef struct { } _sg_buffer_common_t; _SOKOL_PRIVATE void _sg_buffer_common_init(_sg_buffer_common_t* cmn, const sg_buffer_desc* desc) { - cmn->size = desc->size; + cmn->size = (int)desc->size; cmn->append_pos = 0; cmn->append_overflow = false; cmn->type = desc->type; @@ -2639,7 +3009,7 @@ typedef struct { bool render_target; int width; int height; - int depth; + int num_slices; int num_mipmaps; sg_usage usage; sg_pixel_format pixel_format; @@ -2661,7 +3031,7 @@ _SOKOL_PRIVATE void _sg_image_common_init(_sg_image_common_t* cmn, const sg_imag cmn->render_target = desc->render_target; cmn->width = desc->width; cmn->height = desc->height; - cmn->depth = desc->depth; + cmn->num_slices = desc->num_slices; cmn->num_mipmaps = desc->num_mipmaps; cmn->usage = desc->usage; cmn->pixel_format = desc->pixel_format; @@ -2679,11 +3049,11 @@ _SOKOL_PRIVATE void _sg_image_common_init(_sg_image_common_t* cmn, const sg_imag } typedef struct { - int size; + size_t size; } _sg_uniform_block_t; typedef struct { - sg_image_type type; + sg_image_type image_type; sg_sampler_type sampler_type; } _sg_shader_image_t; @@ -2714,10 +3084,10 @@ _SOKOL_PRIVATE void _sg_shader_common_init(_sg_shader_common_t* cmn, const sg_sh SOKOL_ASSERT(stage->num_images == 0); for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - if (img_desc->type == _SG_IMAGETYPE_DEFAULT) { + if (img_desc->image_type == _SG_IMAGETYPE_DEFAULT) { break; } - stage->images[img_index].type = img_desc->type; + stage->images[img_index].image_type = img_desc->image_type; stage->images[img_index].sampler_type = img_desc->sampler_type; stage->num_images++; } @@ -2729,48 +3099,49 @@ typedef struct { sg_index_type index_type; bool vertex_layout_valid[SG_MAX_SHADERSTAGE_BUFFERS]; int color_attachment_count; - sg_pixel_format color_format; + sg_pixel_format color_formats[SG_MAX_COLOR_ATTACHMENTS]; sg_pixel_format depth_format; int sample_count; float depth_bias; float depth_bias_slope_scale; float depth_bias_clamp; - float blend_color[4]; + sg_color blend_color; } _sg_pipeline_common_t; _SOKOL_PRIVATE void _sg_pipeline_common_init(_sg_pipeline_common_t* cmn, const sg_pipeline_desc* desc) { + SOKOL_ASSERT(desc->color_count < SG_MAX_COLOR_ATTACHMENTS); cmn->shader_id = desc->shader; cmn->index_type = desc->index_type; for (int i = 0; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) { cmn->vertex_layout_valid[i] = false; } - cmn->color_attachment_count = desc->blend.color_attachment_count; - cmn->color_format = desc->blend.color_format; - cmn->depth_format = desc->blend.depth_format; - cmn->sample_count = desc->rasterizer.sample_count; - cmn->depth_bias = desc->rasterizer.depth_bias; - cmn->depth_bias_slope_scale = desc->rasterizer.depth_bias_slope_scale; - cmn->depth_bias_clamp = desc->rasterizer.depth_bias_clamp; - for (int i = 0; i < 4; i++) { - cmn->blend_color[i] = desc->blend.blend_color[i]; + cmn->color_attachment_count = desc->color_count; + for (int i = 0; i < cmn->color_attachment_count; i++) { + cmn->color_formats[i] = desc->colors[i].pixel_format; } + cmn->depth_format = desc->depth.pixel_format; + cmn->sample_count = desc->sample_count; + cmn->depth_bias = desc->depth.bias; + cmn->depth_bias_slope_scale = desc->depth.bias_slope_scale; + cmn->depth_bias_clamp = desc->depth.bias_clamp; + cmn->blend_color = desc->blend_color; } typedef struct { sg_image image_id; int mip_level; int slice; -} _sg_attachment_common_t; +} _sg_pass_attachment_common_t; typedef struct { int num_color_atts; - _sg_attachment_common_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; - _sg_attachment_common_t ds_att; + _sg_pass_attachment_common_t color_atts[SG_MAX_COLOR_ATTACHMENTS]; + _sg_pass_attachment_common_t ds_att; } _sg_pass_common_t; _SOKOL_PRIVATE void _sg_pass_common_init(_sg_pass_common_t* cmn, const sg_pass_desc* desc) { - const sg_attachment_desc* att_desc; - _sg_attachment_common_t* att; + const sg_pass_attachment_desc* att_desc; + _sg_pass_attachment_common_t* att; for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { att_desc = &desc->color_attachments[i]; if (att_desc->image.id != SG_INVALID_ID) { @@ -2819,8 +3190,9 @@ _SOKOL_PRIVATE void _sg_smpcache_init(_sg_sampler_cache_t* cache, int capacity) SOKOL_ASSERT(cache && (capacity > 0)); memset(cache, 0, sizeof(_sg_sampler_cache_t)); cache->capacity = capacity; - const int size = cache->capacity * sizeof(_sg_sampler_cache_item_t); + const size_t size = (size_t)cache->capacity * sizeof(_sg_sampler_cache_item_t); cache->items = (_sg_sampler_cache_item_t*) SOKOL_MALLOC(size); + SOKOL_ASSERT(cache->items); memset(cache->items, 0, size); } @@ -2885,7 +3257,7 @@ _SOKOL_PRIVATE void _sg_smpcache_add_item(_sg_sampler_cache_t* cache, const sg_i _SOKOL_PRIVATE uintptr_t _sg_smpcache_sampler(_sg_sampler_cache_t* cache, int item_index) { SOKOL_ASSERT(cache && cache->items); - SOKOL_ASSERT((item_index >= 0) && (item_index < cache->num_items)); + SOKOL_ASSERT(item_index < cache->num_items); return cache->items[item_index].sampler_handle; } @@ -2929,7 +3301,7 @@ typedef struct { } dmy; } _sg_dummy_pass_t; typedef _sg_dummy_pass_t _sg_pass_t; -typedef _sg_attachment_common_t _sg_attachment_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; @@ -3013,10 +3385,15 @@ typedef struct { _sg_shader_t* shader; struct { _sg_gl_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; - sg_depth_stencil_state depth_stencil; + sg_depth_state depth; + sg_stencil_state stencil; sg_primitive_type primitive_type; sg_blend_state blend; - sg_rasterizer_state rast; + sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS]; + sg_cull_mode cull_mode; + sg_face_winding face_winding; + int sample_count; + bool alpha_to_coverage_enabled; } gl; } _sg_gl_pipeline_t; typedef _sg_gl_pipeline_t _sg_pipeline_t; @@ -3036,7 +3413,7 @@ typedef struct { } gl; } _sg_gl_pass_t; typedef _sg_gl_pass_t _sg_pass_t; -typedef _sg_attachment_common_t _sg_attachment_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; @@ -3058,10 +3435,16 @@ typedef struct { } _sg_gl_texture_bind_slot; typedef struct { - sg_depth_stencil_state ds; + sg_depth_state depth; + sg_stencil_state stencil; sg_blend_state blend; - sg_rasterizer_state rast; + sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS]; + sg_cull_mode cull_mode; + sg_face_winding face_winding; bool polygon_offset_enabled; + int sample_count; + sg_color blend_color; + bool alpha_to_coverage_enabled; _sg_gl_cache_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; GLuint vertex_buffer; GLuint index_buffer; @@ -3091,6 +3474,9 @@ typedef struct { bool ext_anisotropic; GLint max_anisotropy; GLint max_combined_texture_image_units; + #if _SOKOL_USE_WIN32_GL_LOADER + HINSTANCE opengl32_dll; + #endif } _sg_gl_backend_t; /*== D3D11 BACKEND DECLARATIONS ==============================================*/ @@ -3138,7 +3524,7 @@ typedef struct { ID3D11VertexShader* vs; ID3D11PixelShader* fs; void* vs_blob; - int vs_blob_length; + size_t vs_blob_length; } d3d11; } _sg_d3d11_shader_t; typedef _sg_d3d11_shader_t _sg_shader_t; @@ -3179,7 +3565,7 @@ typedef struct { } d3d11; } _sg_d3d11_pass_t; typedef _sg_d3d11_pass_t _sg_pass_t; -typedef _sg_attachment_common_t _sg_attachment_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; @@ -3234,16 +3620,16 @@ typedef struct { typedef struct { uint32_t frame_index; /* frame index at which it is safe to release this resource */ - uint32_t slot_index; + int slot_index; } _sg_mtl_release_item_t; typedef struct { NSMutableArray* pool; - uint32_t num_slots; - uint32_t free_queue_top; - uint32_t* free_queue; - uint32_t release_queue_front; - uint32_t release_queue_back; + int num_slots; + int free_queue_top; + int* free_queue; + int release_queue_front; + int release_queue_back; _sg_mtl_release_item_t* release_queue; } _sg_mtl_idpool_t; @@ -3251,7 +3637,7 @@ typedef struct { _sg_slot_t slot; _sg_buffer_common_t cmn; struct { - uint32_t buf[SG_NUM_INFLIGHT_FRAMES]; /* index into _sg_mtl_pool */ + int buf[SG_NUM_INFLIGHT_FRAMES]; /* index into _sg_mtl_pool */ } mtl; } _sg_mtl_buffer_t; typedef _sg_mtl_buffer_t _sg_buffer_t; @@ -3260,17 +3646,17 @@ typedef struct { _sg_slot_t slot; _sg_image_common_t cmn; struct { - uint32_t tex[SG_NUM_INFLIGHT_FRAMES]; - uint32_t depth_tex; - uint32_t msaa_tex; - uint32_t sampler_state; + int tex[SG_NUM_INFLIGHT_FRAMES]; + int depth_tex; + int msaa_tex; + int sampler_state; } mtl; } _sg_mtl_image_t; typedef _sg_mtl_image_t _sg_image_t; typedef struct { - uint32_t mtl_lib; - uint32_t mtl_func; + int mtl_lib; + int mtl_func; } _sg_mtl_shader_stage_t; typedef struct { @@ -3288,13 +3674,13 @@ typedef struct { _sg_shader_t* shader; struct { MTLPrimitiveType prim_type; - NSUInteger index_size; + int index_size; MTLIndexType index_type; MTLCullMode cull_mode; MTLWinding winding; uint32_t stencil_ref; - uint32_t rps; - uint32_t dss; + int rps; + int dss; } mtl; } _sg_mtl_pipeline_t; typedef _sg_mtl_pipeline_t _sg_pipeline_t; @@ -3312,7 +3698,7 @@ typedef struct { } mtl; } _sg_mtl_pass_t; typedef _sg_mtl_pass_t _sg_pass_t; -typedef _sg_attachment_common_t _sg_attachment_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; @@ -3344,8 +3730,8 @@ typedef struct { void* user_data; uint32_t frame_index; uint32_t cur_frame_rotate_index; - uint32_t ub_size; - uint32_t cur_ub_offset; + int ub_size; + int cur_ub_offset; uint8_t* cur_ub_base_ptr; bool in_pass; bool pass_valid; @@ -3433,7 +3819,7 @@ typedef struct { } wgpu; } _sg_wgpu_pass_t; typedef _sg_wgpu_pass_t _sg_pass_t; -typedef _sg_attachment_common_t _sg_attachment_t; +typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; @@ -3529,8 +3915,9 @@ typedef enum { /* buffer creation */ _SG_VALIDATE_BUFFERDESC_CANARY, _SG_VALIDATE_BUFFERDESC_SIZE, - _SG_VALIDATE_BUFFERDESC_CONTENT, - _SG_VALIDATE_BUFFERDESC_NO_CONTENT, + _SG_VALIDATE_BUFFERDESC_DATA, + _SG_VALIDATE_BUFFERDESC_DATA_SIZE, + _SG_VALIDATE_BUFFERDESC_NO_DATA, /* image creation */ _SG_VALIDATE_IMAGEDESC_CANARY, @@ -3541,9 +3928,9 @@ typedef enum { _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT, _SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT, _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE, - _SG_VALIDATE_IMAGEDESC_RT_NO_CONTENT, - _SG_VALIDATE_IMAGEDESC_CONTENT, - _SG_VALIDATE_IMAGEDESC_NO_CONTENT, + _SG_VALIDATE_IMAGEDESC_RT_NO_DATA, + _SG_VALIDATE_IMAGEDESC_DATA, + _SG_VALIDATE_IMAGEDESC_NO_DATA, /* shader creation */ _SG_VALIDATE_SHADERDESC_CANARY, @@ -3580,7 +3967,6 @@ typedef enum { _SG_VALIDATE_PASSDESC_LAYER, _SG_VALIDATE_PASSDESC_SLICE, _SG_VALIDATE_PASSDESC_IMAGE_NO_RT, - _SG_VALIDATE_PASSDESC_COLOR_PIXELFORMATS, _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT, _SG_VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT, _SG_VALIDATE_PASSDESC_IMAGE_SIZES, @@ -3850,13 +4236,15 @@ _SOKOL_PRIVATE int _sg_pixelformat_bytesize(sg_pixel_format fmt) { } } -#define _sg_roundup(val, round_to) (((val)+((round_to)-1))&~((round_to)-1)) +_SOKOL_PRIVATE int _sg_roundup(int val, int round_to) { + return (val+(round_to-1)) & ~(round_to-1); +} /* return row pitch for an image see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp */ -_SOKOL_PRIVATE uint32_t _sg_row_pitch(sg_pixel_format fmt, uint32_t width, uint32_t row_align) { - uint32_t pitch; +_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) { + int pitch; switch (fmt) { case SG_PIXELFORMAT_BC1_RGBA: case SG_PIXELFORMAT_BC4_R: @@ -3945,7 +4333,7 @@ _SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) { /* return pitch of a 2D subimage / texture slice see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp */ -_SOKOL_PRIVATE uint32_t _sg_surface_pitch(sg_pixel_format fmt, uint32_t width, uint32_t height, uint32_t row_align) { +_SOKOL_PRIVATE int _sg_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align) { int num_rows = _sg_num_rows(fmt, height); return num_rows * _sg_row_pitch(fmt, width, row_align); } @@ -4019,19 +4407,19 @@ _SOKOL_PRIVATE void _sg_resolve_default_pass_action(const sg_pass_action* from, for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { if (to->colors[i].action == _SG_ACTION_DEFAULT) { to->colors[i].action = SG_ACTION_CLEAR; - to->colors[i].val[0] = SG_DEFAULT_CLEAR_RED; - to->colors[i].val[1] = SG_DEFAULT_CLEAR_GREEN; - to->colors[i].val[2] = SG_DEFAULT_CLEAR_BLUE; - to->colors[i].val[3] = SG_DEFAULT_CLEAR_ALPHA; + to->colors[i].value.r = SG_DEFAULT_CLEAR_RED; + to->colors[i].value.g = SG_DEFAULT_CLEAR_GREEN; + to->colors[i].value.b = SG_DEFAULT_CLEAR_BLUE; + to->colors[i].value.a = SG_DEFAULT_CLEAR_ALPHA; } } if (to->depth.action == _SG_ACTION_DEFAULT) { to->depth.action = SG_ACTION_CLEAR; - to->depth.val = SG_DEFAULT_CLEAR_DEPTH; + to->depth.value = SG_DEFAULT_CLEAR_DEPTH; } if (to->stencil.action == _SG_ACTION_DEFAULT) { to->stencil.action = SG_ACTION_CLEAR; - to->stencil.val = SG_DEFAULT_CLEAR_STENCIL; + to->stencil.value = SG_DEFAULT_CLEAR_STENCIL; } } @@ -4119,7 +4507,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pipeline(_sg_pipeline_t* pip, if (a_desc->format == SG_VERTEXFORMAT_INVALID) { break; } - SOKOL_ASSERT((a_desc->buffer_index >= 0) && (a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS)); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; } return SG_RESOURCESTATE_VALID; @@ -4136,7 +4524,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pass(_sg_pass_t* pass, _sg_ima _sg_pass_common_init(&pass->cmn, desc); - const sg_attachment_desc* att_desc; + const sg_pass_attachment_desc* att_desc; for (int i = 0; i < pass->cmn.num_color_atts; i++) { att_desc = &desc->color_attachments[i]; SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); @@ -4229,14 +4617,10 @@ _SOKOL_PRIVATE void _sg_dummy_apply_bindings( _SOKOL_UNUSED(fs_imgs); _SOKOL_UNUSED(num_fs_imgs); } -_SOKOL_PRIVATE void _sg_dummy_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { - SOKOL_ASSERT(data && (num_bytes > 0)); - SOKOL_ASSERT((stage_index >= 0) && ((int)stage_index < SG_NUM_SHADER_STAGES)); - SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); +_SOKOL_PRIVATE void _sg_dummy_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { _SOKOL_UNUSED(stage_index); _SOKOL_UNUSED(ub_index); _SOKOL_UNUSED(data); - _SOKOL_UNUSED(num_bytes); } _SOKOL_PRIVATE void _sg_dummy_draw(int base_element, int num_elements, int num_instances) { @@ -4245,29 +4629,27 @@ _SOKOL_PRIVATE void _sg_dummy_draw(int base_element, int num_elements, int num_i _SOKOL_UNUSED(num_instances); } -_SOKOL_PRIVATE void _sg_dummy_update_buffer(_sg_buffer_t* buf, const void* data, uint32_t data_size) { - SOKOL_ASSERT(buf && data && (data_size > 0)); +_SOKOL_PRIVATE void _sg_dummy_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); _SOKOL_UNUSED(data); - _SOKOL_UNUSED(data_size); if (++buf->cmn.active_slot >= buf->cmn.num_slots) { buf->cmn.active_slot = 0; } } -_SOKOL_PRIVATE uint32_t _sg_dummy_append_buffer(_sg_buffer_t* buf, const void* data, uint32_t data_size, bool new_frame) { - SOKOL_ASSERT(buf && data && (data_size > 0)); +_SOKOL_PRIVATE int _sg_dummy_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); _SOKOL_UNUSED(data); - _SOKOL_UNUSED(data_size); if (new_frame) { if (++buf->cmn.active_slot >= buf->cmn.num_slots) { buf->cmn.active_slot = 0; } } /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */ - return _sg_roundup(data_size, 4); + return _sg_roundup((int)data->size, 4); } -_SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_content* data) { +_SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(img && data); _SOKOL_UNUSED(data); if (++img->cmn.active_slot >= img->cmn.num_slots) { @@ -4278,6 +4660,148 @@ _SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_cont /*== GL BACKEND ==============================================================*/ #elif defined(_SOKOL_ANY_GL) +/*=== OPTIONAL GL LOADER FOR WIN32 ===========================================*/ +#if defined(_SOKOL_USE_WIN32_GL_LOADER) + +// X Macro list of GL function names and signatures +#define _SG_GL_FUNCS \ + _SG_XMACRO(glBindVertexArray, void, (GLuint array)) \ + _SG_XMACRO(glFramebufferTextureLayer, void, (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)) \ + _SG_XMACRO(glGenFramebuffers, void, (GLsizei n, GLuint * framebuffers)) \ + _SG_XMACRO(glBindFramebuffer, void, (GLenum target, GLuint framebuffer)) \ + _SG_XMACRO(glBindRenderbuffer, void, (GLenum target, GLuint renderbuffer)) \ + _SG_XMACRO(glGetStringi, const GLubyte *, (GLenum name, GLuint index)) \ + _SG_XMACRO(glClearBufferfi, void, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) \ + _SG_XMACRO(glClearBufferfv, void, (GLenum buffer, GLint drawbuffer, const GLfloat * value)) \ + _SG_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \ + _SG_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \ + _SG_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \ + _SG_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glUseProgram, void, (GLuint program)) \ + _SG_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \ + _SG_XMACRO(glLinkProgram, void, (GLuint program)) \ + _SG_XMACRO(glGetUniformLocation, GLint, (GLuint program, const GLchar * name)) \ + _SG_XMACRO(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint * params)) \ + _SG_XMACRO(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ + _SG_XMACRO(glGetAttribLocation, GLint, (GLuint program, const GLchar * name)) \ + _SG_XMACRO(glDisableVertexAttribArray, void, (GLuint index)) \ + _SG_XMACRO(glDeleteShader, void, (GLuint shader)) \ + _SG_XMACRO(glDeleteProgram, void, (GLuint program)) \ + _SG_XMACRO(glCompileShader, void, (GLuint shader)) \ + _SG_XMACRO(glStencilFuncSeparate, void, (GLenum face, GLenum func, GLint ref, GLuint mask)) \ + _SG_XMACRO(glStencilOpSeparate, void, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) \ + _SG_XMACRO(glRenderbufferStorageMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glDrawBuffers, void, (GLsizei n, const GLenum * bufs)) \ + _SG_XMACRO(glVertexAttribDivisor, void, (GLuint index, GLuint divisor)) \ + _SG_XMACRO(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void * data)) \ + _SG_XMACRO(glGenBuffers, void, (GLsizei n, GLuint * buffers)) \ + _SG_XMACRO(glCheckFramebufferStatus, GLenum, (GLenum target)) \ + _SG_XMACRO(glFramebufferRenderbuffer, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \ + _SG_XMACRO(glCompressedTexImage2D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data)) \ + _SG_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \ + _SG_XMACRO(glActiveTexture, void, (GLenum texture)) \ + _SG_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \ + _SG_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \ + _SG_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \ + _SG_XMACRO(glDrawElements, void, (GLenum mode, GLsizei count, GLenum type, const void * indices)) \ + _SG_XMACRO(glDeleteFramebuffers, void, (GLsizei n, const GLuint * framebuffers)) \ + _SG_XMACRO(glBlendEquationSeparate, void, (GLenum modeRGB, GLenum modeAlpha)) \ + _SG_XMACRO(glDeleteTextures, void, (GLsizei n, const GLuint * textures)) \ + _SG_XMACRO(glGetProgramiv, void, (GLuint program, GLenum pname, GLint * params)) \ + _SG_XMACRO(glBindTexture, void, (GLenum target, GLuint texture)) \ + _SG_XMACRO(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glCreateShader, GLuint, (GLenum type)) \ + _SG_XMACRO(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glClearDepth, void, (GLdouble depth)) \ + _SG_XMACRO(glFramebufferTexture2D, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) \ + _SG_XMACRO(glCreateProgram, GLuint, (void)) \ + _SG_XMACRO(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glDeleteBuffers, void, (GLsizei n, const GLuint * buffers)) \ + _SG_XMACRO(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) \ + _SG_XMACRO(glDrawElementsInstanced, void, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) \ + _SG_XMACRO(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)) \ + _SG_XMACRO(glUniform1i, void, (GLint location, GLint v0)) \ + _SG_XMACRO(glDisable, void, (GLenum cap)) \ + _SG_XMACRO(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ + _SG_XMACRO(glColorMaski, void, (GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \ + _SG_XMACRO(glBindBuffer, void, (GLenum target, GLuint buffer)) \ + _SG_XMACRO(glDeleteVertexArrays, void, (GLsizei n, const GLuint * arrays)) \ + _SG_XMACRO(glDepthMask, void, (GLboolean flag)) \ + _SG_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \ + _SG_XMACRO(glClearStencil, void, (GLint s)) \ + _SG_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \ + _SG_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \ + _SG_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \ + _SG_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \ + _SG_XMACRO(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) \ + _SG_XMACRO(glGetIntegerv, void, (GLenum pname, GLint * data)) \ + _SG_XMACRO(glEnable, void, (GLenum cap)) \ + _SG_XMACRO(glBlitFramebuffer, void, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) \ + _SG_XMACRO(glStencilMask, void, (GLuint mask)) \ + _SG_XMACRO(glAttachShader, void, (GLuint program, GLuint shader)) \ + _SG_XMACRO(glGetError, GLenum, (void)) \ + _SG_XMACRO(glClearColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ + _SG_XMACRO(glBlendColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \ + _SG_XMACRO(glTexParameterf, void, (GLenum target, GLenum pname, GLfloat param)) \ + _SG_XMACRO(glTexParameterfv, void, (GLenum target, GLenum pname, GLfloat* params)) \ + _SG_XMACRO(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \ + _SG_XMACRO(glDepthFunc, void, (GLenum func)) \ + _SG_XMACRO(glStencilOp , void, (GLenum fail, GLenum zfail, GLenum zpass)) \ + _SG_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \ + _SG_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \ + _SG_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \ + _SG_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \ + _SG_XMACRO(glReadBuffer, void, (GLenum src)) \ + _SG_XMACRO(glClear, void, (GLbitfield mask)) \ + _SG_XMACRO(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)) \ + _SG_XMACRO(glGenVertexArrays, void, (GLsizei n, GLuint * arrays)) \ + _SG_XMACRO(glFrontFace, void, (GLenum mode)) \ + _SG_XMACRO(glCullFace, void, (GLenum mode)) + +// generate GL function pointer typedefs +#define _SG_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args; +_SG_GL_FUNCS +#undef _SG_XMACRO + +// generate GL function pointers +#define _SG_XMACRO(name, ret, args) static PFN_ ## name name; +_SG_GL_FUNCS +#undef _SG_XMACRO + +// helper function to lookup GL functions in GL DLL +typedef PROC (WINAPI * _sg_wglGetProcAddress)(LPCSTR); +_SOKOL_PRIVATE void* _sg_gl_getprocaddr(const char* name, _sg_wglGetProcAddress wgl_getprocaddress) { + void* proc_addr = (void*) wgl_getprocaddress(name); + if (0 == proc_addr) { + proc_addr = (void*) GetProcAddress(_sg.gl.opengl32_dll, name); + } + SOKOL_ASSERT(proc_addr); + return proc_addr; +} + +// populate GL function pointers +_SOKOL_PRIVATE void _sg_gl_load_opengl(void) { + SOKOL_ASSERT(0 == _sg.gl.opengl32_dll); + _sg.gl.opengl32_dll = LoadLibraryA("opengl32.dll"); + SOKOL_ASSERT(_sg.gl.opengl32_dll); + _sg_wglGetProcAddress wgl_getprocaddress = (_sg_wglGetProcAddress) GetProcAddress(_sg.gl.opengl32_dll, "wglGetProcAddress"); + SOKOL_ASSERT(wgl_getprocaddress); + #define _SG_XMACRO(name, ret, args) name = (PFN_ ## name) _sg_gl_getprocaddr(#name, wgl_getprocaddress); + _SG_GL_FUNCS + #undef _SG_XMACRO +} + +_SOKOL_PRIVATE void _sg_gl_unload_opengl(void) { + SOKOL_ASSERT(_sg.gl.opengl32_dll); + FreeLibrary(_sg.gl.opengl32_dll); + _sg.gl.opengl32_dll = 0; +} +#endif // _SOKOL_USE_WIN32_GL_LOADER + /*-- type translation --------------------------------------------------------*/ _SOKOL_PRIVATE GLenum _sg_gl_buffer_target(sg_buffer_type t) { switch (t) { @@ -4753,44 +5277,6 @@ _SOKOL_PRIVATE GLenum _sg_gl_depth_attachment_format(sg_pixel_format fmt) { } } -_SOKOL_PRIVATE void _sg_gl_init_attr(_sg_gl_attr_t* attr) { - attr->vb_index = -1; - attr->divisor = -1; -} - -_SOKOL_PRIVATE void _sg_gl_init_stencil_state(sg_stencil_state* s) { - SOKOL_ASSERT(s); - s->fail_op = SG_STENCILOP_KEEP; - s->depth_fail_op = SG_STENCILOP_KEEP; - s->pass_op = SG_STENCILOP_KEEP; - s->compare_func = SG_COMPAREFUNC_ALWAYS; -} - -_SOKOL_PRIVATE void _sg_gl_init_depth_stencil_state(sg_depth_stencil_state* s) { - SOKOL_ASSERT(s); - _sg_gl_init_stencil_state(&s->stencil_front); - _sg_gl_init_stencil_state(&s->stencil_back); - s->depth_compare_func = SG_COMPAREFUNC_ALWAYS; -} - -_SOKOL_PRIVATE void _sg_gl_init_blend_state(sg_blend_state* s) { - SOKOL_ASSERT(s); - s->src_factor_rgb = SG_BLENDFACTOR_ONE; - s->dst_factor_rgb = SG_BLENDFACTOR_ZERO; - s->op_rgb = SG_BLENDOP_ADD; - s->src_factor_alpha = SG_BLENDFACTOR_ONE; - s->dst_factor_alpha = SG_BLENDFACTOR_ZERO; - s->op_alpha = SG_BLENDOP_ADD; - s->color_write_mask = SG_COLORMASK_RGBA; -} - -_SOKOL_PRIVATE void _sg_gl_init_rasterizer_state(sg_rasterizer_state* s) { - SOKOL_ASSERT(s); - s->cull_mode = SG_CULLMODE_NONE; - s->face_winding = SG_FACEWINDING_CW; - s->sample_count = 1; -} - /* see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml */ _SOKOL_PRIVATE void _sg_gl_init_pixelformats(bool has_bgra) { #if !defined(SOKOL_GLES2) @@ -5065,6 +5551,8 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_glcore33(void) { _sg.features.imagetype_3d = true; _sg.features.imagetype_array = true; _sg.features.image_clamp_to_border = true; + _sg.features.mrt_independent_blend_state = false; + _sg.features.mrt_independent_write_mask = true; /* scan extensions */ bool has_s3tc = false; /* BC1..BC3 */ @@ -5075,7 +5563,7 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_glcore33(void) { GLint num_ext = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext); for (int i = 0; i < num_ext; i++) { - const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, i); + const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); if (ext) { if (strstr(ext, "_texture_compression_s3tc")) { has_s3tc = true; @@ -5140,6 +5628,8 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { _sg.features.imagetype_3d = true; _sg.features.imagetype_array = true; _sg.features.image_clamp_to_border = false; + _sg.features.mrt_independent_blend_state = false; + _sg.features.mrt_independent_write_mask = false; bool has_s3tc = false; /* BC1..BC3 */ bool has_rgtc = false; /* BC4 and BC5 */ @@ -5157,7 +5647,7 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { GLint num_ext = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext); for (int i = 0; i < num_ext; i++) { - const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, i); + const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); if (ext) { if (strstr(ext, "_texture_compression_s3tc")) { has_s3tc = true; @@ -5198,6 +5688,13 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { } } + /* on WebGL2, color_buffer_float also includes 16-bit formats + see: https://developer.mozilla.org/en-US/docs/Web/API/EXT_color_buffer_float + */ + #if defined(__EMSCRIPTEN__) + has_colorbuffer_half_float = has_colorbuffer_float; + #endif + /* limits */ _sg_gl_init_limits(); @@ -5260,7 +5757,7 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles2(void) { } _sg.features.origin_top_left = false; - #if defined(SOKOL_INSTANCING_ENABLED) + #if defined(_SOKOL_GL_INSTANCING_ENABLED) _sg.features.instancing = has_instancing; #endif _sg.features.multiple_render_targets = false; @@ -5268,6 +5765,8 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles2(void) { _sg.features.imagetype_3d = false; _sg.features.imagetype_array = false; _sg.features.image_clamp_to_border = false; + _sg.features.mrt_independent_blend_state = false; + _sg.features.mrt_independent_write_mask = false; /* limits */ _sg_gl_init_limits(); @@ -5393,7 +5892,7 @@ _SOKOL_PRIVATE void _sg_gl_cache_active_texture(GLenum texture) { _SOKOL_PRIVATE void _sg_gl_cache_clear_texture_bindings(bool force) { for (int i = 0; (i < SG_MAX_SHADERSTAGE_IMAGES) && (i < _sg.gl.max_combined_texture_image_units); i++) { if (force || (_sg.gl.cache.textures[i].texture != 0)) { - GLenum gl_texture_slot = GL_TEXTURE0 + i; + GLenum gl_texture_slot = (GLenum) (GL_TEXTURE0 + i); glActiveTexture(gl_texture_slot); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); @@ -5421,7 +5920,7 @@ _SOKOL_PRIVATE void _sg_gl_cache_bind_texture(int slot_index, GLenum target, GLu } _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.textures[slot_index]; if ((slot->target != target) || (slot->texture != texture)) { - _sg_gl_cache_active_texture(GL_TEXTURE0 + slot_index); + _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + slot_index)); /* if the target has changed, clear the previous binding on that target */ if ((target != slot->target) && (slot->target != 0)) { glBindTexture(slot->target, 0); @@ -5457,7 +5956,7 @@ _SOKOL_PRIVATE void _sg_gl_cache_invalidate_texture(GLuint tex) { for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.textures[i]; if (tex == slot->texture) { - _sg_gl_cache_active_texture(GL_TEXTURE0 + i); + _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + i)); glBindTexture(slot->target, 0); slot->target = 0; slot->texture = 0; @@ -5491,9 +5990,11 @@ _SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { _SG_GL_CHECK_ERROR(); _sg_gl_cache_clear_texture_bindings(true); _SG_GL_CHECK_ERROR(); - for (uint32_t i = 0; i < _sg.limits.max_vertex_attrs; i++) { - _sg_gl_init_attr(&_sg.gl.cache.attrs[i].gl_attr); - glDisableVertexAttribArray(i); + for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { + _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; + attr->vb_index = -1; + attr->divisor = -1; + glDisableVertexAttribArray((GLuint)i); _SG_GL_CHECK_ERROR(); } _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; @@ -5502,8 +6003,16 @@ _SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); _SG_GL_CHECK_ERROR(); - /* depth-stencil state */ - _sg_gl_init_depth_stencil_state(&_sg.gl.cache.ds); + /* depth and stencil state */ + _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); glDepthMask(GL_FALSE); @@ -5513,15 +6022,25 @@ _SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { glStencilMask(0); /* blend state */ - _sg_gl_init_blend_state(&_sg.gl.cache.blend); + _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; + _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; glDisable(GL_BLEND); glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); - /* rasterizer state */ - _sg_gl_init_rasterizer_state(&_sg.gl.cache.rast); + /* standalone state */ + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; + } + _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; + _sg.gl.cache.face_winding = SG_FACEWINDING_CW; + _sg.gl.cache.sample_count = 1; + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glPolygonOffset(0.0f, 0.0f); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_CULL_FACE); @@ -5548,6 +6067,10 @@ _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { _sg.gl.gles2 = false; #endif + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + _sg_gl_load_opengl(); + #endif + /* clear initial GL error state */ #if defined(SOKOL_DEBUG) while (glGetError() != GL_NO_ERROR); @@ -5569,6 +6092,9 @@ _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { _SOKOL_PRIVATE void _sg_gl_discard_backend(void) { SOKOL_ASSERT(_sg.gl.valid); _sg.gl.valid = false; + #if defined(_SOKOL_USE_WIN32_GL_LOADER) + _sg_gl_unload_opengl(); + #endif } _SOKOL_PRIVATE void _sg_gl_activate_context(_sg_context_t* ctx) { @@ -5629,8 +6155,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_buffer(_sg_buffer_t* buf, const s _sg_gl_cache_bind_buffer(gl_target, gl_buf); glBufferData(gl_target, buf->cmn.size, 0, gl_usage); if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { - SOKOL_ASSERT(desc->content); - glBufferSubData(gl_target, 0, buf->cmn.size, desc->content); + SOKOL_ASSERT(desc->data.ptr); + glBufferSubData(gl_target, 0, buf->cmn.size, desc->data.ptr); } _sg_gl_cache_restore_buffer_binding(gl_target); } @@ -5725,6 +6251,9 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ SOKOL_ASSERT(desc->gl_textures[slot]); img->gl.tex[slot] = desc->gl_textures[slot]; } + if (desc->gl_texture_target) { + img->gl.target = (GLenum)desc->gl_texture_target; + } } else { /* create our own GL texture(s) */ @@ -5732,12 +6261,13 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ const bool is_compressed = _sg_is_compressed_pixel_format(img->cmn.pixel_format); for (int slot = 0; slot < img->cmn.num_slots; slot++) { glGenTextures(1, &img->gl.tex[slot]); + SOKOL_ASSERT(img->gl.tex[slot]); _sg_gl_cache_store_texture_binding(0); _sg_gl_cache_bind_texture(0, img->gl.target, img->gl.tex[slot]); GLenum gl_min_filter = _sg_gl_filter(img->cmn.min_filter); GLenum gl_mag_filter = _sg_gl_filter(img->cmn.mag_filter); - glTexParameteri(img->gl.target, GL_TEXTURE_MIN_FILTER, gl_min_filter); - glTexParameteri(img->gl.target, GL_TEXTURE_MAG_FILTER, gl_mag_filter); + glTexParameteri(img->gl.target, GL_TEXTURE_MIN_FILTER, (GLint)gl_min_filter); + glTexParameteri(img->gl.target, GL_TEXTURE_MAG_FILTER, (GLint)gl_mag_filter); if (_sg.gl.ext_anisotropic && (img->cmn.max_anisotropy > 1)) { GLint max_aniso = (GLint) img->cmn.max_anisotropy; if (max_aniso > _sg.gl.max_anisotropy) { @@ -5750,11 +6280,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { - glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_S, _sg_gl_wrap(img->cmn.wrap_u)); - glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, _sg_gl_wrap(img->cmn.wrap_v)); + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_S, (GLint)_sg_gl_wrap(img->cmn.wrap_u)); + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, (GLint)_sg_gl_wrap(img->cmn.wrap_v)); #if !defined(SOKOL_GLES2) if (!_sg.gl.gles2 && (img->cmn.type == SG_IMAGETYPE_3D)) { - glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_R, _sg_gl_wrap(img->cmn.wrap_w)); + glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_R, (GLint)_sg_gl_wrap(img->cmn.wrap_w)); } #endif #if defined(SOKOL_GLCORE33) @@ -5790,8 +6320,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ if (SG_IMAGETYPE_CUBE == img->cmn.type) { gl_img_target = _sg_gl_cubeface_target(face_index); } - const GLvoid* data_ptr = desc->content.subimage[face_index][mip_index].ptr; - const int data_size = desc->content.subimage[face_index][mip_index].size; + 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; @@ -5807,13 +6337,13 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ } else { const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); - glTexImage2D(gl_img_target, mip_index, gl_internal_format, + glTexImage2D(gl_img_target, mip_index, (GLint)gl_internal_format, mip_width, mip_height, 0, gl_format, gl_type, data_ptr); } } #if !defined(SOKOL_GLES2) else if (!_sg.gl.gles2 && ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type))) { - int mip_depth = img->cmn.depth; + int mip_depth = img->cmn.num_slices; if (SG_IMAGETYPE_3D == img->cmn.type) { mip_depth >>= mip_index; } @@ -5826,7 +6356,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ } else { const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); - glTexImage3D(gl_img_target, mip_index, gl_internal_format, + glTexImage3D(gl_img_target, mip_index, (GLint)gl_internal_format, mip_width, mip_height, mip_depth, 0, gl_format, gl_type, data_ptr); } } @@ -5874,7 +6404,7 @@ _SOKOL_PRIVATE GLuint _sg_gl_compile_shader(sg_shader_stage stage, const char* s GLint log_len = 0; glGetShaderiv(gl_shd, GL_INFO_LOG_LENGTH, &log_len); if (log_len > 0) { - GLchar* log_buf = (GLchar*) SOKOL_MALLOC(log_len); + GLchar* log_buf = (GLchar*) SOKOL_MALLOC((size_t)log_len); glGetShaderInfoLog(gl_shd, log_len, &log_len, log_buf); SOKOL_LOG(log_buf); SOKOL_FREE(log_buf); @@ -5917,7 +6447,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const s GLint log_len = 0; glGetProgramiv(gl_prog, GL_INFO_LOG_LENGTH, &log_len); if (log_len > 0) { - GLchar* log_buf = (GLchar*) SOKOL_MALLOC(log_len); + GLchar* log_buf = (GLchar*) SOKOL_MALLOC((size_t)log_len); glGetProgramInfoLog(gl_prog, log_len, &log_len, log_buf); SOKOL_LOG(log_buf); SOKOL_FREE(log_buf); @@ -5956,7 +6486,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const s } ub->num_uniforms++; } - SOKOL_ASSERT(ub_desc->size == cur_uniform_offset); + SOKOL_ASSERT(ub_desc->size == (size_t)cur_uniform_offset); } } @@ -5971,7 +6501,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const s _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index]; for (int img_index = 0; img_index < shd->cmn.stage[stage_index].num_images; img_index++) { const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - SOKOL_ASSERT(img_desc->type != _SG_IMAGETYPE_DEFAULT); + SOKOL_ASSERT(img_desc->image_type != _SG_IMAGETYPE_DEFAULT); _sg_gl_shader_image_t* gl_img = &gl_stage->images[img_index]; GLint gl_loc = img_index; if (img_desc->name) { @@ -6010,20 +6540,28 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pipeline(_sg_pipeline_t* pip, _sg pip->shader = shd; _sg_pipeline_common_init(&pip->cmn, desc); pip->gl.primitive_type = desc->primitive_type; - pip->gl.depth_stencil = desc->depth_stencil; - pip->gl.blend = desc->blend; - pip->gl.rast = desc->rasterizer; + pip->gl.depth = desc->depth; + pip->gl.stencil = desc->stencil; + // FIXME: blend color and write mask per draw-buffer-attachment (requires GL4) + pip->gl.blend = desc->colors[0].blend; + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + pip->gl.color_write_mask[i] = desc->colors[i].write_mask; + } + pip->gl.cull_mode = desc->cull_mode; + pip->gl.face_winding = desc->face_winding; + pip->gl.sample_count = desc->sample_count; + pip->gl.alpha_to_coverage_enabled = desc->alpha_to_coverage_enabled; /* resolve vertex attributes */ for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { pip->gl.attrs[attr_index].vb_index = -1; } - for (uint32_t attr_index = 0; attr_index < _sg.limits.max_vertex_attrs; attr_index++) { + for (int attr_index = 0; attr_index < _sg.limits.max_vertex_attrs; attr_index++) { const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; if (a_desc->format == SG_VERTEXFORMAT_INVALID) { break; } - SOKOL_ASSERT((a_desc->buffer_index >= 0) && (a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS)); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[a_desc->buffer_index]; const sg_vertex_step step_func = l_desc->step_func; const int step_rate = l_desc->step_rate; @@ -6079,7 +6617,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ _sg_pass_common_init(&pass->cmn, desc); /* copy image pointers */ - const sg_attachment_desc* att_desc; + const sg_pass_attachment_desc* att_desc; for (int i = 0; i < pass->cmn.num_color_atts; i++) { att_desc = &desc->color_attachments[i]; SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); @@ -6113,7 +6651,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ if (att_img) { const GLuint gl_render_buffer = att_img->gl.msaa_render_buffer; SOKOL_ASSERT(gl_render_buffer); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_RENDERBUFFER, gl_render_buffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, (GLenum)(GL_COLOR_ATTACHMENT0+i), GL_RENDERBUFFER, gl_render_buffer); } } } @@ -6125,7 +6663,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ if (att_img) { const GLuint gl_tex = att_img->gl.tex[0]; SOKOL_ASSERT(gl_tex); - const GLenum gl_att = GL_COLOR_ATTACHMENT0 + i; + const GLenum gl_att = (GLenum)(GL_COLOR_ATTACHMENT0 + i); switch (att_img->cmn.type) { case SG_IMAGETYPE_2D: glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, GL_TEXTURE_2D, gl_tex, mip_level); @@ -6179,7 +6717,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ if (is_msaa) { for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { _sg_gl_attachment_t* gl_att = &pass->gl.color_atts[i]; - _sg_attachment_t* cmn_att = &pass->cmn.color_atts[i]; + _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i]; if (gl_att->image) { SOKOL_ASSERT(0 == gl_att->gl_msaa_resolve_buffer); glGenFramebuffers(1, &gl_att->gl_msaa_resolve_buffer); @@ -6301,28 +6839,35 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac bool need_pip_cache_flush = false; if (clear_color) { - if (_sg.gl.cache.blend.color_write_mask != SG_COLORMASK_RGBA) { - need_pip_cache_flush = true; - _sg.gl.cache.blend.color_write_mask = SG_COLORMASK_RGBA; + bool need_color_mask_flush = false; + // NOTE: not a bug to iterate over all possible color attachments + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + if (SG_COLORMASK_RGBA != _sg.gl.cache.color_write_mask[i]) { + need_pip_cache_flush = true; + need_color_mask_flush = true; + _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; + } + } + if (need_color_mask_flush) { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } } if (clear_depth) { - if (!_sg.gl.cache.ds.depth_write_enabled) { + if (!_sg.gl.cache.depth.write_enabled) { need_pip_cache_flush = true; - _sg.gl.cache.ds.depth_write_enabled = true; + _sg.gl.cache.depth.write_enabled = true; glDepthMask(GL_TRUE); } - if (_sg.gl.cache.ds.depth_compare_func != SG_COMPAREFUNC_ALWAYS) { + if (_sg.gl.cache.depth.compare != SG_COMPAREFUNC_ALWAYS) { need_pip_cache_flush = true; - _sg.gl.cache.ds.depth_compare_func = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; glDepthFunc(GL_ALWAYS); } } if (clear_stencil) { - if (_sg.gl.cache.ds.stencil_write_mask != 0xFF) { + if (_sg.gl.cache.stencil.write_mask != 0xFF) { need_pip_cache_flush = true; - _sg.gl.cache.ds.stencil_write_mask = 0xFF; + _sg.gl.cache.stencil.write_mask = 0xFF; glStencilMask(0xFF); } } @@ -6344,20 +6889,20 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac GLbitfield clear_mask = 0; if (clear_color) { clear_mask |= GL_COLOR_BUFFER_BIT; - const float* c = action->colors[0].val; - glClearColor(c[0], c[1], c[2], c[3]); + const sg_color c = action->colors[0].value; + glClearColor(c.r, c.g, c.b, c.a); } if (clear_depth) { clear_mask |= GL_DEPTH_BUFFER_BIT; #ifdef SOKOL_GLCORE33 - glClearDepth(action->depth.val); + glClearDepth(action->depth.value); #else - glClearDepthf(action->depth.val); + glClearDepthf(action->depth.value); #endif } if (clear_stencil) { clear_mask |= GL_STENCIL_BUFFER_BIT; - glClearStencil(action->stencil.val); + glClearStencil(action->stencil.value); } if (0 != clear_mask) { glClear(clear_mask); @@ -6368,18 +6913,18 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac SOKOL_ASSERT(pass); for (int i = 0; i < num_color_atts; i++) { if (action->colors[i].action == SG_ACTION_CLEAR) { - glClearBufferfv(GL_COLOR, i, action->colors[i].val); + glClearBufferfv(GL_COLOR, i, &action->colors[i].value.r); } } if (pass->gl.ds_att.image) { if (clear_depth && clear_stencil) { - glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth.val, action->stencil.val); + glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth.value, action->stencil.value); } else if (clear_depth) { - glClearBufferfv(GL_DEPTH, 0, &action->depth.val); + glClearBufferfv(GL_DEPTH, 0, &action->depth.value); } else if (clear_stencil) { - GLint val = (GLint) action->stencil.val; + GLint val = (GLint) action->stencil.value; glClearBufferiv(GL_STENCIL, 0, &val); } } @@ -6411,7 +6956,7 @@ _SOKOL_PRIVATE void _sg_gl_end_pass(void) { if (gl_att->image) { SOKOL_ASSERT(gl_att->gl_msaa_resolve_buffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gl_att->gl_msaa_resolve_buffer); - glReadBuffer(GL_COLOR_ATTACHMENT0 + att_index); + glReadBuffer((GLenum)(GL_COLOR_ATTACHMENT0 + att_index)); glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { @@ -6454,156 +6999,198 @@ _SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) { _sg.gl.cache.cur_primitive_type = _sg_gl_primitive_type(pip->gl.primitive_type); _sg.gl.cache.cur_index_type = _sg_gl_index_type(pip->cmn.index_type); - /* update depth-stencil state */ - const sg_depth_stencil_state* new_ds = &pip->gl.depth_stencil; - sg_depth_stencil_state* cache_ds = &_sg.gl.cache.ds; - if (new_ds->depth_compare_func != cache_ds->depth_compare_func) { - cache_ds->depth_compare_func = new_ds->depth_compare_func; - glDepthFunc(_sg_gl_compare_func(new_ds->depth_compare_func)); - } - if (new_ds->depth_write_enabled != cache_ds->depth_write_enabled) { - cache_ds->depth_write_enabled = new_ds->depth_write_enabled; - glDepthMask(new_ds->depth_write_enabled); - } - if (new_ds->stencil_enabled != cache_ds->stencil_enabled) { - cache_ds->stencil_enabled = new_ds->stencil_enabled; - if (new_ds->stencil_enabled) glEnable(GL_STENCIL_TEST); - else glDisable(GL_STENCIL_TEST); - } - if (new_ds->stencil_write_mask != cache_ds->stencil_write_mask) { - cache_ds->stencil_write_mask = new_ds->stencil_write_mask; - glStencilMask(new_ds->stencil_write_mask); - } - for (int i = 0; i < 2; i++) { - const sg_stencil_state* new_ss = (i==0)? &new_ds->stencil_front : &new_ds->stencil_back; - sg_stencil_state* cache_ss = (i==0)? &cache_ds->stencil_front : &cache_ds->stencil_back; - GLenum gl_face = (i==0)? GL_FRONT : GL_BACK; - if ((new_ss->compare_func != cache_ss->compare_func) || - (new_ds->stencil_read_mask != cache_ds->stencil_read_mask) || - (new_ds->stencil_ref != cache_ds->stencil_ref)) - { - cache_ss->compare_func = new_ss->compare_func; - glStencilFuncSeparate(gl_face, - _sg_gl_compare_func(new_ss->compare_func), - new_ds->stencil_ref, - new_ds->stencil_read_mask); - } - if ((new_ss->fail_op != cache_ss->fail_op) || - (new_ss->depth_fail_op != cache_ss->depth_fail_op) || - (new_ss->pass_op != cache_ss->pass_op)) - { - cache_ss->fail_op = new_ss->fail_op; - cache_ss->depth_fail_op = new_ss->depth_fail_op; - cache_ss->pass_op = new_ss->pass_op; - glStencilOpSeparate(gl_face, - _sg_gl_stencil_op(new_ss->fail_op), - _sg_gl_stencil_op(new_ss->depth_fail_op), - _sg_gl_stencil_op(new_ss->pass_op)); - } - } - cache_ds->stencil_read_mask = new_ds->stencil_read_mask; - cache_ds->stencil_ref = new_ds->stencil_ref; - - /* update blend state */ - const sg_blend_state* new_b = &pip->gl.blend; - sg_blend_state* cache_b = &_sg.gl.cache.blend; - if (new_b->enabled != cache_b->enabled) { - cache_b->enabled = new_b->enabled; - if (new_b->enabled) glEnable(GL_BLEND); - else glDisable(GL_BLEND); - } - if ((new_b->src_factor_rgb != cache_b->src_factor_rgb) || - (new_b->dst_factor_rgb != cache_b->dst_factor_rgb) || - (new_b->src_factor_alpha != cache_b->src_factor_alpha) || - (new_b->dst_factor_alpha != cache_b->dst_factor_alpha)) + /* update depth state */ { - cache_b->src_factor_rgb = new_b->src_factor_rgb; - cache_b->dst_factor_rgb = new_b->dst_factor_rgb; - cache_b->src_factor_alpha = new_b->src_factor_alpha; - cache_b->dst_factor_alpha = new_b->dst_factor_alpha; - glBlendFuncSeparate(_sg_gl_blend_factor(new_b->src_factor_rgb), - _sg_gl_blend_factor(new_b->dst_factor_rgb), - _sg_gl_blend_factor(new_b->src_factor_alpha), - _sg_gl_blend_factor(new_b->dst_factor_alpha)); - } - if ((new_b->op_rgb != cache_b->op_rgb) || (new_b->op_alpha != cache_b->op_alpha)) { - cache_b->op_rgb = new_b->op_rgb; - cache_b->op_alpha = new_b->op_alpha; - glBlendEquationSeparate(_sg_gl_blend_op(new_b->op_rgb), _sg_gl_blend_op(new_b->op_alpha)); - } - if (new_b->color_write_mask != cache_b->color_write_mask) { - cache_b->color_write_mask = new_b->color_write_mask; - glColorMask((new_b->color_write_mask & SG_COLORMASK_R) != 0, - (new_b->color_write_mask & SG_COLORMASK_G) != 0, - (new_b->color_write_mask & SG_COLORMASK_B) != 0, - (new_b->color_write_mask & SG_COLORMASK_A) != 0); - } - if (!_sg_fequal(new_b->blend_color[0], cache_b->blend_color[0], 0.0001f) || - !_sg_fequal(new_b->blend_color[1], cache_b->blend_color[1], 0.0001f) || - !_sg_fequal(new_b->blend_color[2], cache_b->blend_color[2], 0.0001f) || - !_sg_fequal(new_b->blend_color[3], cache_b->blend_color[3], 0.0001f)) - { - const float* bc = new_b->blend_color; - for (int i=0; i<4; i++) { - cache_b->blend_color[i] = bc[i]; + const sg_depth_state* state_ds = &pip->gl.depth; + sg_depth_state* cache_ds = &_sg.gl.cache.depth; + if (state_ds->compare != cache_ds->compare) { + cache_ds->compare = state_ds->compare; + glDepthFunc(_sg_gl_compare_func(state_ds->compare)); + } + if (state_ds->write_enabled != cache_ds->write_enabled) { + cache_ds->write_enabled = state_ds->write_enabled; + glDepthMask(state_ds->write_enabled); + } + if (!_sg_fequal(state_ds->bias, cache_ds->bias, 0.000001f) || + !_sg_fequal(state_ds->bias_slope_scale, cache_ds->bias_slope_scale, 0.000001f)) + { + /* according to ANGLE's D3D11 backend: + D3D11 SlopeScaledDepthBias ==> GL polygonOffsetFactor + D3D11 DepthBias ==> GL polygonOffsetUnits + DepthBiasClamp has no meaning on GL + */ + cache_ds->bias = state_ds->bias; + cache_ds->bias_slope_scale = state_ds->bias_slope_scale; + glPolygonOffset(state_ds->bias_slope_scale, state_ds->bias); + bool po_enabled = true; + if (_sg_fequal(state_ds->bias, 0.0f, 0.000001f) && + _sg_fequal(state_ds->bias_slope_scale, 0.0f, 0.000001f)) + { + po_enabled = false; + } + if (po_enabled != _sg.gl.cache.polygon_offset_enabled) { + _sg.gl.cache.polygon_offset_enabled = po_enabled; + if (po_enabled) { + glEnable(GL_POLYGON_OFFSET_FILL); + } + else { + glDisable(GL_POLYGON_OFFSET_FILL); + } + } } - glBlendColor(bc[0], bc[1], bc[2], bc[3]); } - /* update rasterizer state */ - const sg_rasterizer_state* new_r = &pip->gl.rast; - sg_rasterizer_state* cache_r = &_sg.gl.cache.rast; - if (new_r->cull_mode != cache_r->cull_mode) { - cache_r->cull_mode = new_r->cull_mode; - if (SG_CULLMODE_NONE == new_r->cull_mode) { + /* update stencil state */ + { + const sg_stencil_state* state_ss = &pip->gl.stencil; + sg_stencil_state* cache_ss = &_sg.gl.cache.stencil; + if (state_ss->enabled != cache_ss->enabled) { + cache_ss->enabled = state_ss->enabled; + if (state_ss->enabled) { + glEnable(GL_STENCIL_TEST); + } + else { + glDisable(GL_STENCIL_TEST); + } + } + if (state_ss->write_mask != cache_ss->write_mask) { + cache_ss->write_mask = state_ss->write_mask; + glStencilMask(state_ss->write_mask); + } + for (int i = 0; i < 2; i++) { + const sg_stencil_face_state* state_sfs = (i==0)? &state_ss->front : &state_ss->back; + sg_stencil_face_state* cache_sfs = (i==0)? &cache_ss->front : &cache_ss->back; + GLenum gl_face = (i==0)? GL_FRONT : GL_BACK; + if ((state_sfs->compare != cache_sfs->compare) || + (state_ss->read_mask != cache_ss->read_mask) || + (state_ss->ref != cache_ss->ref)) + { + cache_sfs->compare = state_sfs->compare; + glStencilFuncSeparate(gl_face, + _sg_gl_compare_func(state_sfs->compare), + state_ss->ref, + state_ss->read_mask); + } + if ((state_sfs->fail_op != cache_sfs->fail_op) || + (state_sfs->depth_fail_op != cache_sfs->depth_fail_op) || + (state_sfs->pass_op != cache_sfs->pass_op)) + { + cache_sfs->fail_op = state_sfs->fail_op; + cache_sfs->depth_fail_op = state_sfs->depth_fail_op; + cache_sfs->pass_op = state_sfs->pass_op; + glStencilOpSeparate(gl_face, + _sg_gl_stencil_op(state_sfs->fail_op), + _sg_gl_stencil_op(state_sfs->depth_fail_op), + _sg_gl_stencil_op(state_sfs->pass_op)); + } + } + cache_ss->read_mask = state_ss->read_mask; + cache_ss->ref = state_ss->ref; + } + + /* update blend state + FIXME: separate blend state per color attachment not support, needs GL4 + */ + { + const sg_blend_state* state_bs = &pip->gl.blend; + sg_blend_state* cache_bs = &_sg.gl.cache.blend; + if (state_bs->enabled != cache_bs->enabled) { + cache_bs->enabled = state_bs->enabled; + if (state_bs->enabled) { + glEnable(GL_BLEND); + } + else { + glDisable(GL_BLEND); + } + } + if ((state_bs->src_factor_rgb != cache_bs->src_factor_rgb) || + (state_bs->dst_factor_rgb != cache_bs->dst_factor_rgb) || + (state_bs->src_factor_alpha != cache_bs->src_factor_alpha) || + (state_bs->dst_factor_alpha != cache_bs->dst_factor_alpha)) + { + cache_bs->src_factor_rgb = state_bs->src_factor_rgb; + cache_bs->dst_factor_rgb = state_bs->dst_factor_rgb; + cache_bs->src_factor_alpha = state_bs->src_factor_alpha; + cache_bs->dst_factor_alpha = state_bs->dst_factor_alpha; + glBlendFuncSeparate(_sg_gl_blend_factor(state_bs->src_factor_rgb), + _sg_gl_blend_factor(state_bs->dst_factor_rgb), + _sg_gl_blend_factor(state_bs->src_factor_alpha), + _sg_gl_blend_factor(state_bs->dst_factor_alpha)); + } + if ((state_bs->op_rgb != cache_bs->op_rgb) || (state_bs->op_alpha != cache_bs->op_alpha)) { + cache_bs->op_rgb = state_bs->op_rgb; + cache_bs->op_alpha = state_bs->op_alpha; + glBlendEquationSeparate(_sg_gl_blend_op(state_bs->op_rgb), _sg_gl_blend_op(state_bs->op_alpha)); + } + } + + /* standalone state */ + for (GLuint i = 0; i < (GLuint)pip->cmn.color_attachment_count; i++) { + if (pip->gl.color_write_mask[i] != _sg.gl.cache.color_write_mask[i]) { + const sg_color_mask cm = pip->gl.color_write_mask[i]; + _sg.gl.cache.color_write_mask[i] = cm; + #ifdef SOKOL_GLCORE33 + glColorMaski(i, + (cm & SG_COLORMASK_R) != 0, + (cm & SG_COLORMASK_G) != 0, + (cm & SG_COLORMASK_B) != 0, + (cm & SG_COLORMASK_A) != 0); + #else + if (0 == i) { + glColorMask((cm & SG_COLORMASK_R) != 0, + (cm & SG_COLORMASK_G) != 0, + (cm & SG_COLORMASK_B) != 0, + (cm & SG_COLORMASK_A) != 0); + } + #endif + } + } + + if (!_sg_fequal(pip->cmn.blend_color.r, _sg.gl.cache.blend_color.r, 0.0001f) || + !_sg_fequal(pip->cmn.blend_color.g, _sg.gl.cache.blend_color.g, 0.0001f) || + !_sg_fequal(pip->cmn.blend_color.b, _sg.gl.cache.blend_color.b, 0.0001f) || + !_sg_fequal(pip->cmn.blend_color.a, _sg.gl.cache.blend_color.a, 0.0001f)) + { + sg_color c = pip->cmn.blend_color; + _sg.gl.cache.blend_color = c; + glBlendColor(c.r, c.g, c.b, c.a); + } + if (pip->gl.cull_mode != _sg.gl.cache.cull_mode) { + _sg.gl.cache.cull_mode = pip->gl.cull_mode; + if (SG_CULLMODE_NONE == pip->gl.cull_mode) { glDisable(GL_CULL_FACE); } else { glEnable(GL_CULL_FACE); - GLenum gl_mode = (SG_CULLMODE_FRONT == new_r->cull_mode) ? GL_FRONT : GL_BACK; + GLenum gl_mode = (SG_CULLMODE_FRONT == pip->gl.cull_mode) ? GL_FRONT : GL_BACK; glCullFace(gl_mode); } } - if (new_r->face_winding != cache_r->face_winding) { - cache_r->face_winding = new_r->face_winding; - GLenum gl_winding = (SG_FACEWINDING_CW == new_r->face_winding) ? GL_CW : GL_CCW; + if (pip->gl.face_winding != _sg.gl.cache.face_winding) { + _sg.gl.cache.face_winding = pip->gl.face_winding; + GLenum gl_winding = (SG_FACEWINDING_CW == pip->gl.face_winding) ? GL_CW : GL_CCW; glFrontFace(gl_winding); } - if (new_r->alpha_to_coverage_enabled != cache_r->alpha_to_coverage_enabled) { - cache_r->alpha_to_coverage_enabled = new_r->alpha_to_coverage_enabled; - if (new_r->alpha_to_coverage_enabled) glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); - else glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + if (pip->gl.alpha_to_coverage_enabled != _sg.gl.cache.alpha_to_coverage_enabled) { + _sg.gl.cache.alpha_to_coverage_enabled = pip->gl.alpha_to_coverage_enabled; + if (pip->gl.alpha_to_coverage_enabled) { + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + else { + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } } #ifdef SOKOL_GLCORE33 - if (new_r->sample_count != cache_r->sample_count) { - cache_r->sample_count = new_r->sample_count; - if (new_r->sample_count > 1) glEnable(GL_MULTISAMPLE); - else glDisable(GL_MULTISAMPLE); + if (pip->gl.sample_count != _sg.gl.cache.sample_count) { + _sg.gl.cache.sample_count = pip->gl.sample_count; + if (pip->gl.sample_count > 1) { + glEnable(GL_MULTISAMPLE); + } + else { + glDisable(GL_MULTISAMPLE); + } } #endif - if (!_sg_fequal(new_r->depth_bias, cache_r->depth_bias, 0.000001f) || - !_sg_fequal(new_r->depth_bias_slope_scale, cache_r->depth_bias_slope_scale, 0.000001f)) - { - /* according to ANGLE's D3D11 backend: - D3D11 SlopeScaledDepthBias ==> GL polygonOffsetFactor - D3D11 DepthBias ==> GL polygonOffsetUnits - DepthBiasClamp has no meaning on GL - */ - cache_r->depth_bias = new_r->depth_bias; - cache_r->depth_bias_slope_scale = new_r->depth_bias_slope_scale; - glPolygonOffset(new_r->depth_bias_slope_scale, new_r->depth_bias); - bool po_enabled = true; - if (_sg_fequal(new_r->depth_bias, 0.0f, 0.000001f) && - _sg_fequal(new_r->depth_bias_slope_scale, 0.0f, 0.000001f)) - { - po_enabled = false; - } - if (po_enabled != _sg.gl.cache.polygon_offset_enabled) { - _sg.gl.cache.polygon_offset_enabled = po_enabled; - if (po_enabled) glEnable(GL_POLYGON_OFFSET_FILL); - else glDisable(GL_POLYGON_OFFSET_FILL); - } - } /* bind shader program */ if (pip->shader->gl.prog != _sg.gl.cache.prog) { @@ -6611,6 +7198,7 @@ _SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) { glUseProgram(pip->shader->gl.prog); } } + _SG_GL_CHECK_ERROR(); } _SOKOL_PRIVATE void _sg_gl_apply_bindings( @@ -6652,7 +7240,7 @@ _SOKOL_PRIVATE void _sg_gl_apply_bindings( _sg.gl.cache.cur_ib_offset = ib_offset; /* vertex attributes */ - for (uint32_t attr_index = 0; attr_index < _sg.limits.max_vertex_attrs; attr_index++) { + for (GLuint attr_index = 0; attr_index < (GLuint)_sg.limits.max_vertex_attrs; attr_index++) { _sg_gl_attr_t* attr = &pip->gl.attrs[attr_index]; _sg_gl_cache_attr_t* cache_attr = &_sg.gl.cache.attrs[attr_index]; bool cache_attr_dirty = false; @@ -6677,9 +7265,9 @@ _SOKOL_PRIVATE void _sg_gl_apply_bindings( glVertexAttribPointer(attr_index, attr->size, attr->type, attr->normalized, attr->stride, (const GLvoid*)(GLintptr)vb_offset); - #ifdef SOKOL_INSTANCING_ENABLED + #if defined(_SOKOL_GL_INSTANCING_ENABLED) if (_sg.features.instancing) { - glVertexAttribDivisor(attr_index, attr->divisor); + glVertexAttribDivisor(attr_index, (GLuint)attr->divisor); } #endif cache_attr_dirty = true; @@ -6705,15 +7293,12 @@ _SOKOL_PRIVATE void _sg_gl_apply_bindings( _SG_GL_CHECK_ERROR(); } -_SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { - _SOKOL_UNUSED(num_bytes); - SOKOL_ASSERT(data && (num_bytes > 0)); - SOKOL_ASSERT((stage_index >= 0) && ((int)stage_index < SG_NUM_SHADER_STAGES)); +_SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->slot.id == _sg.gl.cache.cur_pipeline_id.id); SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->slot.id == _sg.gl.cache.cur_pipeline->cmn.shader_id.id); SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks > ub_index); - SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size == num_bytes); + SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size == data->size); const _sg_gl_shader_stage_t* gl_stage = &_sg.gl.cache.cur_pipeline->shader->gl.stage[stage_index]; const _sg_gl_uniform_block_t* gl_ub = &gl_stage->uniform_blocks[ub_index]; for (int u_index = 0; u_index < gl_ub->num_uniforms; u_index++) { @@ -6722,7 +7307,7 @@ _SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_in if (u->gl_loc == -1) { continue; } - GLfloat* ptr = (GLfloat*) (((uint8_t*)data) + u->offset); + GLfloat* ptr = (GLfloat*) (((uint8_t*)data->ptr) + u->offset); switch (u->type) { case SG_UNIFORMTYPE_INVALID: break; @@ -6785,8 +7370,8 @@ _SOKOL_PRIVATE void _sg_gl_commit(void) { _sg_gl_cache_clear_texture_bindings(false); } -_SOKOL_PRIVATE void _sg_gl_update_buffer(_sg_buffer_t* buf, const void* data_ptr, uint32_t data_size) { - SOKOL_ASSERT(buf && data_ptr && (data_size > 0)); +_SOKOL_PRIVATE void _sg_gl_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); /* only one update per buffer per frame allowed */ if (++buf->cmn.active_slot >= buf->cmn.num_slots) { buf->cmn.active_slot = 0; @@ -6798,13 +7383,13 @@ _SOKOL_PRIVATE void _sg_gl_update_buffer(_sg_buffer_t* buf, const void* data_ptr _SG_GL_CHECK_ERROR(); _sg_gl_cache_store_buffer_binding(gl_tgt); _sg_gl_cache_bind_buffer(gl_tgt, gl_buf); - glBufferSubData(gl_tgt, 0, data_size, data_ptr); + glBufferSubData(gl_tgt, 0, (GLsizeiptr)data->size, data->ptr); _sg_gl_cache_restore_buffer_binding(gl_tgt); _SG_GL_CHECK_ERROR(); } -_SOKOL_PRIVATE uint32_t _sg_gl_append_buffer(_sg_buffer_t* buf, const void* data_ptr, uint32_t data_size, bool new_frame) { - SOKOL_ASSERT(buf && data_ptr && (data_size > 0)); +_SOKOL_PRIVATE int _sg_gl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); if (new_frame) { if (++buf->cmn.active_slot >= buf->cmn.num_slots) { buf->cmn.active_slot = 0; @@ -6817,14 +7402,14 @@ _SOKOL_PRIVATE uint32_t _sg_gl_append_buffer(_sg_buffer_t* buf, const void* data _SG_GL_CHECK_ERROR(); _sg_gl_cache_store_buffer_binding(gl_tgt); _sg_gl_cache_bind_buffer(gl_tgt, gl_buf); - glBufferSubData(gl_tgt, buf->cmn.append_pos, data_size, data_ptr); + glBufferSubData(gl_tgt, buf->cmn.append_pos, (GLsizeiptr)data->size, data->ptr); _sg_gl_cache_restore_buffer_binding(gl_tgt); _SG_GL_CHECK_ERROR(); /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */ - return _sg_roundup(data_size, 4); + return _sg_roundup((int)data->size, 4); } -_SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_content* data) { +_SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(img && data); /* only one update per image per frame allowed */ if (++img->cmn.active_slot >= img->cmn.num_slots) { @@ -6862,7 +7447,7 @@ _SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_content } #if !defined(SOKOL_GLES2) else if (!_sg.gl.gles2 && ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type))) { - int mip_depth = img->cmn.depth >> mip_index; + int mip_depth = img->cmn.num_slices >> mip_index; if (mip_depth == 0) { mip_depth = 1; } @@ -7047,6 +7632,14 @@ static inline HRESULT _sg_d3d11_CreateShaderResourceView(ID3D11Device* self, ID3 #endif } +static inline void _sg_d3d11_GetResource(ID3D11View* self, ID3D11Resource** ppResource) { + #if defined(__cplusplus) + self->GetResource(ppResource); + #else + self->lpVtbl->GetResource(self, ppResource); + #endif +} + static inline HRESULT _sg_d3d11_CreateTexture3D(ID3D11Device* self, const D3D11_TEXTURE3D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture3D** ppTexture3D) { #if defined(__cplusplus) return self->CreateTexture3D(pDesc, pInitialData, ppTexture3D); @@ -7526,6 +8119,8 @@ _SOKOL_PRIVATE void _sg_d3d11_init_caps(void) { _sg.features.imagetype_3d = true; _sg.features.imagetype_array = true; _sg.features.image_clamp_to_border = true; + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; _sg.limits.max_image_size_2d = 16 * 1024; _sg.limits.max_image_size_cube = 16 * 1024; @@ -7634,7 +8229,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, cons else { D3D11_BUFFER_DESC d3d11_desc; memset(&d3d11_desc, 0, sizeof(d3d11_desc)); - d3d11_desc.ByteWidth = buf->cmn.size; + d3d11_desc.ByteWidth = (UINT)buf->cmn.size; d3d11_desc.Usage = _sg_d3d11_usage(buf->cmn.usage); d3d11_desc.BindFlags = buf->cmn.type == SG_BUFFERTYPE_VERTEXBUFFER ? D3D11_BIND_VERTEX_BUFFER : D3D11_BIND_INDEX_BUFFER; d3d11_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(buf->cmn.usage); @@ -7642,8 +8237,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, cons D3D11_SUBRESOURCE_DATA init_data; memset(&init_data, 0, sizeof(init_data)); if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { - SOKOL_ASSERT(desc->content); - init_data.pSysMem = desc->content; + SOKOL_ASSERT(desc->data.ptr); + init_data.pSysMem = desc->data.ptr; init_data_ptr = &init_data; } HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_desc, init_data_ptr, &buf->d3d11.buf); @@ -7660,9 +8255,9 @@ _SOKOL_PRIVATE void _sg_d3d11_destroy_buffer(_sg_buffer_t* buf) { } } -_SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_image_content* content) { +_SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_image_data* data) { const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.depth:1; + const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1; int subres_index = 0; for (int face_index = 0; face_index < num_faces; face_index++) { for (int slice_index = 0; slice_index < num_slices; slice_index++) { @@ -7671,15 +8266,15 @@ _SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_ D3D11_SUBRESOURCE_DATA* subres_data = &_sg.d3d11.subres_data[subres_index]; const int mip_width = ((img->cmn.width>>mip_index)>0) ? img->cmn.width>>mip_index : 1; const int mip_height = ((img->cmn.height>>mip_index)>0) ? img->cmn.height>>mip_index : 1; - const sg_subimage_content* subimg_content = &(content->subimage[face_index][mip_index]); - const int slice_size = subimg_content->size / num_slices; - const int slice_offset = slice_size * slice_index; - const uint8_t* ptr = (const uint8_t*) subimg_content->ptr; + const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); + const size_t slice_size = subimg_data->size / (size_t)num_slices; + const size_t slice_offset = slice_size * (size_t)slice_index; + const uint8_t* ptr = (const uint8_t*) subimg_data->ptr; subres_data->pSysMem = ptr + slice_offset; - subres_data->SysMemPitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + subres_data->SysMemPitch = (UINT)_sg_row_pitch(img->cmn.pixel_format, mip_width, 1); if (img->cmn.type == SG_IMAGETYPE_3D) { /* FIXME? const int mip_depth = ((img->depth>>mip_index)>0) ? img->depth>>mip_index : 1; */ - subres_data->SysMemSlicePitch = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); + subres_data->SysMemSlicePitch = (UINT)_sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); } else { subres_data->SysMemSlicePitch = 0; @@ -7697,172 +8292,200 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const _SOKOL_UNUSED(hr); _sg_image_common_init(&img->cmn, desc); - const bool injected = (0 != desc->d3d11_texture); + const bool injected = (0 != desc->d3d11_texture) || (0 != desc->d3d11_shader_resource_view); const bool msaa = (img->cmn.sample_count > 1); + img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); /* special case depth-stencil buffer? */ if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) { /* create only a depth-texture */ SOKOL_ASSERT(!injected); - img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { SOKOL_LOG("trying to create a D3D11 depth-texture with unsupported pixel format\n"); return SG_RESOURCESTATE_FAILED; } D3D11_TEXTURE2D_DESC d3d11_desc; memset(&d3d11_desc, 0, sizeof(d3d11_desc)); - d3d11_desc.Width = img->cmn.width; - d3d11_desc.Height = img->cmn.height; + d3d11_desc.Width = (UINT)img->cmn.width; + d3d11_desc.Height = (UINT)img->cmn.height; d3d11_desc.MipLevels = 1; d3d11_desc.ArraySize = 1; d3d11_desc.Format = img->d3d11.format; d3d11_desc.Usage = D3D11_USAGE_DEFAULT; d3d11_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - d3d11_desc.SampleDesc.Count = img->cmn.sample_count; - d3d11_desc.SampleDesc.Quality = msaa ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0; + 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); } else { - /* create (or inject) color texture */ + /* create (or inject) color texture and shader-resource-view */ /* prepare initial content pointers */ D3D11_SUBRESOURCE_DATA* init_data = 0; if (!injected && (img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { - _sg_d3d11_fill_subres_data(img, &desc->content); + _sg_d3d11_fill_subres_data(img, &desc->data); init_data = _sg.d3d11.subres_data; } if (img->cmn.type != SG_IMAGETYPE_3D) { /* 2D-, cube- or array-texture */ /* if this is an MSAA render target, the following texture will be the 'resolve-texture' */ - D3D11_TEXTURE2D_DESC d3d11_tex_desc; - memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); - d3d11_tex_desc.Width = img->cmn.width; - d3d11_tex_desc.Height = img->cmn.height; - d3d11_tex_desc.MipLevels = img->cmn.num_mipmaps; - switch (img->cmn.type) { - case SG_IMAGETYPE_ARRAY: d3d11_tex_desc.ArraySize = img->cmn.depth; break; - case SG_IMAGETYPE_CUBE: d3d11_tex_desc.ArraySize = 6; break; - default: d3d11_tex_desc.ArraySize = 1; break; - } - d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - if (img->cmn.render_target) { - img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); - d3d11_tex_desc.Format = img->d3d11.format; - d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; - if (!msaa) { - d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET; - } - d3d11_tex_desc.CPUAccessFlags = 0; - } - else { - img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); - d3d11_tex_desc.Format = img->d3d11.format; - d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); - d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); - } - if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { - /* trying to create a texture format that's not supported by D3D */ - SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); - return SG_RESOURCESTATE_FAILED; - } - d3d11_tex_desc.SampleDesc.Count = 1; - d3d11_tex_desc.SampleDesc.Quality = 0; - d3d11_tex_desc.MiscFlags = (img->cmn.type == SG_IMAGETYPE_CUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0; + + /* first check for injected texture and/or resource view */ if (injected) { img->d3d11.tex2d = (ID3D11Texture2D*) desc->d3d11_texture; - _sg_d3d11_AddRef(img->d3d11.tex2d); + img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view; + if (img->d3d11.tex2d) { + _sg_d3d11_AddRef(img->d3d11.tex2d); + } + else { + /* if only a shader-resource-view was provided, but no texture, lookup + the texture from the shader-resource-view, this also bumps the refcount + */ + SOKOL_ASSERT(img->d3d11.srv); + _sg_d3d11_GetResource((ID3D11View*)img->d3d11.srv, (ID3D11Resource**)&img->d3d11.tex2d); + SOKOL_ASSERT(img->d3d11.tex2d); + } + if (img->d3d11.srv) { + _sg_d3d11_AddRef(img->d3d11.srv); + } } - else { + + /* if not injected, create texture */ + if (0 == img->d3d11.tex2d) { + D3D11_TEXTURE2D_DESC d3d11_tex_desc; + memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); + d3d11_tex_desc.Width = (UINT)img->cmn.width; + d3d11_tex_desc.Height = (UINT)img->cmn.height; + d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps; + switch (img->cmn.type) { + case SG_IMAGETYPE_ARRAY: d3d11_tex_desc.ArraySize = (UINT)img->cmn.num_slices; break; + case SG_IMAGETYPE_CUBE: d3d11_tex_desc.ArraySize = 6; break; + default: d3d11_tex_desc.ArraySize = 1; break; + } + d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + d3d11_tex_desc.Format = img->d3d11.format; + if (img->cmn.render_target) { + d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; + if (!msaa) { + d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + } + d3d11_tex_desc.CPUAccessFlags = 0; + } + else { + d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); + d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); + } + if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { + /* trying to create a texture format that's not supported by D3D */ + SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); + return SG_RESOURCESTATE_FAILED; + } + d3d11_tex_desc.SampleDesc.Count = 1; + d3d11_tex_desc.SampleDesc.Quality = 0; + 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); } - /* shader-resource-view */ - D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; - memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc)); - d3d11_srv_desc.Format = d3d11_tex_desc.Format; - switch (img->cmn.type) { - case SG_IMAGETYPE_2D: - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - d3d11_srv_desc.Texture2D.MipLevels = img->cmn.num_mipmaps; - break; - case SG_IMAGETYPE_CUBE: - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - d3d11_srv_desc.TextureCube.MipLevels = img->cmn.num_mipmaps; - break; - case SG_IMAGETYPE_ARRAY: - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - d3d11_srv_desc.Texture2DArray.MipLevels = img->cmn.num_mipmaps; - d3d11_srv_desc.Texture2DArray.ArraySize = img->cmn.depth; - break; - default: - SOKOL_UNREACHABLE; break; + /* ...and similar, if not injected, create shader-resource-view */ + if (0 == img->d3d11.srv) { + D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; + memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc)); + d3d11_srv_desc.Format = img->d3d11.format; + switch (img->cmn.type) { + case SG_IMAGETYPE_2D: + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + d3d11_srv_desc.Texture2D.MipLevels = (UINT)img->cmn.num_mipmaps; + break; + case SG_IMAGETYPE_CUBE: + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + d3d11_srv_desc.TextureCube.MipLevels = (UINT)img->cmn.num_mipmaps; + break; + case SG_IMAGETYPE_ARRAY: + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + d3d11_srv_desc.Texture2DArray.MipLevels = (UINT)img->cmn.num_mipmaps; + d3d11_srv_desc.Texture2DArray.ArraySize = (UINT)img->cmn.num_slices; + break; + default: + 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); } - hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex2d, &d3d11_srv_desc, &img->d3d11.srv); - SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.srv); } else { - /* 3D texture */ - D3D11_TEXTURE3D_DESC d3d11_tex_desc; - memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); - d3d11_tex_desc.Width = img->cmn.width; - d3d11_tex_desc.Height = img->cmn.height; - d3d11_tex_desc.Depth = img->cmn.depth; - d3d11_tex_desc.MipLevels = img->cmn.num_mipmaps; - d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - if (img->cmn.render_target) { - img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); - d3d11_tex_desc.Format = img->d3d11.format; - d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; - if (!msaa) { - d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET; - } - d3d11_tex_desc.CPUAccessFlags = 0; - } - else { - img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format); - d3d11_tex_desc.Format = img->d3d11.format; - d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); - d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); - } - if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { - /* trying to create a texture format that's not supported by D3D */ - SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); - return SG_RESOURCESTATE_FAILED; - } + /* 3D texture - same procedure, first check if injected, than create non-injected */ if (injected) { img->d3d11.tex3d = (ID3D11Texture3D*) desc->d3d11_texture; - _sg_d3d11_AddRef(img->d3d11.tex3d); + img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view; + if (img->d3d11.tex3d) { + _sg_d3d11_AddRef(img->d3d11.tex3d); + } + else { + SOKOL_ASSERT(img->d3d11.srv); + _sg_d3d11_GetResource((ID3D11View*)img->d3d11.srv, (ID3D11Resource**)&img->d3d11.tex3d); + SOKOL_ASSERT(img->d3d11.tex3d); + } + if (img->d3d11.srv) { + _sg_d3d11_AddRef(img->d3d11.srv); + } } - else { + + if (0 == img->d3d11.tex3d) { + D3D11_TEXTURE3D_DESC d3d11_tex_desc; + memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); + d3d11_tex_desc.Width = (UINT)img->cmn.width; + d3d11_tex_desc.Height = (UINT)img->cmn.height; + d3d11_tex_desc.Depth = (UINT)img->cmn.num_slices; + d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps; + d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + d3d11_tex_desc.Format = img->d3d11.format; + if (img->cmn.render_target) { + d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; + if (!msaa) { + d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + } + d3d11_tex_desc.CPUAccessFlags = 0; + } + else { + d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage); + d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage); + } + if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { + /* trying to create a texture format that's not supported by D3D */ + SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); + 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); } - /* shader resource view for 3d texture */ - D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; - memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc)); - d3d11_srv_desc.Format = d3d11_tex_desc.Format; - d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; - d3d11_srv_desc.Texture3D.MipLevels = 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 (0 == img->d3d11.srv) { + D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; + memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc)); + d3d11_srv_desc.Format = img->d3d11.format; + 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); + } } /* also need to create a separate MSAA render target texture? */ if (msaa) { D3D11_TEXTURE2D_DESC d3d11_tex_desc; memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc)); - d3d11_tex_desc.Width = img->cmn.width; - d3d11_tex_desc.Height = img->cmn.height; + d3d11_tex_desc.Width = (UINT)img->cmn.width; + d3d11_tex_desc.Height = (UINT)img->cmn.height; d3d11_tex_desc.MipLevels = 1; d3d11_tex_desc.ArraySize = 1; d3d11_tex_desc.Format = img->d3d11.format; d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT; d3d11_tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; d3d11_tex_desc.CPUAccessFlags = 0; - d3d11_tex_desc.SampleDesc.Count = img->cmn.sample_count; + 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); @@ -7936,7 +8559,7 @@ _SOKOL_PRIVATE bool _sg_d3d11_load_d3dcompiler_dll(void) { return false; } /* look up function pointers */ - _sg.d3d11.D3DCompile_func = (pD3DCompile) GetProcAddress(_sg.d3d11.d3dcompiler_dll, "D3DCompile"); + _sg.d3d11.D3DCompile_func = (pD3DCompile)(void*) GetProcAddress(_sg.d3d11.d3dcompiler_dll, "D3DCompile"); SOKOL_ASSERT(_sg.d3d11.D3DCompile_func); } return 0 != _sg.d3d11.d3dcompiler_dll; @@ -7982,8 +8605,6 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* st return output; } -#define _sg_d3d11_roundup(val, round_to) (((val)+((round_to)-1))&~((round_to)-1)) - _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { SOKOL_ASSERT(shd && desc); SOKOL_ASSERT(!shd->d3d11.vs && !shd->d3d11.fs && !shd->d3d11.vs_blob); @@ -8009,7 +8630,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons SOKOL_ASSERT(0 == d3d11_stage->cbufs[ub_index]); D3D11_BUFFER_DESC cb_desc; memset(&cb_desc, 0, sizeof(cb_desc)); - cb_desc.ByteWidth = _sg_d3d11_roundup(ub->size, 16); + cb_desc.ByteWidth = (UINT)_sg_roundup((int)ub->size, 16); 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]); @@ -8020,12 +8641,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons const void* vs_ptr = 0, *fs_ptr = 0; SIZE_T vs_length = 0, fs_length = 0; ID3DBlob* vs_blob = 0, *fs_blob = 0; - if (desc->vs.byte_code && desc->fs.byte_code) { + if (desc->vs.bytecode.ptr && desc->fs.bytecode.ptr) { /* create from shader byte code */ - vs_ptr = desc->vs.byte_code; - fs_ptr = desc->fs.byte_code; - vs_length = desc->vs.byte_code_size; - fs_length = desc->fs.byte_code_size; + vs_ptr = desc->vs.bytecode.ptr; + fs_ptr = desc->fs.bytecode.ptr; + vs_length = desc->vs.bytecode.size; + fs_length = desc->fs.bytecode.size; } else { /* compile from shader source code */ @@ -8048,8 +8669,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons /* need to store the vertex shader byte code, this is needed later in sg_create_pipeline */ if (vs_succeeded && fs_succeeded) { - shd->d3d11.vs_blob_length = (int)vs_length; - shd->d3d11.vs_blob = SOKOL_MALLOC((int)vs_length); + shd->d3d11.vs_blob_length = vs_length; + shd->d3d11.vs_blob = SOKOL_MALLOC((size_t)vs_length); SOKOL_ASSERT(shd->d3d11.vs_blob); memcpy(shd->d3d11.vs_blob, vs_ptr, vs_length); result = SG_RESOURCESTATE_VALID; @@ -8097,7 +8718,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, _sg_pipeline_common_init(&pip->cmn, desc); pip->d3d11.index_format = _sg_d3d11_index_format(pip->cmn.index_type); pip->d3d11.topology = _sg_d3d11_primitive_topology(desc->primitive_type); - pip->d3d11.stencil_ref = desc->depth_stencil.stencil_ref; + pip->d3d11.stencil_ref = desc->stencil.ref; /* create input layout object */ HRESULT hr; @@ -8110,19 +8731,19 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, if (a_desc->format == SG_VERTEXFORMAT_INVALID) { break; } - SOKOL_ASSERT((a_desc->buffer_index >= 0) && (a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS)); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[a_desc->buffer_index]; const sg_vertex_step step_func = l_desc->step_func; const int step_rate = l_desc->step_rate; D3D11_INPUT_ELEMENT_DESC* d3d11_comp = &d3d11_comps[attr_index]; d3d11_comp->SemanticName = _sg_strptr(&shd->d3d11.attrs[attr_index].sem_name); - d3d11_comp->SemanticIndex = shd->d3d11.attrs[attr_index].sem_index; + d3d11_comp->SemanticIndex = (UINT)shd->d3d11.attrs[attr_index].sem_index; d3d11_comp->Format = _sg_d3d11_vertex_format(a_desc->format); - d3d11_comp->InputSlot = a_desc->buffer_index; - d3d11_comp->AlignedByteOffset = a_desc->offset; + d3d11_comp->InputSlot = (UINT)a_desc->buffer_index; + d3d11_comp->AlignedByteOffset = (UINT)a_desc->offset; d3d11_comp->InputSlotClass = _sg_d3d11_input_classification(step_func); if (SG_VERTEXSTEP_PER_INSTANCE == step_func) { - d3d11_comp->InstanceDataStepRate = step_rate; + d3d11_comp->InstanceDataStepRate = (UINT)step_rate; } pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; } @@ -8130,7 +8751,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, if (pip->cmn.vertex_layout_valid[layout_index]) { const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[layout_index]; SOKOL_ASSERT(l_desc->stride > 0); - pip->d3d11.vb_strides[layout_index] = l_desc->stride; + pip->d3d11.vb_strides[layout_index] = (UINT)l_desc->stride; } else { pip->d3d11.vb_strides[layout_index] = 0; @@ -8138,7 +8759,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, } hr = _sg_d3d11_CreateInputLayout(_sg.d3d11.dev, d3d11_comps, /* pInputElementDesc */ - attr_index, /* NumElements */ + (UINT)attr_index, /* NumElements */ shd->d3d11.vs_blob, /* pShaderByteCodeWithInputSignature */ shd->d3d11.vs_blob_length, /* BytecodeLength */ &pip->d3d11.il); @@ -8148,14 +8769,14 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, D3D11_RASTERIZER_DESC rs_desc; memset(&rs_desc, 0, sizeof(rs_desc)); rs_desc.FillMode = D3D11_FILL_SOLID; - rs_desc.CullMode = _sg_d3d11_cull_mode(desc->rasterizer.cull_mode); - rs_desc.FrontCounterClockwise = desc->rasterizer.face_winding == SG_FACEWINDING_CCW; + rs_desc.CullMode = _sg_d3d11_cull_mode(desc->cull_mode); + rs_desc.FrontCounterClockwise = desc->face_winding == SG_FACEWINDING_CCW; rs_desc.DepthBias = (INT) pip->cmn.depth_bias; rs_desc.DepthBiasClamp = pip->cmn.depth_bias_clamp; rs_desc.SlopeScaledDepthBias = pip->cmn.depth_bias_slope_scale; rs_desc.DepthClipEnable = TRUE; rs_desc.ScissorEnable = TRUE; - rs_desc.MultisampleEnable = desc->rasterizer.sample_count > 1; + 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); @@ -8164,37 +8785,52 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, D3D11_DEPTH_STENCIL_DESC dss_desc; memset(&dss_desc, 0, sizeof(dss_desc)); dss_desc.DepthEnable = TRUE; - dss_desc.DepthWriteMask = desc->depth_stencil.depth_write_enabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - dss_desc.DepthFunc = _sg_d3d11_compare_func(desc->depth_stencil.depth_compare_func); - dss_desc.StencilEnable = desc->depth_stencil.stencil_enabled; - dss_desc.StencilReadMask = desc->depth_stencil.stencil_read_mask; - dss_desc.StencilWriteMask = desc->depth_stencil.stencil_write_mask; - const sg_stencil_state* sf = &desc->depth_stencil.stencil_front; + dss_desc.DepthWriteMask = desc->depth.write_enabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dss_desc.DepthFunc = _sg_d3d11_compare_func(desc->depth.compare); + dss_desc.StencilEnable = desc->stencil.enabled; + dss_desc.StencilReadMask = desc->stencil.read_mask; + dss_desc.StencilWriteMask = desc->stencil.write_mask; + const sg_stencil_face_state* sf = &desc->stencil.front; dss_desc.FrontFace.StencilFailOp = _sg_d3d11_stencil_op(sf->fail_op); dss_desc.FrontFace.StencilDepthFailOp = _sg_d3d11_stencil_op(sf->depth_fail_op); dss_desc.FrontFace.StencilPassOp = _sg_d3d11_stencil_op(sf->pass_op); - dss_desc.FrontFace.StencilFunc = _sg_d3d11_compare_func(sf->compare_func); - const sg_stencil_state* sb = &desc->depth_stencil.stencil_back; + dss_desc.FrontFace.StencilFunc = _sg_d3d11_compare_func(sf->compare); + const sg_stencil_face_state* sb = &desc->stencil.back; dss_desc.BackFace.StencilFailOp = _sg_d3d11_stencil_op(sb->fail_op); dss_desc.BackFace.StencilDepthFailOp = _sg_d3d11_stencil_op(sb->depth_fail_op); dss_desc.BackFace.StencilPassOp = _sg_d3d11_stencil_op(sb->pass_op); - dss_desc.BackFace.StencilFunc = _sg_d3d11_compare_func(sb->compare_func); + 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); /* create blend state */ D3D11_BLEND_DESC bs_desc; memset(&bs_desc, 0, sizeof(bs_desc)); - bs_desc.AlphaToCoverageEnable = desc->rasterizer.alpha_to_coverage_enabled; - bs_desc.IndependentBlendEnable = FALSE; - bs_desc.RenderTarget[0].BlendEnable = desc->blend.enabled; - bs_desc.RenderTarget[0].SrcBlend = _sg_d3d11_blend_factor(desc->blend.src_factor_rgb); - bs_desc.RenderTarget[0].DestBlend = _sg_d3d11_blend_factor(desc->blend.dst_factor_rgb); - bs_desc.RenderTarget[0].BlendOp = _sg_d3d11_blend_op(desc->blend.op_rgb); - bs_desc.RenderTarget[0].SrcBlendAlpha = _sg_d3d11_blend_factor(desc->blend.src_factor_alpha); - bs_desc.RenderTarget[0].DestBlendAlpha = _sg_d3d11_blend_factor(desc->blend.dst_factor_alpha); - bs_desc.RenderTarget[0].BlendOpAlpha = _sg_d3d11_blend_op(desc->blend.op_alpha); - bs_desc.RenderTarget[0].RenderTargetWriteMask = _sg_d3d11_color_write_mask((sg_color_mask)desc->blend.color_write_mask); + bs_desc.AlphaToCoverageEnable = desc->alpha_to_coverage_enabled; + bs_desc.IndependentBlendEnable = TRUE; + { + int i = 0; + for (i = 0; i < desc->color_count; i++) { + const sg_blend_state* src = &desc->colors[i].blend; + D3D11_RENDER_TARGET_BLEND_DESC* dst = &bs_desc.RenderTarget[i]; + dst->BlendEnable = src->enabled; + dst->SrcBlend = _sg_d3d11_blend_factor(src->src_factor_rgb); + dst->DestBlend = _sg_d3d11_blend_factor(src->dst_factor_rgb); + dst->BlendOp = _sg_d3d11_blend_op(src->op_rgb); + dst->SrcBlendAlpha = _sg_d3d11_blend_factor(src->src_factor_alpha); + dst->DestBlendAlpha = _sg_d3d11_blend_factor(src->dst_factor_alpha); + dst->BlendOpAlpha = _sg_d3d11_blend_op(src->op_alpha); + dst->RenderTargetWriteMask = _sg_d3d11_color_write_mask(desc->colors[i].write_mask); + } + for (; i < 8; i++) { + D3D11_RENDER_TARGET_BLEND_DESC* dst = &bs_desc.RenderTarget[i]; + dst->BlendEnable = FALSE; + dst->SrcBlend = dst->SrcBlendAlpha = D3D11_BLEND_ONE; + dst->DestBlend = dst->DestBlendAlpha = D3D11_BLEND_ZERO; + dst->BlendOp = dst->BlendOpAlpha = D3D11_BLEND_OP_ADD; + dst->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + } hr = _sg_d3d11_CreateBlendState(_sg.d3d11.dev, &bs_desc, &pip->d3d11.bs); SOKOL_ASSERT(SUCCEEDED(hr) && pip->d3d11.bs); @@ -8225,7 +8861,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima _sg_pass_common_init(&pass->cmn, desc); for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const sg_attachment_desc* att_desc = &desc->color_attachments[i]; + const sg_pass_attachment_desc* att_desc = &desc->color_attachments[i]; _SOKOL_UNUSED(att_desc); SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); _sg_image_t* att_img = att_images[i]; @@ -8235,7 +8871,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima pass->d3d11.color_atts[i].image = att_img; /* create D3D11 render-target-view */ - const _sg_attachment_t* cmn_att = &pass->cmn.color_atts[i]; + const _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i]; SOKOL_ASSERT(0 == pass->d3d11.color_atts[i].rtv); ID3D11Resource* d3d11_res = 0; const bool is_msaa = att_img->cmn.sample_count > 1; @@ -8250,22 +8886,22 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima else { d3d11_res = (ID3D11Resource*) att_img->d3d11.tex2d; d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - d3d11_rtv_desc.Texture2D.MipSlice = cmn_att->mip_level; + d3d11_rtv_desc.Texture2D.MipSlice = (UINT)cmn_att->mip_level; } } else if ((att_img->cmn.type == SG_IMAGETYPE_CUBE) || (att_img->cmn.type == SG_IMAGETYPE_ARRAY)) { d3d11_res = (ID3D11Resource*) att_img->d3d11.tex2d; d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - d3d11_rtv_desc.Texture2DArray.MipSlice = cmn_att->mip_level; - d3d11_rtv_desc.Texture2DArray.FirstArraySlice = cmn_att->slice; + d3d11_rtv_desc.Texture2DArray.MipSlice = (UINT)cmn_att->mip_level; + d3d11_rtv_desc.Texture2DArray.FirstArraySlice = (UINT)cmn_att->slice; d3d11_rtv_desc.Texture2DArray.ArraySize = 1; } else { SOKOL_ASSERT(att_img->cmn.type == SG_IMAGETYPE_3D); d3d11_res = (ID3D11Resource*) att_img->d3d11.tex3d; d3d11_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - d3d11_rtv_desc.Texture3D.MipSlice = cmn_att->mip_level; - d3d11_rtv_desc.Texture3D.FirstWSlice = cmn_att->slice; + d3d11_rtv_desc.Texture3D.MipSlice = (UINT)cmn_att->mip_level; + d3d11_rtv_desc.Texture3D.FirstWSlice = (UINT)cmn_att->slice; d3d11_rtv_desc.Texture3D.WSize = 1; } SOKOL_ASSERT(d3d11_res); @@ -8279,7 +8915,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima SOKOL_ASSERT(0 == pass->d3d11.ds_att.dsv); if (desc->depth_stencil_attachment.image.id != SG_INVALID_ID) { const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS; - const sg_attachment_desc* att_desc = &desc->depth_stencil_attachment; + const sg_pass_attachment_desc* att_desc = &desc->depth_stencil_attachment; _SOKOL_UNUSED(att_desc); _sg_image_t* att_img = att_images[ds_img_index]; SOKOL_ASSERT(att_img && (att_img->slot.id == att_desc->image.id)); @@ -8393,7 +9029,7 @@ _SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* /* perform clear action */ for (int i = 0; i < _sg.d3d11.num_rtvs; i++) { if (action->colors[i].action == SG_ACTION_CLEAR) { - _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, _sg.d3d11.cur_rtvs[i], action->colors[i].val); + _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, _sg.d3d11.cur_rtvs[i], &action->colors[i].value.r); } } UINT ds_flags = 0; @@ -8404,7 +9040,7 @@ _SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* ds_flags |= D3D11_CLEAR_STENCIL; } if ((0 != ds_flags) && _sg.d3d11.cur_dsv) { - _sg_d3d11_ClearDepthStencilView(_sg.d3d11.ctx, _sg.d3d11.cur_dsv, ds_flags, action->depth.val, action->stencil.val); + _sg_d3d11_ClearDepthStencilView(_sg.d3d11.ctx, _sg.d3d11.cur_dsv, ds_flags, action->depth.value, action->stencil.value); } } @@ -8421,14 +9057,14 @@ _SOKOL_PRIVATE void _sg_d3d11_end_pass(void) { if (_sg.d3d11.cur_pass) { SOKOL_ASSERT(_sg.d3d11.cur_pass->slot.id == _sg.d3d11.cur_pass_id.id); for (int i = 0; i < _sg.d3d11.num_rtvs; i++) { - _sg_attachment_t* cmn_att = &_sg.d3d11.cur_pass->cmn.color_atts[i]; + _sg_pass_attachment_t* cmn_att = &_sg.d3d11.cur_pass->cmn.color_atts[i]; _sg_image_t* att_img = _sg.d3d11.cur_pass->d3d11.color_atts[i].image; SOKOL_ASSERT(att_img && (att_img->slot.id == cmn_att->image_id.id)); if (att_img->cmn.sample_count > 1) { /* FIXME: support MSAA resolve into 3D texture */ SOKOL_ASSERT(att_img->d3d11.tex2d && att_img->d3d11.texmsaa && !att_img->d3d11.tex3d); SOKOL_ASSERT(DXGI_FORMAT_UNKNOWN != att_img->d3d11.format); - UINT dst_subres = _sg_d3d11_calcsubresource(cmn_att->mip_level, cmn_att->slice, att_img->cmn.num_mipmaps); + UINT dst_subres = _sg_d3d11_calcsubresource((UINT)cmn_att->mip_level, (UINT)cmn_att->slice, (UINT)att_img->cmn.num_mipmaps); _sg_d3d11_ResolveSubresource(_sg.d3d11.ctx, (ID3D11Resource*) att_img->d3d11.tex2d, /* pDstResource */ dst_subres, /* DstSubresource */ @@ -8486,7 +9122,7 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) { _sg_d3d11_RSSetState(_sg.d3d11.ctx, pip->d3d11.rs); _sg_d3d11_OMSetDepthStencilState(_sg.d3d11.ctx, pip->d3d11.dss, pip->d3d11.stencil_ref); - _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, pip->d3d11.bs, pip->cmn.blend_color, 0xFFFFFFFF); + _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, pip->d3d11.bs, &pip->cmn.blend_color.r, 0xFFFFFFFF); _sg_d3d11_IASetPrimitiveTopology(_sg.d3d11.ctx, pip->d3d11.topology); _sg_d3d11_IASetInputLayout(_sg.d3d11.ctx, pip->d3d11.il); _sg_d3d11_VSSetShader(_sg.d3d11.ctx, pip->shader->d3d11.vs, NULL, 0); @@ -8518,7 +9154,7 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_bindings( for (i = 0; i < num_vbs; i++) { SOKOL_ASSERT(vbs[i]->d3d11.buf); d3d11_vbs[i] = vbs[i]->d3d11.buf; - d3d11_vb_offsets[i] = vb_offsets[i]; + d3d11_vb_offsets[i] = (UINT)vb_offsets[i]; } for (; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) { d3d11_vbs[i] = 0; @@ -8546,44 +9182,40 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_bindings( } _sg_d3d11_IASetVertexBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_BUFFERS, d3d11_vbs, pip->d3d11.vb_strides, d3d11_vb_offsets); - _sg_d3d11_IASetIndexBuffer(_sg.d3d11.ctx, d3d11_ib, pip->d3d11.index_format, ib_offset); + _sg_d3d11_IASetIndexBuffer(_sg.d3d11.ctx, d3d11_ib, pip->d3d11.index_format, (UINT)ib_offset); _sg_d3d11_VSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_vs_srvs); _sg_d3d11_VSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_vs_smps); _sg_d3d11_PSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_fs_srvs); _sg_d3d11_PSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_fs_smps); } -_SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { - _SOKOL_UNUSED(num_bytes); +_SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.d3d11.ctx && _sg.d3d11.in_pass); - SOKOL_ASSERT(data && (num_bytes > 0)); - SOKOL_ASSERT((stage_index >= 0) && ((int)stage_index < SG_NUM_SHADER_STAGES)); - SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); SOKOL_ASSERT(_sg.d3d11.cur_pipeline && _sg.d3d11.cur_pipeline->slot.id == _sg.d3d11.cur_pipeline_id.id); SOKOL_ASSERT(_sg.d3d11.cur_pipeline->shader && _sg.d3d11.cur_pipeline->shader->slot.id == _sg.d3d11.cur_pipeline->cmn.shader_id.id); SOKOL_ASSERT(ub_index < _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); - SOKOL_ASSERT(num_bytes == _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); + SOKOL_ASSERT(data->size == _sg.d3d11.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); ID3D11Buffer* cb = _sg.d3d11.cur_pipeline->shader->d3d11.stage[stage_index].cbufs[ub_index]; SOKOL_ASSERT(cb); - _sg_d3d11_UpdateSubresource(_sg.d3d11.ctx, (ID3D11Resource*)cb, 0, NULL, data, 0, 0); + _sg_d3d11_UpdateSubresource(_sg.d3d11.ctx, (ID3D11Resource*)cb, 0, NULL, data->ptr, 0, 0); } _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, num_elements, base_element, 0); + _sg_d3d11_DrawIndexed(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element, 0); } else { - _sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, num_elements, num_instances, base_element, 0, 0); + _sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0, 0); } } else { if (1 == num_instances) { - _sg_d3d11_Draw(_sg.d3d11.ctx, num_elements, base_element); + _sg_d3d11_Draw(_sg.d3d11.ctx, (UINT)num_elements, (UINT)base_element); } else { - _sg_d3d11_DrawInstanced(_sg.d3d11.ctx, num_elements, num_instances, base_element, 0); + _sg_d3d11_DrawInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0); } } } @@ -8592,20 +9224,20 @@ _SOKOL_PRIVATE void _sg_d3d11_commit(void) { SOKOL_ASSERT(!_sg.d3d11.in_pass); } -_SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const void* data_ptr, uint32_t data_size) { - SOKOL_ASSERT(buf && data_ptr && (data_size > 0)); +_SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); SOKOL_ASSERT(_sg.d3d11.ctx); 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)); - memcpy(d3d11_msr.pData, data_ptr, data_size); + memcpy(d3d11_msr.pData, data->ptr, data->size); _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); } -_SOKOL_PRIVATE uint32_t _sg_d3d11_append_buffer(_sg_buffer_t* buf, const void* data_ptr, uint32_t data_size, bool new_frame) { - SOKOL_ASSERT(buf && data_ptr && (data_size > 0)); +_SOKOL_PRIVATE int _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); SOKOL_ASSERT(_sg.d3d11.ctx); SOKOL_ASSERT(buf->d3d11.buf); D3D11_MAP map_type = new_frame ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE; @@ -8614,13 +9246,13 @@ _SOKOL_PRIVATE uint32_t _sg_d3d11_append_buffer(_sg_buffer_t* buf, const void* d _SOKOL_UNUSED(hr); SOKOL_ASSERT(SUCCEEDED(hr)); uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData + buf->cmn.append_pos; - memcpy(dst_ptr, data_ptr, data_size); + 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 */ - return _sg_roundup(data_size, 4); + return _sg_roundup((int)data->size, 4); } -_SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_content* data) { +_SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(img && data); SOKOL_ASSERT(_sg.d3d11.ctx); SOKOL_ASSERT(img->d3d11.tex2d || img->d3d11.tex3d); @@ -8633,8 +9265,8 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_cont } SOKOL_ASSERT(d3d11_res); const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.depth:1; - int subres_index = 0; + 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; @@ -8645,10 +9277,10 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_cont const int mip_width = ((img->cmn.width>>mip_index)>0) ? img->cmn.width>>mip_index : 1; const int mip_height = ((img->cmn.height>>mip_index)>0) ? img->cmn.height>>mip_index : 1; const int src_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); - const sg_subimage_content* subimg_content = &(data->subimage[face_index][mip_index]); - const int slice_size = subimg_content->size / num_slices; - const int slice_offset = slice_size * slice_index; - const uint8_t* slice_ptr = ((const uint8_t*)subimg_content->ptr) + slice_offset; + const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); + const size_t slice_size = subimg_data->size / (size_t)num_slices; + 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)); /* FIXME: need to handle difference in depth-pitch for 3D textures as well! */ @@ -8660,7 +9292,7 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_cont const uint8_t* src_ptr = slice_ptr; uint8_t* dst_ptr = (uint8_t*) d3d11_msr.pData; for (int row_index = 0; row_index < mip_height; row_index++) { - memcpy(dst_ptr, src_ptr, src_pitch); + memcpy(dst_ptr, src_ptr, (size_t)src_pitch); src_ptr += src_pitch; dst_ptr += d3d11_msr.RowPitch; } @@ -8920,7 +9552,7 @@ _SOKOL_PRIVATE MTLIndexType _sg_mtl_index_type(sg_index_type t) { } } -_SOKOL_PRIVATE NSUInteger _sg_mtl_index_size(sg_index_type t) { +_SOKOL_PRIVATE int _sg_mtl_index_size(sg_index_type t) { switch (t) { case SG_INDEXTYPE_NONE: return 0; case SG_INDEXTYPE_UINT16: return 2; @@ -9019,19 +9651,19 @@ _SOKOL_PRIVATE void _sg_mtl_init_pool(const sg_desc* desc) { 2 * desc->pipeline_pool_size + desc->pass_pool_size ); - _sg.mtl.idpool.pool = [NSMutableArray arrayWithCapacity:_sg.mtl.idpool.num_slots]; + _sg.mtl.idpool.pool = [NSMutableArray arrayWithCapacity:(NSUInteger)_sg.mtl.idpool.num_slots]; _SG_OBJC_RETAIN(_sg.mtl.idpool.pool); NSNull* null = [NSNull null]; - for (uint32_t i = 0; i < _sg.mtl.idpool.num_slots; i++) { + for (int i = 0; i < _sg.mtl.idpool.num_slots; i++) { [_sg.mtl.idpool.pool addObject:null]; } - SOKOL_ASSERT([_sg.mtl.idpool.pool count] == _sg.mtl.idpool.num_slots); + SOKOL_ASSERT([_sg.mtl.idpool.pool count] == (NSUInteger)_sg.mtl.idpool.num_slots); /* a queue of currently free slot indices */ _sg.mtl.idpool.free_queue_top = 0; - _sg.mtl.idpool.free_queue = (uint32_t*)SOKOL_MALLOC(_sg.mtl.idpool.num_slots * sizeof(uint32_t)); + _sg.mtl.idpool.free_queue = (int*)SOKOL_MALLOC((size_t)_sg.mtl.idpool.num_slots * sizeof(int)); /* pool slot 0 is reserved! */ for (int i = _sg.mtl.idpool.num_slots-1; i >= 1; i--) { - _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = (uint32_t)i; + _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = i; } /* a circular queue which holds release items (frame index when a resource is to be released, and the resource's @@ -9039,8 +9671,8 @@ _SOKOL_PRIVATE void _sg_mtl_init_pool(const sg_desc* desc) { */ _sg.mtl.idpool.release_queue_front = 0; _sg.mtl.idpool.release_queue_back = 0; - _sg.mtl.idpool.release_queue = (_sg_mtl_release_item_t*)SOKOL_MALLOC(_sg.mtl.idpool.num_slots * sizeof(_sg_mtl_release_item_t)); - for (uint32_t i = 0; i < _sg.mtl.idpool.num_slots; i++) { + _sg.mtl.idpool.release_queue = (_sg_mtl_release_item_t*)SOKOL_MALLOC((size_t)_sg.mtl.idpool.num_slots * sizeof(_sg_mtl_release_item_t)); + for (int i = 0; i < _sg.mtl.idpool.num_slots; i++) { _sg.mtl.idpool.release_queue[i].frame_index = 0; _sg.mtl.idpool.release_queue[i].slot_index = _SG_MTL_INVALID_SLOT_INDEX; } @@ -9053,28 +9685,28 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_pool(void) { } /* get a new free resource pool slot */ -_SOKOL_PRIVATE uint32_t _sg_mtl_alloc_pool_slot(void) { +_SOKOL_PRIVATE int _sg_mtl_alloc_pool_slot(void) { SOKOL_ASSERT(_sg.mtl.idpool.free_queue_top > 0); - const uint32_t slot_index = _sg.mtl.idpool.free_queue[--_sg.mtl.idpool.free_queue_top]; + const int slot_index = _sg.mtl.idpool.free_queue[--_sg.mtl.idpool.free_queue_top]; SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); return slot_index; } /* put a free resource pool slot back into the free-queue */ -_SOKOL_PRIVATE void _sg_mtl_free_pool_slot(uint32_t slot_index) { +_SOKOL_PRIVATE void _sg_mtl_free_pool_slot(int slot_index) { SOKOL_ASSERT(_sg.mtl.idpool.free_queue_top < _sg.mtl.idpool.num_slots); SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); _sg.mtl.idpool.free_queue[_sg.mtl.idpool.free_queue_top++] = slot_index; } /* add an MTLResource to the pool, return pool index or 0 if input was 'nil' */ -_SOKOL_PRIVATE uint32_t _sg_mtl_add_resource(id res) { +_SOKOL_PRIVATE int _sg_mtl_add_resource(id res) { if (nil == res) { return _SG_MTL_INVALID_SLOT_INDEX; } - const uint32_t slot_index = _sg_mtl_alloc_pool_slot(); - SOKOL_ASSERT([NSNull null] == _sg.mtl.idpool.pool[slot_index]); - _sg.mtl.idpool.pool[slot_index] = res; + const int slot_index = _sg_mtl_alloc_pool_slot(); + SOKOL_ASSERT([NSNull null] == _sg.mtl.idpool.pool[(NSUInteger)slot_index]); + _sg.mtl.idpool.pool[(NSUInteger)slot_index] = res; return slot_index; } @@ -9083,12 +9715,12 @@ _SOKOL_PRIVATE uint32_t _sg_mtl_add_resource(id res) { the special pool index 0 will be ignored (this means that a nil value was provided to _sg_mtl_add_resource() */ -_SOKOL_PRIVATE void _sg_mtl_release_resource(uint32_t frame_index, uint32_t slot_index) { +_SOKOL_PRIVATE void _sg_mtl_release_resource(uint32_t frame_index, int slot_index) { if (slot_index == _SG_MTL_INVALID_SLOT_INDEX) { return; } SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); - SOKOL_ASSERT([NSNull null] != _sg.mtl.idpool.pool[slot_index]); + SOKOL_ASSERT([NSNull null] != _sg.mtl.idpool.pool[(NSUInteger)slot_index]); int release_index = _sg.mtl.idpool.release_queue_front++; if (_sg.mtl.idpool.release_queue_front >= _sg.mtl.idpool.num_slots) { /* wrap-around */ @@ -9110,10 +9742,10 @@ _SOKOL_PRIVATE void _sg_mtl_garbage_collect(uint32_t frame_index) { break; } /* safe to release this resource */ - const uint32_t slot_index = _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].slot_index; + const int slot_index = _sg.mtl.idpool.release_queue[_sg.mtl.idpool.release_queue_back].slot_index; SOKOL_ASSERT((slot_index > 0) && (slot_index < _sg.mtl.idpool.num_slots)); - SOKOL_ASSERT(_sg.mtl.idpool.pool[slot_index] != [NSNull null]); - _SG_OBJC_RELEASE_WITH_NULL(_sg.mtl.idpool.pool[slot_index]); + SOKOL_ASSERT(_sg.mtl.idpool.pool[(NSUInteger)slot_index] != [NSNull null]); + _SG_OBJC_RELEASE_WITH_NULL(_sg.mtl.idpool.pool[(NSUInteger)slot_index]); /* put the now free pool index back on the free queue */ _sg_mtl_free_pool_slot(slot_index); /* reset the release queue slot and advance the back index */ @@ -9127,8 +9759,8 @@ _SOKOL_PRIVATE void _sg_mtl_garbage_collect(uint32_t frame_index) { } } -_SOKOL_PRIVATE id _sg_mtl_id(uint32_t slot_index) { - return _sg.mtl.idpool.pool[slot_index]; +_SOKOL_PRIVATE id _sg_mtl_id(int slot_index) { + return _sg.mtl.idpool.pool[(NSUInteger)slot_index]; } _SOKOL_PRIVATE void _sg_mtl_init_sampler_cache(const sg_desc* desc) { @@ -9141,7 +9773,7 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_sampler_cache(uint32_t frame_index) { SOKOL_ASSERT(_sg.mtl.sampler_cache.items); SOKOL_ASSERT(_sg.mtl.sampler_cache.num_items <= _sg.mtl.sampler_cache.capacity); for (int i = 0; i < _sg.mtl.sampler_cache.num_items; i++) { - _sg_mtl_release_resource(frame_index, (uint32_t)_sg_smpcache_sampler(&_sg.mtl.sampler_cache, i)); + _sg_mtl_release_resource(frame_index, (int)_sg_smpcache_sampler(&_sg.mtl.sampler_cache, i)); } _sg_smpcache_discard(&_sg.mtl.sampler_cache); } @@ -9150,12 +9782,12 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_sampler_cache(uint32_t frame_index) { create and add an MTLSamplerStateObject and return its resource pool index, reuse identical sampler state if one exists */ -_SOKOL_PRIVATE uint32_t _sg_mtl_create_sampler(id mtl_device, const sg_image_desc* img_desc) { +_SOKOL_PRIVATE int _sg_mtl_create_sampler(id mtl_device, const sg_image_desc* img_desc) { SOKOL_ASSERT(img_desc); int index = _sg_smpcache_find_item(&_sg.mtl.sampler_cache, img_desc); if (index >= 0) { /* reuse existing sampler */ - return (uint32_t) _sg_smpcache_sampler(&_sg.mtl.sampler_cache, index); + return (int)_sg_smpcache_sampler(&_sg.mtl.sampler_cache, index); } else { /* create a new Metal sampler state object and add to sampler cache */ @@ -9177,8 +9809,8 @@ _SOKOL_PRIVATE uint32_t _sg_mtl_create_sampler(id mtl_device, const s mtl_desc.normalizedCoordinates = YES; id mtl_sampler = [mtl_device newSamplerStateWithDescriptor:mtl_desc]; _SG_OBJC_RELEASE(mtl_desc); - uint32_t sampler_handle = _sg_mtl_add_resource(mtl_sampler); - _sg_smpcache_add_item(&_sg.mtl.sampler_cache, img_desc, sampler_handle); + int sampler_handle = _sg_mtl_add_resource(mtl_sampler); + _sg_smpcache_add_item(&_sg.mtl.sampler_cache, img_desc, (uintptr_t)sampler_handle); return sampler_handle; } } @@ -9209,6 +9841,8 @@ _SOKOL_PRIVATE void _sg_mtl_init_caps(void) { #else _sg.features.image_clamp_to_border = false; #endif + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; #if defined(_SG_TARGET_MACOS) _sg.limits.max_image_size_2d = 16 * 1024; @@ -9353,7 +9987,7 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { #endif for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { _sg.mtl.uniform_buffers[i] = [_sg.mtl.device - newBufferWithLength:_sg.mtl.ub_size + newBufferWithLength:(NSUInteger)_sg.mtl.ub_size options:res_opts ]; } @@ -9392,11 +10026,11 @@ _SOKOL_PRIVATE void _sg_mtl_bind_uniform_buffers(void) { [_sg.mtl.cmd_encoder setVertexBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] offset:0 - atIndex:slot]; + atIndex:(NSUInteger)slot]; [_sg.mtl.cmd_encoder setFragmentBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] offset:0 - atIndex:slot]; + atIndex:(NSUInteger)slot]; } } @@ -9441,11 +10075,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_buffer(_sg_buffer_t* buf, const } else { if (buf->cmn.usage == SG_USAGE_IMMUTABLE) { - SOKOL_ASSERT(desc->content); - mtl_buf = [_sg.mtl.device newBufferWithBytes:desc->content length:buf->cmn.size options:mtl_options]; + SOKOL_ASSERT(desc->data.ptr); + mtl_buf = [_sg.mtl.device newBufferWithBytes:desc->data.ptr length:(NSUInteger)buf->cmn.size options:mtl_options]; } else { - mtl_buf = [_sg.mtl.device newBufferWithLength:buf->cmn.size options:mtl_options]; + mtl_buf = [_sg.mtl.device newBufferWithLength:(NSUInteger)buf->cmn.size options:mtl_options]; } } buf->mtl.buf[slot] = _sg_mtl_add_resource(mtl_buf); @@ -9461,14 +10095,14 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_buffer(_sg_buffer_t* buf) { } } -_SOKOL_PRIVATE void _sg_mtl_copy_image_content(const _sg_image_t* img, __unsafe_unretained id mtl_tex, const sg_image_content* content) { +_SOKOL_PRIVATE void _sg_mtl_copy_image_data(const _sg_image_t* img, __unsafe_unretained id mtl_tex, const sg_image_data* data) { const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.depth : 1; + const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; for (int face_index = 0; face_index < num_faces; face_index++) { for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { - SOKOL_ASSERT(content->subimage[face_index][mip_index].ptr); - SOKOL_ASSERT(content->subimage[face_index][mip_index].size > 0); - const uint8_t* data_ptr = (const uint8_t*)content->subimage[face_index][mip_index].ptr; + SOKOL_ASSERT(data->subimage[face_index][mip_index].ptr); + SOKOL_ASSERT(data->subimage[face_index][mip_index].size > 0); + 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 */ @@ -9479,24 +10113,24 @@ _SOKOL_PRIVATE void _sg_mtl_copy_image_content(const _sg_image_t* img, __unsafe_ } MTLRegion region; if (img->cmn.type == SG_IMAGETYPE_3D) { - const int mip_depth = _sg_max(img->cmn.depth >> mip_index, 1); - region = MTLRegionMake3D(0, 0, 0, mip_width, mip_height, mip_depth); + 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); /* FIXME: apparently the minimal bytes_per_image size for 3D texture is 4 KByte... somehow need to handle this */ } else { - region = MTLRegionMake2D(0, 0, mip_width, mip_height); + region = MTLRegionMake2D(0, 0, (NSUInteger)mip_width, (NSUInteger)mip_height); } 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; - SOKOL_ASSERT((slice_offset + bytes_per_slice) <= (int)content->subimage[face_index][mip_index].size); + SOKOL_ASSERT((slice_offset + bytes_per_slice) <= (int)data->subimage[face_index][mip_index].size); [mtl_tex replaceRegion:region - mipmapLevel:mip_index - slice:mtl_slice_index + mipmapLevel:(NSUInteger)mip_index + slice:(NSUInteger)mtl_slice_index withBytes:data_ptr + slice_offset - bytesPerRow:bytes_per_row - bytesPerImage:bytes_per_slice]; + bytesPerRow:(NSUInteger)bytes_per_row + bytesPerImage:(NSUInteger)bytes_per_slice]; } } } @@ -9525,17 +10159,17 @@ _SOKOL_PRIVATE bool _sg_mtl_init_texdesc_common(MTLTextureDescriptor* mtl_desc, SOKOL_LOG("Unsupported texture pixel format!\n"); return false; } - mtl_desc.width = img->cmn.width; - mtl_desc.height = img->cmn.height; + mtl_desc.width = (NSUInteger)img->cmn.width; + mtl_desc.height = (NSUInteger)img->cmn.height; if (SG_IMAGETYPE_3D == img->cmn.type) { - mtl_desc.depth = img->cmn.depth; + mtl_desc.depth = (NSUInteger)img->cmn.num_slices; } else { mtl_desc.depth = 1; } - mtl_desc.mipmapLevelCount = img->cmn.num_mipmaps; + mtl_desc.mipmapLevelCount = (NSUInteger)img->cmn.num_mipmaps; if (SG_IMAGETYPE_ARRAY == img->cmn.type) { - mtl_desc.arrayLength = img->cmn.depth; + mtl_desc.arrayLength = (NSUInteger)img->cmn.num_slices; } else { mtl_desc.arrayLength = 1; @@ -9583,7 +10217,7 @@ _SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt_msaa(MTLTextureDescriptor* mtl_desc, mtl_desc.depth = 1; mtl_desc.arrayLength = 1; mtl_desc.mipmapLevelCount = 1; - mtl_desc.sampleCount = img->cmn.sample_count; + mtl_desc.sampleCount = (NSUInteger)img->cmn.sample_count; } _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_image(_sg_image_t* img, const sg_image_desc* desc) { @@ -9645,7 +10279,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_image(_sg_image_t* img, const sg else { tex = [_sg.mtl.device newTextureWithDescriptor:mtl_desc]; if ((img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { - _sg_mtl_copy_image_content(img, tex, &desc->content); + _sg_mtl_copy_image_data(img, tex, &desc->data); } } img->mtl.tex[slot] = _sg_mtl_add_resource(tex); @@ -9689,7 +10323,7 @@ _SOKOL_PRIVATE id _sg_mtl_compile_library(const char* src) { return lib; } -_SOKOL_PRIVATE id _sg_mtl_library_from_bytecode(const uint8_t* ptr, int num_bytes) { +_SOKOL_PRIVATE id _sg_mtl_library_from_bytecode(const void* ptr, size_t num_bytes) { NSError* err = NULL; dispatch_data_t lib_data = dispatch_data_create(ptr, num_bytes, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT); id lib = [_sg.mtl.device newLibraryWithData:lib_data error:&err]; @@ -9712,10 +10346,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_shader(_sg_shader_t* shd, const id fs_func; const char* vs_entry = desc->vs.entry; const char* fs_entry = desc->fs.entry; - if (desc->vs.byte_code && desc->fs.byte_code) { + if (desc->vs.bytecode.ptr && desc->fs.bytecode.ptr) { /* separate byte code provided */ - vs_lib = _sg_mtl_library_from_bytecode(desc->vs.byte_code, desc->vs.byte_code_size); - fs_lib = _sg_mtl_library_from_bytecode(desc->fs.byte_code, desc->fs.byte_code_size); + vs_lib = _sg_mtl_library_from_bytecode(desc->vs.bytecode.ptr, desc->vs.bytecode.size); + fs_lib = _sg_mtl_library_from_bytecode(desc->fs.bytecode.ptr, desc->fs.bytecode.size); if (nil == vs_lib || nil == fs_lib) { return SG_RESOURCESTATE_FAILED; } @@ -9773,31 +10407,31 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s if (SG_INDEXTYPE_NONE != pip->cmn.index_type) { pip->mtl.index_type = _sg_mtl_index_type(pip->cmn.index_type); } - pip->mtl.cull_mode = _sg_mtl_cull_mode(desc->rasterizer.cull_mode); - pip->mtl.winding = _sg_mtl_winding(desc->rasterizer.face_winding); - pip->mtl.stencil_ref = desc->depth_stencil.stencil_ref; + pip->mtl.cull_mode = _sg_mtl_cull_mode(desc->cull_mode); + pip->mtl.winding = _sg_mtl_winding(desc->face_winding); + pip->mtl.stencil_ref = desc->stencil.ref; /* create vertex-descriptor */ MTLVertexDescriptor* vtx_desc = [MTLVertexDescriptor vertexDescriptor]; - for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { + for (NSUInteger attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index]; if (a_desc->format == SG_VERTEXFORMAT_INVALID) { break; } - SOKOL_ASSERT((a_desc->buffer_index >= 0) && (a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS)); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); vtx_desc.attributes[attr_index].format = _sg_mtl_vertex_format(a_desc->format); - vtx_desc.attributes[attr_index].offset = a_desc->offset; - vtx_desc.attributes[attr_index].bufferIndex = a_desc->buffer_index + SG_MAX_SHADERSTAGE_UBS; + vtx_desc.attributes[attr_index].offset = (NSUInteger)a_desc->offset; + vtx_desc.attributes[attr_index].bufferIndex = (NSUInteger)(a_desc->buffer_index + SG_MAX_SHADERSTAGE_UBS); pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; } - for (int layout_index = 0; layout_index < SG_MAX_SHADERSTAGE_BUFFERS; layout_index++) { + for (NSUInteger layout_index = 0; layout_index < SG_MAX_SHADERSTAGE_BUFFERS; layout_index++) { if (pip->cmn.vertex_layout_valid[layout_index]) { const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[layout_index]; - const int mtl_vb_slot = layout_index + SG_MAX_SHADERSTAGE_UBS; + const NSUInteger mtl_vb_slot = layout_index + SG_MAX_SHADERSTAGE_UBS; SOKOL_ASSERT(l_desc->stride > 0); - vtx_desc.layouts[mtl_vb_slot].stride = l_desc->stride; + 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 = l_desc->step_rate; + vtx_desc.layouts[mtl_vb_slot].stepRate = (NSUInteger)l_desc->step_rate; } } @@ -9808,13 +10442,13 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s rp_desc.vertexFunction = _sg_mtl_id(shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); SOKOL_ASSERT(shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func != _SG_MTL_INVALID_SLOT_INDEX); rp_desc.fragmentFunction = _sg_mtl_id(shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); - rp_desc.sampleCount = desc->rasterizer.sample_count; - rp_desc.alphaToCoverageEnabled = desc->rasterizer.alpha_to_coverage_enabled; + rp_desc.sampleCount = (NSUInteger)desc->sample_count; + rp_desc.alphaToCoverageEnabled = desc->alpha_to_coverage_enabled; rp_desc.alphaToOneEnabled = NO; rp_desc.rasterizationEnabled = YES; - rp_desc.depthAttachmentPixelFormat = _sg_mtl_pixel_format(desc->blend.depth_format); - if (desc->blend.depth_format == SG_PIXELFORMAT_DEPTH_STENCIL) { - rp_desc.stencilAttachmentPixelFormat = _sg_mtl_pixel_format(desc->blend.depth_format); + rp_desc.depthAttachmentPixelFormat = _sg_mtl_pixel_format(desc->depth.pixel_format); + if (desc->depth.pixel_format == SG_PIXELFORMAT_DEPTH_STENCIL) { + rp_desc.stencilAttachmentPixelFormat = _sg_mtl_pixel_format(desc->depth.pixel_format); } /* FIXME: this only works on macOS 10.13! for (int i = 0; i < (SG_MAX_SHADERSTAGE_UBS+SG_MAX_SHADERSTAGE_BUFFERS); i++) { @@ -9824,17 +10458,18 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s rp_desc.fragmentBuffers[i].mutability = MTLMutabilityImmutable; } */ - const int att_count = desc->blend.color_attachment_count; - for (int i = 0; i < att_count; i++) { - rp_desc.colorAttachments[i].pixelFormat = _sg_mtl_pixel_format(desc->blend.color_format); - rp_desc.colorAttachments[i].writeMask = _sg_mtl_color_write_mask((sg_color_mask)desc->blend.color_write_mask); - rp_desc.colorAttachments[i].blendingEnabled = desc->blend.enabled; - rp_desc.colorAttachments[i].alphaBlendOperation = _sg_mtl_blend_op(desc->blend.op_alpha); - rp_desc.colorAttachments[i].rgbBlendOperation = _sg_mtl_blend_op(desc->blend.op_rgb); - rp_desc.colorAttachments[i].destinationAlphaBlendFactor = _sg_mtl_blend_factor(desc->blend.dst_factor_alpha); - rp_desc.colorAttachments[i].destinationRGBBlendFactor = _sg_mtl_blend_factor(desc->blend.dst_factor_rgb); - rp_desc.colorAttachments[i].sourceAlphaBlendFactor = _sg_mtl_blend_factor(desc->blend.src_factor_alpha); - rp_desc.colorAttachments[i].sourceRGBBlendFactor = _sg_mtl_blend_factor(desc->blend.src_factor_rgb); + for (NSUInteger i = 0; i < (NSUInteger)desc->color_count; i++) { + SOKOL_ASSERT(i < SG_MAX_COLOR_ATTACHMENTS); + const sg_color_state* cs = &desc->colors[i]; + rp_desc.colorAttachments[i].pixelFormat = _sg_mtl_pixel_format(cs->pixel_format); + rp_desc.colorAttachments[i].writeMask = _sg_mtl_color_write_mask(cs->write_mask); + rp_desc.colorAttachments[i].blendingEnabled = cs->blend.enabled; + rp_desc.colorAttachments[i].alphaBlendOperation = _sg_mtl_blend_op(cs->blend.op_alpha); + rp_desc.colorAttachments[i].rgbBlendOperation = _sg_mtl_blend_op(cs->blend.op_rgb); + rp_desc.colorAttachments[i].destinationAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.dst_factor_alpha); + rp_desc.colorAttachments[i].destinationRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.dst_factor_rgb); + rp_desc.colorAttachments[i].sourceAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_alpha); + rp_desc.colorAttachments[i].sourceRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_rgb); } NSError* err = NULL; id mtl_rps = [_sg.mtl.device newRenderPipelineStateWithDescriptor:rp_desc error:&err]; @@ -9847,25 +10482,25 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s /* depth-stencil-state */ MTLDepthStencilDescriptor* ds_desc = [[MTLDepthStencilDescriptor alloc] init]; - ds_desc.depthCompareFunction = _sg_mtl_compare_func(desc->depth_stencil.depth_compare_func); - ds_desc.depthWriteEnabled = desc->depth_stencil.depth_write_enabled; - if (desc->depth_stencil.stencil_enabled) { - const sg_stencil_state* sb = &desc->depth_stencil.stencil_back; + ds_desc.depthCompareFunction = _sg_mtl_compare_func(desc->depth.compare); + ds_desc.depthWriteEnabled = desc->depth.write_enabled; + if (desc->stencil.enabled) { + const sg_stencil_face_state* sb = &desc->stencil.back; ds_desc.backFaceStencil = [[MTLStencilDescriptor alloc] init]; ds_desc.backFaceStencil.stencilFailureOperation = _sg_mtl_stencil_op(sb->fail_op); ds_desc.backFaceStencil.depthFailureOperation = _sg_mtl_stencil_op(sb->depth_fail_op); ds_desc.backFaceStencil.depthStencilPassOperation = _sg_mtl_stencil_op(sb->pass_op); - ds_desc.backFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sb->compare_func); - ds_desc.backFaceStencil.readMask = desc->depth_stencil.stencil_read_mask; - ds_desc.backFaceStencil.writeMask = desc->depth_stencil.stencil_write_mask; - const sg_stencil_state* sf = &desc->depth_stencil.stencil_front; + ds_desc.backFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sb->compare); + ds_desc.backFaceStencil.readMask = desc->stencil.read_mask; + ds_desc.backFaceStencil.writeMask = desc->stencil.write_mask; + const sg_stencil_face_state* sf = &desc->stencil.front; ds_desc.frontFaceStencil = [[MTLStencilDescriptor alloc] init]; ds_desc.frontFaceStencil.stencilFailureOperation = _sg_mtl_stencil_op(sf->fail_op); ds_desc.frontFaceStencil.depthFailureOperation = _sg_mtl_stencil_op(sf->depth_fail_op); ds_desc.frontFaceStencil.depthStencilPassOperation = _sg_mtl_stencil_op(sf->pass_op); - ds_desc.frontFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sf->compare_func); - ds_desc.frontFaceStencil.readMask = desc->depth_stencil.stencil_read_mask; - ds_desc.frontFaceStencil.writeMask = desc->depth_stencil.stencil_write_mask; + ds_desc.frontFaceStencil.stencilCompareFunction = _sg_mtl_compare_func(sf->compare); + ds_desc.frontFaceStencil.readMask = desc->stencil.read_mask; + ds_desc.frontFaceStencil.writeMask = desc->stencil.write_mask; } id mtl_dss = [_sg.mtl.device newDepthStencilStateWithDescriptor:ds_desc]; _SG_OBJC_RELEASE(ds_desc); @@ -9888,7 +10523,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pass(_sg_pass_t* pass, _sg_image _sg_pass_common_init(&pass->cmn, desc); /* copy image pointers */ - const sg_attachment_desc* att_desc; + const sg_pass_attachment_desc* att_desc; for (int i = 0; i < pass->cmn.num_color_atts; i++) { att_desc = &desc->color_attachments[i]; if (att_desc->image.id != SG_INVALID_ID) { @@ -9978,8 +10613,8 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a if (pass) { /* setup pass descriptor for offscreen rendering */ SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_VALID); - for (int i = 0; i < pass->cmn.num_color_atts; i++) { - const _sg_attachment_t* cmn_att = &pass->cmn.color_atts[i]; + for (NSUInteger i = 0; i < (NSUInteger)pass->cmn.num_color_atts; i++) { + const _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i]; const _sg_mtl_attachment_t* mtl_att = &pass->mtl.color_atts[i]; const _sg_image_t* att_img = mtl_att->image; SOKOL_ASSERT(att_img->slot.state == SG_RESOURCESTATE_VALID); @@ -9987,21 +10622,21 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a const bool is_msaa = (att_img->cmn.sample_count > 1); pass_desc.colorAttachments[i].loadAction = _sg_mtl_load_action(action->colors[i].action); pass_desc.colorAttachments[i].storeAction = is_msaa ? MTLStoreActionMultisampleResolve : MTLStoreActionStore; - const float* c = &(action->colors[i].val[0]); - pass_desc.colorAttachments[i].clearColor = MTLClearColorMake(c[0], c[1], c[2], c[3]); + sg_color c = action->colors[i].value; + pass_desc.colorAttachments[i].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); if (is_msaa) { SOKOL_ASSERT(att_img->mtl.msaa_tex != _SG_MTL_INVALID_SLOT_INDEX); SOKOL_ASSERT(att_img->mtl.tex[mtl_att->image->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); pass_desc.colorAttachments[i].texture = _sg_mtl_id(att_img->mtl.msaa_tex); pass_desc.colorAttachments[i].resolveTexture = _sg_mtl_id(att_img->mtl.tex[att_img->cmn.active_slot]); - pass_desc.colorAttachments[i].resolveLevel = cmn_att->mip_level; + pass_desc.colorAttachments[i].resolveLevel = (NSUInteger)cmn_att->mip_level; switch (att_img->cmn.type) { case SG_IMAGETYPE_CUBE: case SG_IMAGETYPE_ARRAY: - pass_desc.colorAttachments[i].resolveSlice = cmn_att->slice; + pass_desc.colorAttachments[i].resolveSlice = (NSUInteger)cmn_att->slice; break; case SG_IMAGETYPE_3D: - pass_desc.colorAttachments[i].resolveDepthPlane = cmn_att->slice; + pass_desc.colorAttachments[i].resolveDepthPlane = (NSUInteger)cmn_att->slice; break; default: break; } @@ -10009,14 +10644,14 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a else { SOKOL_ASSERT(att_img->mtl.tex[att_img->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); pass_desc.colorAttachments[i].texture = _sg_mtl_id(att_img->mtl.tex[att_img->cmn.active_slot]); - pass_desc.colorAttachments[i].level = cmn_att->mip_level; + pass_desc.colorAttachments[i].level = (NSUInteger)cmn_att->mip_level; switch (att_img->cmn.type) { case SG_IMAGETYPE_CUBE: case SG_IMAGETYPE_ARRAY: - pass_desc.colorAttachments[i].slice = cmn_att->slice; + pass_desc.colorAttachments[i].slice = (NSUInteger)cmn_att->slice; break; case SG_IMAGETYPE_3D: - pass_desc.colorAttachments[i].depthPlane = cmn_att->slice; + pass_desc.colorAttachments[i].depthPlane = (NSUInteger)cmn_att->slice; break; default: break; } @@ -10029,23 +10664,23 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a SOKOL_ASSERT(ds_att_img->mtl.depth_tex != _SG_MTL_INVALID_SLOT_INDEX); pass_desc.depthAttachment.texture = _sg_mtl_id(ds_att_img->mtl.depth_tex); pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.action); - pass_desc.depthAttachment.clearDepth = action->depth.val; + pass_desc.depthAttachment.clearDepth = action->depth.value; if (_sg_is_depth_stencil_format(ds_att_img->cmn.pixel_format)) { pass_desc.stencilAttachment.texture = _sg_mtl_id(ds_att_img->mtl.depth_tex); pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.action); - pass_desc.stencilAttachment.clearStencil = action->stencil.val; + pass_desc.stencilAttachment.clearStencil = action->stencil.value; } } } else { /* setup pass descriptor for default rendering */ pass_desc.colorAttachments[0].loadAction = _sg_mtl_load_action(action->colors[0].action); - const float* c = &(action->colors[0].val[0]); - pass_desc.colorAttachments[0].clearColor = MTLClearColorMake(c[0], c[1], c[2], c[3]); + sg_color c = action->colors[0].value; + pass_desc.colorAttachments[0].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); pass_desc.depthAttachment.loadAction = _sg_mtl_load_action(action->depth.action); - pass_desc.depthAttachment.clearDepth = action->depth.val; + pass_desc.depthAttachment.clearDepth = action->depth.value; pass_desc.stencilAttachment.loadAction = _sg_mtl_load_action(action->stencil.action); - pass_desc.stencilAttachment.clearStencil = action->stencil.val; + pass_desc.stencilAttachment.clearStencil = action->stencil.value; } /* create a render command encoder, this might return nil if window is minimized */ @@ -10078,7 +10713,7 @@ _SOKOL_PRIVATE void _sg_mtl_commit(void) { SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer); #if defined(_SG_TARGET_MACOS) - [_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] didModifyRange:NSMakeRange(0, _sg.mtl.cur_ub_offset)]; + [_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] didModifyRange:NSMakeRange(0, (NSUInteger)_sg.mtl.cur_ub_offset)]; #endif /* present, commit and signal semaphore when done */ @@ -10145,10 +10780,10 @@ _SOKOL_PRIVATE void _sg_mtl_apply_scissor_rect(int x, int y, int w, int h, bool h = _sg_max(h, 1); MTLScissorRect r; - r.x = x; - r.y = origin_top_left ? y : (_sg.mtl.cur_height - (y + h)); - r.width = w; - r.height = h; + r.x = (NSUInteger)x; + r.y = (NSUInteger) (origin_top_left ? y : (_sg.mtl.cur_height - (y + h))); + r.width = (NSUInteger)w; + r.height = (NSUInteger)h; [_sg.mtl.cmd_encoder setScissorRect:r]; } @@ -10164,8 +10799,8 @@ _SOKOL_PRIVATE void _sg_mtl_apply_pipeline(_sg_pipeline_t* pip) { if ((_sg.mtl.state_cache.cur_pipeline != pip) || (_sg.mtl.state_cache.cur_pipeline_id.id != pip->slot.id)) { _sg.mtl.state_cache.cur_pipeline = pip; _sg.mtl.state_cache.cur_pipeline_id.id = pip->slot.id; - const float* c = pip->cmn.blend_color; - [_sg.mtl.cmd_encoder setBlendColorRed:c[0] green:c[1] blue:c[2] alpha:c[3]]; + sg_color c = pip->cmn.blend_color; + [_sg.mtl.cmd_encoder setBlendColorRed:c.r green:c.g blue:c.b alpha:c.a]; [_sg.mtl.cmd_encoder setCullMode:pip->mtl.cull_mode]; [_sg.mtl.cmd_encoder setFrontFacingWinding:pip->mtl.winding]; [_sg.mtl.cmd_encoder setStencilReferenceValue:pip->mtl.stencil_ref]; @@ -10204,8 +10839,8 @@ _SOKOL_PRIVATE void _sg_mtl_apply_bindings( } /* apply vertex buffers */ - int slot; - for (slot = 0; slot < num_vbs; slot++) { + NSUInteger slot; + for (slot = 0; slot < (NSUInteger)num_vbs; slot++) { const _sg_buffer_t* vb = vbs[slot]; if ((_sg.mtl.state_cache.cur_vertexbuffers[slot] != vb) || (_sg.mtl.state_cache.cur_vertexbuffer_offsets[slot] != vb_offsets[slot]) || @@ -10217,13 +10852,13 @@ _SOKOL_PRIVATE void _sg_mtl_apply_bindings( const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + slot; SOKOL_ASSERT(vb->mtl.buf[vb->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); [_sg.mtl.cmd_encoder setVertexBuffer:_sg_mtl_id(vb->mtl.buf[vb->cmn.active_slot]) - offset:vb_offsets[slot] + offset:(NSUInteger)vb_offsets[slot] atIndex:mtl_slot]; } } /* apply vertex shader images */ - for (slot = 0; slot < num_vs_imgs; slot++) { + for (slot = 0; slot < (NSUInteger)num_vs_imgs; slot++) { const _sg_image_t* img = vs_imgs[slot]; if ((_sg.mtl.state_cache.cur_vs_images[slot] != img) || (_sg.mtl.state_cache.cur_vs_image_ids[slot].id != img->slot.id)) { _sg.mtl.state_cache.cur_vs_images[slot] = img; @@ -10236,7 +10871,7 @@ _SOKOL_PRIVATE void _sg_mtl_apply_bindings( } /* apply fragment shader images */ - for (slot = 0; slot < num_fs_imgs; slot++) { + for (slot = 0; slot < (NSUInteger)num_fs_imgs; slot++) { const _sg_image_t* img = fs_imgs[slot]; if ((_sg.mtl.state_cache.cur_fs_images[slot] != img) || (_sg.mtl.state_cache.cur_fs_image_ids[slot].id != img->slot.id)) { _sg.mtl.state_cache.cur_fs_images[slot] = img; @@ -10249,33 +10884,30 @@ _SOKOL_PRIVATE void _sg_mtl_apply_bindings( } } -_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { +_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.mtl.in_pass); if (!_sg.mtl.pass_valid) { return; } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - SOKOL_ASSERT(data && (num_bytes > 0)); - SOKOL_ASSERT((stage_index >= 0) && ((int)stage_index < SG_NUM_SHADER_STAGES)); - SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); - SOKOL_ASSERT((_sg.mtl.cur_ub_offset + num_bytes) <= _sg.mtl.ub_size); + SOKOL_ASSERT(((size_t)_sg.mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size); SOKOL_ASSERT((_sg.mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && _sg.mtl.state_cache.cur_pipeline->shader); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->shader->slot.id == _sg.mtl.state_cache.cur_pipeline->cmn.shader_id.id); SOKOL_ASSERT(ub_index < _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); - SOKOL_ASSERT(num_bytes <= _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); + SOKOL_ASSERT(data->size <= _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); /* copy to global uniform buffer, record offset into cmd encoder, and advance offset */ uint8_t* dst = &_sg.mtl.cur_ub_base_ptr[_sg.mtl.cur_ub_offset]; - memcpy(dst, data, num_bytes); + memcpy(dst, data->ptr, data->size); if (stage_index == SG_SHADERSTAGE_VS) { - [_sg.mtl.cmd_encoder setVertexBufferOffset:_sg.mtl.cur_ub_offset atIndex:ub_index]; + [_sg.mtl.cmd_encoder setVertexBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; } else { - [_sg.mtl.cmd_encoder setFragmentBufferOffset:_sg.mtl.cur_ub_offset atIndex:ub_index]; + [_sg.mtl.cmd_encoder setFragmentBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; } - _sg.mtl.cur_ub_offset = _sg_roundup(_sg.mtl.cur_ub_offset + num_bytes, _SG_MTL_UB_ALIGN); + _sg.mtl.cur_ub_offset = _sg_roundup(_sg.mtl.cur_ub_offset + (int)data->size, _SG_MTL_UB_ALIGN); } _SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_instances) { @@ -10290,39 +10922,38 @@ _SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_ins SOKOL_ASSERT(_sg.mtl.state_cache.cur_indexbuffer && (_sg.mtl.state_cache.cur_indexbuffer->slot.id == _sg.mtl.state_cache.cur_indexbuffer_id.id)); const _sg_buffer_t* ib = _sg.mtl.state_cache.cur_indexbuffer; SOKOL_ASSERT(ib->mtl.buf[ib->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); - const NSUInteger index_buffer_offset = _sg.mtl.state_cache.cur_indexbuffer_offset + - base_element * _sg.mtl.state_cache.cur_pipeline->mtl.index_size; + const NSUInteger index_buffer_offset = (NSUInteger) (_sg.mtl.state_cache.cur_indexbuffer_offset + base_element * _sg.mtl.state_cache.cur_pipeline->mtl.index_size); [_sg.mtl.cmd_encoder drawIndexedPrimitives:_sg.mtl.state_cache.cur_pipeline->mtl.prim_type - indexCount:num_elements + indexCount:(NSUInteger)num_elements indexType:_sg.mtl.state_cache.cur_pipeline->mtl.index_type indexBuffer:_sg_mtl_id(ib->mtl.buf[ib->cmn.active_slot]) indexBufferOffset:index_buffer_offset - instanceCount:num_instances]; + instanceCount:(NSUInteger)num_instances]; } else { /* non-indexed rendering */ [_sg.mtl.cmd_encoder drawPrimitives:_sg.mtl.state_cache.cur_pipeline->mtl.prim_type - vertexStart:base_element - vertexCount:num_elements - instanceCount:num_instances]; + vertexStart:(NSUInteger)base_element + vertexCount:(NSUInteger)num_elements + instanceCount:(NSUInteger)num_instances]; } } -_SOKOL_PRIVATE void _sg_mtl_update_buffer(_sg_buffer_t* buf, const void* data, uint32_t data_size) { - SOKOL_ASSERT(buf && data && (data_size > 0)); +_SOKOL_PRIVATE void _sg_mtl_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); if (++buf->cmn.active_slot >= buf->cmn.num_slots) { buf->cmn.active_slot = 0; } __unsafe_unretained id mtl_buf = _sg_mtl_id(buf->mtl.buf[buf->cmn.active_slot]); void* dst_ptr = [mtl_buf contents]; - memcpy(dst_ptr, data, data_size); + memcpy(dst_ptr, data->ptr, data->size); #if defined(_SG_TARGET_MACOS) - [mtl_buf didModifyRange:NSMakeRange(0, data_size)]; + [mtl_buf didModifyRange:NSMakeRange(0, data->size)]; #endif } -_SOKOL_PRIVATE uint32_t _sg_mtl_append_buffer(_sg_buffer_t* buf, const void* data, uint32_t data_size, bool new_frame) { - SOKOL_ASSERT(buf && data && (data_size > 0)); +_SOKOL_PRIVATE int _sg_mtl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); if (new_frame) { if (++buf->cmn.active_slot >= buf->cmn.num_slots) { buf->cmn.active_slot = 0; @@ -10331,21 +10962,21 @@ _SOKOL_PRIVATE uint32_t _sg_mtl_append_buffer(_sg_buffer_t* buf, const void* dat __unsafe_unretained id mtl_buf = _sg_mtl_id(buf->mtl.buf[buf->cmn.active_slot]); uint8_t* dst_ptr = (uint8_t*) [mtl_buf contents]; dst_ptr += buf->cmn.append_pos; - memcpy(dst_ptr, data, data_size); + memcpy(dst_ptr, data->ptr, data->size); #if defined(_SG_TARGET_MACOS) - [mtl_buf didModifyRange:NSMakeRange(buf->cmn.append_pos, data_size)]; + [mtl_buf didModifyRange:NSMakeRange((NSUInteger)buf->cmn.append_pos, (NSUInteger)data->size)]; #endif - /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */ - return _sg_roundup(data_size, 4); + /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backends */ + return _sg_roundup((int)data->size, 4); } -_SOKOL_PRIVATE void _sg_mtl_update_image(_sg_image_t* img, const sg_image_content* data) { +_SOKOL_PRIVATE void _sg_mtl_update_image(_sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(img && data); if (++img->cmn.active_slot >= img->cmn.num_slots) { img->cmn.active_slot = 0; } __unsafe_unretained id mtl_tex = _sg_mtl_id(img->mtl.tex[img->cmn.active_slot]); - _sg_mtl_copy_image_content(img, mtl_tex, data); + _sg_mtl_copy_image_data(img, mtl_tex, data); } /*== WEBGPU BACKEND IMPLEMENTATION ===========================================*/ @@ -10679,6 +11310,8 @@ _SOKOL_PRIVATE void _sg_wgpu_init_caps(void) { _sg.features.imagetype_3d = true; _sg.features.imagetype_array = true; _sg.features.image_clamp_to_border = false; + _sg.features.mrt_independent_blend_state = true; + _sg.features.mrt_independent_write_mask = true; /* FIXME: max images size??? */ _sg.limits.max_image_size_2d = 8 * 1024; @@ -10897,10 +11530,10 @@ _SOKOL_PRIVATE void _sg_wgpu_ubpool_flush(void) { } /* helper function to compute number of bytes needed in staging buffer to copy image data */ -_SOKOL_PRIVATE uint32_t _sg_wgpu_image_content_buffer_size(const _sg_image_t* img, const sg_image_content* content) { +_SOKOL_PRIVATE uint32_t _sg_wgpu_image_data_buffer_size(const _sg_image_t* img) { uint32_t num_bytes = 0; const uint32_t num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const uint32_t num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.depth : 1; + const uint32_t num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++) { const uint32_t mip_width = _sg_max(img->cmn.width >> mip_index, 1); const uint32_t mip_height = _sg_max(img->cmn.height >> mip_index, 1); @@ -10914,14 +11547,14 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_image_content_buffer_size(const _sg_image_t* im /* helper function to copy image data into a texture via a staging buffer, returns number of bytes copied */ -_SOKOL_PRIVATE uint32_t _sg_wgpu_copy_image_content(WGPUBuffer stg_buf, uint8_t* stg_base_ptr, uint32_t stg_base_offset, _sg_image_t* img, const sg_image_content* content) { +_SOKOL_PRIVATE uint32_t _sg_wgpu_copy_image_data(WGPUBuffer stg_buf, uint8_t* stg_base_ptr, uint32_t stg_base_offset, _sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); SOKOL_ASSERT(stg_buf && stg_base_ptr); SOKOL_ASSERT(img); - SOKOL_ASSERT(content); + SOKOL_ASSERT(data); uint32_t stg_offset = stg_base_offset; const uint32_t num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; - const uint32_t num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.depth : 1; + const uint32_t num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices : 1; const sg_pixel_format fmt = img->cmn.pixel_format; WGPUBufferCopyView src_view; memset(&src_view, 0, sizeof(src_view)); @@ -10934,30 +11567,30 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_copy_image_content(WGPUBuffer stg_buf, uint8_t* for (uint32_t face_index = 0; face_index < num_faces; face_index++) { for (uint32_t mip_index = 0; mip_index < (uint32_t)img->cmn.num_mipmaps; mip_index++) { - SOKOL_ASSERT(content->subimage[face_index][mip_index].ptr); - SOKOL_ASSERT(content->subimage[face_index][mip_index].size > 0); - const uint8_t* src_base_ptr = (const uint8_t*)content->subimage[face_index][mip_index].ptr; + SOKOL_ASSERT(data->subimage[face_index][mip_index].ptr); + SOKOL_ASSERT(data->subimage[face_index][mip_index].size > 0); + const uint8_t* src_base_ptr = (const uint8_t*)data->subimage[face_index][mip_index].ptr; SOKOL_ASSERT(src_base_ptr); uint8_t* dst_base_ptr = stg_base_ptr + stg_offset; const uint32_t mip_width = _sg_max(img->cmn.width >> mip_index, 1); const uint32_t mip_height = _sg_max(img->cmn.height >> mip_index, 1); - const uint32_t mip_depth = (img->cmn.type == SG_IMAGETYPE_3D) ? _sg_max(img->cmn.depth >> mip_index, 1) : 1; + const uint32_t mip_depth = (img->cmn.type == SG_IMAGETYPE_3D) ? _sg_max(img->cmn.num_slices >> mip_index, 1) : 1; const uint32_t num_rows = _sg_num_rows(fmt, mip_height); const uint32_t src_bytes_per_row = _sg_row_pitch(fmt, mip_width, 1); const uint32_t dst_bytes_per_row = _sg_row_pitch(fmt, mip_width, _SG_WGPU_ROWPITCH_ALIGN); const uint32_t src_bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, 1); const uint32_t dst_bytes_per_slice = _sg_surface_pitch(fmt, mip_width, mip_height, _SG_WGPU_ROWPITCH_ALIGN); - SOKOL_ASSERT((uint32_t)content->subimage[face_index][mip_index].size == (src_bytes_per_slice * num_slices)); + SOKOL_ASSERT((uint32_t)data->subimage[face_index][mip_index].size == (src_bytes_per_slice * num_slices)); SOKOL_ASSERT(src_bytes_per_row <= dst_bytes_per_row); SOKOL_ASSERT(src_bytes_per_slice == (src_bytes_per_row * num_rows)); SOKOL_ASSERT(dst_bytes_per_slice == (dst_bytes_per_row * num_rows)); _SOKOL_UNUSED(src_bytes_per_slice); - /* copy content into mapped staging buffer */ + /* copy data into mapped staging buffer */ if (src_bytes_per_row == dst_bytes_per_row) { /* can do a single memcpy */ - uint32_t num_bytes = content->subimage[face_index][mip_index].size; + uint32_t num_bytes = data->subimage[face_index][mip_index].size; memcpy(dst_base_ptr, src_base_ptr, num_bytes); } else { @@ -11109,10 +11742,10 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_staging_copy_to_buffer(WGPUBuffer dst_buf, uint return copy_num_bytes; } -_SOKOL_PRIVATE bool _sg_wgpu_staging_copy_to_texture(_sg_image_t* img, const sg_image_content* content) { +_SOKOL_PRIVATE bool _sg_wgpu_staging_copy_to_texture(_sg_image_t* img, const sg_image_data* data) { /* similar to _sg_wgpu_staging_copy_to_buffer(), but with image data instead */ SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); - uint32_t num_bytes = _sg_wgpu_image_content_buffer_size(img, content); + uint32_t num_bytes = _sg_wgpu_image_data_buffer_size(img); if ((_sg.wgpu.staging.offset + num_bytes) >= _sg.wgpu.staging.num_bytes) { SOKOL_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_texture)!\n"); return false; @@ -11122,7 +11755,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_staging_copy_to_texture(_sg_image_t* img, const sg_ uint32_t stg_offset = _sg.wgpu.staging.offset; uint8_t* stg_ptr = _sg.wgpu.staging.ptr[cur]; WGPUBuffer stg_buf = _sg.wgpu.staging.buf[cur]; - uint32_t bytes_copied = _sg_wgpu_copy_image_content(stg_buf, stg_ptr, stg_offset, img, content); + uint32_t bytes_copied = _sg_wgpu_copy_image_data(stg_buf, stg_ptr, stg_offset, img, data); _SOKOL_UNUSED(bytes_copied); SOKOL_ASSERT(bytes_copied == num_bytes); _sg.wgpu.staging.offset = _sg_roundup(stg_offset + num_bytes, _SG_WGPU_STAGING_ALIGN); @@ -11267,6 +11900,7 @@ _SOKOL_PRIVATE void _sg_wgpu_destroy_context(_sg_context_t* ctx) { } _SOKOL_PRIVATE void _sg_wgpu_activate_context(_sg_context_t* ctx) { + (void)ctx; SOKOL_LOG("_sg_wgpu_activate_context: FIXME\n"); } @@ -11284,11 +11918,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const wgpu_buf_desc.usage = _sg_wgpu_buffer_usage(buf->cmn.type, buf->cmn.usage); wgpu_buf_desc.size = buf->cmn.size; if (SG_USAGE_IMMUTABLE == buf->cmn.usage) { - SOKOL_ASSERT(desc->content); + SOKOL_ASSERT(desc->data.ptr); WGPUCreateBufferMappedResult res = wgpuDeviceCreateBufferMapped(_sg.wgpu.dev, &wgpu_buf_desc); buf->wgpu.buf = res.buffer; - SOKOL_ASSERT(res.data && ((int)res.dataLength == buf->cmn.size)); - memcpy(res.data, desc->content, buf->cmn.size); + SOKOL_ASSERT(res.data && (res.dataLength == buf->cmn.size)); + memcpy(res.data, desc->data.ptr, buf->cmn.size); wgpuBufferUnmap(res.buffer); } else { @@ -11312,7 +11946,7 @@ _SOKOL_PRIVATE void _sg_wgpu_init_texdesc_common(WGPUTextureDescriptor* wgpu_tex wgpu_tex_desc->size.width = desc->width; wgpu_tex_desc->size.height = desc->height; if (desc->type == SG_IMAGETYPE_3D) { - wgpu_tex_desc->size.depth = desc->depth; + wgpu_tex_desc->size.depth = desc->num_slices; wgpu_tex_desc->arrayLayerCount = 1; } else if (desc->type == SG_IMAGETYPE_CUBE) { @@ -11321,7 +11955,7 @@ _SOKOL_PRIVATE void _sg_wgpu_init_texdesc_common(WGPUTextureDescriptor* wgpu_tex } else { wgpu_tex_desc->size.depth = 1; - wgpu_tex_desc->arrayLayerCount = desc->layers; + wgpu_tex_desc->arrayLayerCount = desc->num_slices; } wgpu_tex_desc->format = _sg_wgpu_textureformat(desc->pixel_format); wgpu_tex_desc->mipLevelCount = desc->num_mipmaps; @@ -11372,11 +12006,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_image(_sg_image_t* img, const s if (desc->usage == SG_USAGE_IMMUTABLE && !desc->render_target) { WGPUBufferDescriptor wgpu_buf_desc; memset(&wgpu_buf_desc, 0, sizeof(wgpu_buf_desc)); - wgpu_buf_desc.size = _sg_wgpu_image_content_buffer_size(img, &desc->content); + wgpu_buf_desc.size = _sg_wgpu_image_data_buffer_size(img); wgpu_buf_desc.usage = WGPUBufferUsage_CopySrc|WGPUBufferUsage_CopyDst; WGPUCreateBufferMappedResult map = wgpuDeviceCreateBufferMapped(_sg.wgpu.dev, &wgpu_buf_desc); SOKOL_ASSERT(map.buffer && map.data); - uint32_t num_bytes = _sg_wgpu_copy_image_content(map.buffer, (uint8_t*)map.data, 0, img, &desc->content); + uint32_t num_bytes = _sg_wgpu_copy_image_data(map.buffer, (uint8_t*)map.data, 0, img, &desc->data); _SOKOL_UNUSED(num_bytes); SOKOL_ASSERT(num_bytes == wgpu_buf_desc.size); wgpuBufferUnmap(map.buffer); @@ -11433,7 +12067,7 @@ _SOKOL_PRIVATE void _sg_wgpu_destroy_image(_sg_image_t* img) { /* How BindGroups work in WebGPU: - - up to 4 bind groups can be bound simultanously + - up to 4 bind groups can be bound simultaneously - up to 16 bindings per bind group - 'binding' slots are local per bind group - in the shader: @@ -11459,13 +12093,13 @@ _SOKOL_PRIVATE void _sg_wgpu_destroy_image(_sg_image_t* img) { */ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) { SOKOL_ASSERT(shd && desc); - SOKOL_ASSERT(desc->vs.byte_code && desc->fs.byte_code); + SOKOL_ASSERT(desc->vs.bytecode.ptr && desc->fs.bytecode.ptr); _sg_shader_common_init(&shd->cmn, desc); bool success = true; for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs; - SOKOL_ASSERT((stage_desc->byte_code_size & 3) == 0); + SOKOL_ASSERT((stage_desc->bytecode.size & 3) == 0); _sg_shader_stage_t* cmn_stage = &shd->cmn.stage[stage_index]; _sg_wgpu_shader_stage_t* wgpu_stage = &shd->wgpu.stage[stage_index]; @@ -11473,8 +12107,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const _sg_strcpy(&wgpu_stage->entry, stage_desc->entry); WGPUShaderModuleDescriptor wgpu_shdmod_desc; memset(&wgpu_shdmod_desc, 0, sizeof(wgpu_shdmod_desc)); - wgpu_shdmod_desc.codeSize = stage_desc->byte_code_size >> 2; - wgpu_shdmod_desc.code = (const uint32_t*) stage_desc->byte_code; + wgpu_shdmod_desc.codeSize = stage_desc->bytecode.size >> 2; + wgpu_shdmod_desc.code = (const uint32_t*) stage_desc->bytecode.ptr; wgpu_stage->module = wgpuDeviceCreateShaderModule(_sg.wgpu.dev, &wgpu_shdmod_desc); if (0 == wgpu_stage->module) { success = false; @@ -11496,7 +12130,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const tex_desc->binding = img_index; tex_desc->visibility = vis; tex_desc->type = WGPUBindingType_SampledTexture; - tex_desc->textureDimension = _sg_wgpu_tex_viewdim(cmn_stage->images[img_index].type); + tex_desc->textureDimension = _sg_wgpu_tex_viewdim(cmn_stage->images[img_index].image_type); tex_desc->textureComponentType = _sg_wgpu_tex_comptype(cmn_stage->images[img_index].sampler_type); smp_desc->binding = img_index + _SG_WGPU_MAX_SHADERSTAGE_IMAGES; @@ -11535,7 +12169,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _ SOKOL_ASSERT(shd->wgpu.stage[SG_SHADERSTAGE_FS].bind_group_layout); pip->shader = shd; _sg_pipeline_common_init(&pip->cmn, desc); - pip->wgpu.stencil_ref = (uint32_t) desc->depth_stencil.stencil_ref; + pip->wgpu.stencil_ref = (uint32_t) desc->stencil.ref; WGPUBindGroupLayout pip_bgl[3] = { _sg.wgpu.ub.bindgroup_layout, @@ -11588,27 +12222,27 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _ WGPURasterizationStateDescriptor rs_desc; memset(&rs_desc, 0, sizeof(rs_desc)); - rs_desc.frontFace = _sg_wgpu_frontface(desc->rasterizer.face_winding); - rs_desc.cullMode = _sg_wgpu_cullmode(desc->rasterizer.cull_mode); - rs_desc.depthBias = (int32_t) desc->rasterizer.depth_bias; - rs_desc.depthBiasClamp = desc->rasterizer.depth_bias_clamp; - rs_desc.depthBiasSlopeScale = desc->rasterizer.depth_bias_slope_scale; + rs_desc.frontFace = _sg_wgpu_frontface(desc->face_winding); + rs_desc.cullMode = _sg_wgpu_cullmode(desc->cull_mode); + rs_desc.depthBias = (int32_t) desc->depth.bias; + rs_desc.depthBiasClamp = desc->depth.bias_clamp; + rs_desc.depthBiasSlopeScale = desc->depth.bias_slope_scale; WGPUDepthStencilStateDescriptor ds_desc; memset(&ds_desc, 0, sizeof(ds_desc)); - ds_desc.format = _sg_wgpu_textureformat(desc->blend.depth_format); - ds_desc.depthWriteEnabled = desc->depth_stencil.depth_write_enabled; - ds_desc.depthCompare = _sg_wgpu_comparefunc(desc->depth_stencil.depth_compare_func); - ds_desc.stencilReadMask = desc->depth_stencil.stencil_read_mask; - ds_desc.stencilWriteMask = desc->depth_stencil.stencil_write_mask; - ds_desc.stencilFront.compare = _sg_wgpu_comparefunc(desc->depth_stencil.stencil_front.compare_func); - ds_desc.stencilFront.failOp = _sg_wgpu_stencilop(desc->depth_stencil.stencil_front.fail_op); - ds_desc.stencilFront.depthFailOp = _sg_wgpu_stencilop(desc->depth_stencil.stencil_front.depth_fail_op); - ds_desc.stencilFront.passOp = _sg_wgpu_stencilop(desc->depth_stencil.stencil_front.pass_op); - ds_desc.stencilBack.compare = _sg_wgpu_comparefunc(desc->depth_stencil.stencil_back.compare_func); - ds_desc.stencilBack.failOp = _sg_wgpu_stencilop(desc->depth_stencil.stencil_back.fail_op); - ds_desc.stencilBack.depthFailOp = _sg_wgpu_stencilop(desc->depth_stencil.stencil_back.depth_fail_op); - ds_desc.stencilBack.passOp = _sg_wgpu_stencilop(desc->depth_stencil.stencil_back.pass_op); + ds_desc.format = _sg_wgpu_textureformat(desc->depth.pixel_format); + ds_desc.depthWriteEnabled = desc->depth.write_enabled; + ds_desc.depthCompare = _sg_wgpu_comparefunc(desc->depth.compare); + ds_desc.stencilReadMask = desc->stencil.read_mask; + ds_desc.stencilWriteMask = desc->stencil.write_mask; + ds_desc.stencilFront.compare = _sg_wgpu_comparefunc(desc->stencil.front.compare); + ds_desc.stencilFront.failOp = _sg_wgpu_stencilop(desc->stencil.front.fail_op); + ds_desc.stencilFront.depthFailOp = _sg_wgpu_stencilop(desc->stencil.front.depth_fail_op); + ds_desc.stencilFront.passOp = _sg_wgpu_stencilop(desc->stencil.front.pass_op); + ds_desc.stencilBack.compare = _sg_wgpu_comparefunc(desc->stencil.back.compare); + ds_desc.stencilBack.failOp = _sg_wgpu_stencilop(desc->stencil.back.fail_op); + ds_desc.stencilBack.depthFailOp = _sg_wgpu_stencilop(desc->stencil.back.depth_fail_op); + ds_desc.stencilBack.passOp = _sg_wgpu_stencilop(desc->stencil.back.pass_op); WGPUProgrammableStageDescriptor fs_desc; memset(&fs_desc, 0, sizeof(fs_desc)); @@ -11617,17 +12251,16 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _ WGPUColorStateDescriptor cs_desc[SG_MAX_COLOR_ATTACHMENTS]; memset(cs_desc, 0, sizeof(cs_desc)); - cs_desc[0].format = _sg_wgpu_textureformat(desc->blend.color_format); - cs_desc[0].colorBlend.operation = _sg_wgpu_blendop(desc->blend.op_rgb); - cs_desc[0].colorBlend.srcFactor = _sg_wgpu_blendfactor(desc->blend.src_factor_rgb); - cs_desc[0].colorBlend.dstFactor = _sg_wgpu_blendfactor(desc->blend.dst_factor_rgb); - cs_desc[0].alphaBlend.operation = _sg_wgpu_blendop(desc->blend.op_alpha); - cs_desc[0].alphaBlend.srcFactor = _sg_wgpu_blendfactor(desc->blend.src_factor_alpha); - cs_desc[0].alphaBlend.dstFactor = _sg_wgpu_blendfactor(desc->blend.dst_factor_alpha); - cs_desc[0].writeMask = _sg_wgpu_colorwritemask(desc->blend.color_write_mask); - SOKOL_ASSERT(desc->blend.color_attachment_count <= SG_MAX_COLOR_ATTACHMENTS); - for (int i = 1; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - cs_desc[i] = cs_desc[0]; + for (uint32_t i = 0; i < desc->color_count; i++) { + SOKOL_ASSERT(i < SG_MAX_COLOR_ATTACHMENTS); + cs_desc[i].format = _sg_wgpu_textureformat(desc->colors[i].pixel_format); + cs_desc[i].colorBlend.operation = _sg_wgpu_blendop(desc->colors[i].blend.op_rgb); + cs_desc[i].colorBlend.srcFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.src_factor_rgb); + cs_desc[i].colorBlend.dstFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.dst_factor_rgb); + cs_desc[i].alphaBlend.operation = _sg_wgpu_blendop(desc->colors[i].blend.op_alpha); + cs_desc[i].alphaBlend.srcFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.src_factor_alpha); + cs_desc[i].alphaBlend.dstFactor = _sg_wgpu_blendfactor(desc->colors[i].blend.dst_factor_alpha); + cs_desc[i].writeMask = _sg_wgpu_colorwritemask(desc->colors[i].write_mask); } WGPURenderPipelineDescriptor pip_desc; @@ -11639,11 +12272,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _ pip_desc.vertexState = &vx_state_desc; pip_desc.primitiveTopology = _sg_wgpu_topology(desc->primitive_type); pip_desc.rasterizationState = &rs_desc; - pip_desc.sampleCount = desc->rasterizer.sample_count; - if (SG_PIXELFORMAT_NONE != desc->blend.depth_format) { + pip_desc.sampleCount = desc->sample_count; + if (SG_PIXELFORMAT_NONE != desc->depth.pixel_format) { pip_desc.depthStencilState = &ds_desc; } - pip_desc.colorStateCount = desc->blend.color_attachment_count; + pip_desc.colorStateCount = desc->color_count; pip_desc.colorStates = cs_desc; pip_desc.sampleMask = 0xFFFFFFFF; /* FIXME: ??? */ pip->wgpu.pip = wgpuDeviceCreateRenderPipeline(_sg.wgpu.dev, &pip_desc); @@ -11667,8 +12300,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_imag _sg_pass_common_init(&pass->cmn, desc); /* copy image pointers and create render-texture views */ - const sg_attachment_desc* att_desc; - for (int i = 0; i < pass->cmn.num_color_atts; i++) { + const sg_pass_attachment_desc* att_desc; + for (uint32_t i = 0; i < pass->cmn.num_color_atts; i++) { att_desc = &desc->color_attachments[i]; if (att_desc->image.id != SG_INVALID_ID) { SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID); @@ -11722,7 +12355,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pass(_sg_pass_t* pass, _sg_imag _SOKOL_PRIVATE void _sg_wgpu_destroy_pass(_sg_pass_t* pass) { SOKOL_ASSERT(pass); - for (int i = 0; i < pass->cmn.num_color_atts; i++) { + for (uint32_t i = 0; i < pass->cmn.num_color_atts; i++) { if (pass->wgpu.color_atts[i].render_tex_view) { wgpuTextureViewRelease(pass->wgpu.color_atts[i].render_tex_view); pass->wgpu.color_atts[i].render_tex_view = 0; @@ -11771,14 +12404,14 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* WGPURenderPassColorAttachmentDescriptor wgpu_color_att_desc[SG_MAX_COLOR_ATTACHMENTS]; memset(&wgpu_color_att_desc, 0, sizeof(wgpu_color_att_desc)); SOKOL_ASSERT(pass->slot.state == SG_RESOURCESTATE_VALID); - for (int i = 0; i < pass->cmn.num_color_atts; i++) { + for (uint32_t i = 0; i < pass->cmn.num_color_atts; i++) { const _sg_wgpu_attachment_t* wgpu_att = &pass->wgpu.color_atts[i]; wgpu_color_att_desc[i].loadOp = _sg_wgpu_load_op(action->colors[i].action); wgpu_color_att_desc[i].storeOp = WGPUStoreOp_Store; - wgpu_color_att_desc[i].clearColor.r = action->colors[i].val[0]; - wgpu_color_att_desc[i].clearColor.g = action->colors[i].val[1]; - wgpu_color_att_desc[i].clearColor.b = action->colors[i].val[2]; - wgpu_color_att_desc[i].clearColor.a = action->colors[i].val[3]; + wgpu_color_att_desc[i].clearColor.r = action->colors[i].value.r; + wgpu_color_att_desc[i].clearColor.g = action->colors[i].value.g; + wgpu_color_att_desc[i].clearColor.b = action->colors[i].value.b; + wgpu_color_att_desc[i].clearColor.a = action->colors[i].value.a; wgpu_color_att_desc[i].attachment = wgpu_att->render_tex_view; if (wgpu_att->image->cmn.sample_count > 1) { wgpu_color_att_desc[i].resolveTarget = wgpu_att->resolve_tex_view; @@ -11790,9 +12423,9 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* WGPURenderPassDepthStencilAttachmentDescriptor wgpu_ds_att_desc; memset(&wgpu_ds_att_desc, 0, sizeof(wgpu_ds_att_desc)); wgpu_ds_att_desc.depthLoadOp = _sg_wgpu_load_op(action->depth.action); - wgpu_ds_att_desc.clearDepth = action->depth.val; + wgpu_ds_att_desc.clearDepth = action->depth.value; wgpu_ds_att_desc.stencilLoadOp = _sg_wgpu_load_op(action->stencil.action); - wgpu_ds_att_desc.clearStencil = action->stencil.val; + wgpu_ds_att_desc.clearStencil = action->stencil.value; wgpu_ds_att_desc.attachment = pass->wgpu.ds_att.render_tex_view; wgpu_pass_desc.depthStencilAttachment = &wgpu_ds_att_desc; _sg.wgpu.pass_enc = wgpuCommandEncoderBeginRenderPass(_sg.wgpu.render_cmd_enc, &wgpu_pass_desc); @@ -11809,10 +12442,10 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* WGPURenderPassColorAttachmentDescriptor color_att_desc; memset(&color_att_desc, 0, sizeof(color_att_desc)); color_att_desc.loadOp = _sg_wgpu_load_op(action->colors[0].action); - color_att_desc.clearColor.r = action->colors[0].val[0]; - color_att_desc.clearColor.g = action->colors[0].val[1]; - color_att_desc.clearColor.b = action->colors[0].val[2]; - color_att_desc.clearColor.a = action->colors[0].val[3]; + color_att_desc.clearColor.r = action->colors[0].value.r; + color_att_desc.clearColor.g = action->colors[0].value.g; + color_att_desc.clearColor.b = action->colors[0].value.b; + color_att_desc.clearColor.a = action->colors[0].value.a; color_att_desc.attachment = wgpu_render_view; color_att_desc.resolveTarget = wgpu_resolve_view; /* null if no MSAA rendering */ pass_desc.colorAttachmentCount = 1; @@ -11822,9 +12455,9 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_pass(_sg_pass_t* pass, const sg_pass_action* ds_att_desc.attachment = wgpu_depth_stencil_view; SOKOL_ASSERT(0 != ds_att_desc.attachment); ds_att_desc.depthLoadOp = _sg_wgpu_load_op(action->depth.action); - ds_att_desc.clearDepth = action->depth.val; + ds_att_desc.clearDepth = action->depth.value; ds_att_desc.stencilLoadOp = _sg_wgpu_load_op(action->stencil.action); - ds_att_desc.clearStencil = action->stencil.val; + ds_att_desc.clearStencil = action->stencil.value; pass_desc.depthStencilAttachment = &ds_att_desc; _sg.wgpu.pass_enc = wgpuCommandEncoderBeginRenderPass(_sg.wgpu.render_cmd_enc, &pass_desc); } @@ -11931,7 +12564,7 @@ _SOKOL_PRIVATE void _sg_wgpu_apply_pipeline(_sg_pipeline_t* pip) { _sg.wgpu.cur_pipeline = pip; _sg.wgpu.cur_pipeline_id.id = pip->slot.id; wgpuRenderPassEncoderSetPipeline(_sg.wgpu.pass_enc, pip->wgpu.pip); - wgpuRenderPassEncoderSetBlendColor(_sg.wgpu.pass_enc, (WGPUColor*)pip->cmn.blend_color); + wgpuRenderPassEncoderSetBlendColor(_sg.wgpu.pass_enc, (WGPUColor*)&pip->cmn.blend_color); wgpuRenderPassEncoderSetStencilReference(_sg.wgpu.pass_enc, pip->wgpu.stencil_ref); } @@ -12008,31 +12641,28 @@ _SOKOL_PRIVATE void _sg_wgpu_apply_bindings( } } -_SOKOL_PRIVATE void _sg_wgpu_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { +_SOKOL_PRIVATE void _sg_wgpu_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.wgpu.in_pass); SOKOL_ASSERT(_sg.wgpu.pass_enc); - SOKOL_ASSERT(data && (num_bytes > 0)); - SOKOL_ASSERT((stage_index >= 0) && ((int)stage_index < SG_NUM_SHADER_STAGES)); - SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); - SOKOL_ASSERT((_sg.wgpu.ub.offset + num_bytes) <= _sg.wgpu.ub.num_bytes); + SOKOL_ASSERT((_sg.wgpu.ub.offset + data->size) <= _sg.wgpu.ub.num_bytes); SOKOL_ASSERT((_sg.wgpu.ub.offset & (_SG_WGPU_STAGING_ALIGN-1)) == 0); SOKOL_ASSERT(_sg.wgpu.cur_pipeline && _sg.wgpu.cur_pipeline->shader); SOKOL_ASSERT(_sg.wgpu.cur_pipeline->slot.id == _sg.wgpu.cur_pipeline_id.id); SOKOL_ASSERT(_sg.wgpu.cur_pipeline->shader->slot.id == _sg.wgpu.cur_pipeline->cmn.shader_id.id); SOKOL_ASSERT(ub_index < _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks); - SOKOL_ASSERT(num_bytes <= _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); - SOKOL_ASSERT(num_bytes <= _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE); + SOKOL_ASSERT(data->size <= _sg.wgpu.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); + SOKOL_ASSERT(data->size <= _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE); SOKOL_ASSERT(0 != _sg.wgpu.ub.stage.ptr[_sg.wgpu.ub.stage.cur]); uint8_t* dst_ptr = _sg.wgpu.ub.stage.ptr[_sg.wgpu.ub.stage.cur] + _sg.wgpu.ub.offset; - memcpy(dst_ptr, data, num_bytes); + memcpy(dst_ptr, data->ptr, data->size); _sg.wgpu.ub.bind_offsets[stage_index][ub_index] = _sg.wgpu.ub.offset; wgpuRenderPassEncoderSetBindGroup(_sg.wgpu.pass_enc, 0, /* groupIndex 0 is reserved for uniform buffers */ _sg.wgpu.ub.bindgroup, SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_UBS, &_sg.wgpu.ub.bind_offsets[0][0]); - _sg.wgpu.ub.offset = _sg_roundup(_sg.wgpu.ub.offset + num_bytes, _SG_WGPU_STAGING_ALIGN); + _sg.wgpu.ub.offset = _sg_roundup(_sg.wgpu.ub.offset + data->size, _SG_WGPU_STAGING_ALIGN); } _SOKOL_PRIVATE void _sg_wgpu_draw(int base_element, int num_elements, int num_instances) { @@ -12046,21 +12676,21 @@ _SOKOL_PRIVATE void _sg_wgpu_draw(int base_element, int num_elements, int num_in } } -_SOKOL_PRIVATE void _sg_wgpu_update_buffer(_sg_buffer_t* buf, const void* data, uint32_t num_bytes) { - SOKOL_ASSERT(buf && data && (num_bytes > 0)); - uint32_t copied_num_bytes = _sg_wgpu_staging_copy_to_buffer(buf->wgpu.buf, 0, data, (uint32_t)num_bytes); +_SOKOL_PRIVATE void _sg_wgpu_update_buffer(_sg_buffer_t* buf, const sg_range* data) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); + uint32_t copied_num_bytes = _sg_wgpu_staging_copy_to_buffer(buf->wgpu.buf, 0, data->ptr, data->size); SOKOL_ASSERT(copied_num_bytes > 0); _SOKOL_UNUSED(copied_num_bytes); } -_SOKOL_PRIVATE uint32_t _sg_wgpu_append_buffer(_sg_buffer_t* buf, const void* data, uint32_t num_bytes, bool new_frame) { - SOKOL_ASSERT(buf && data && (num_bytes > 0)); +_SOKOL_PRIVATE int _sg_wgpu_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { + SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0)); _SOKOL_UNUSED(new_frame); - uint32_t copied_num_bytes = _sg_wgpu_staging_copy_to_buffer(buf->wgpu.buf, buf->cmn.append_pos, data, num_bytes); + uint32_t copied_num_bytes = _sg_wgpu_staging_copy_to_buffer(buf->wgpu.buf, buf->cmn.append_pos, data->ptr, data->size); SOKOL_ASSERT(copied_num_bytes > 0); _SOKOL_UNUSED(copied_num_bytes); - return copied_num_bytes; + return (int)copied_num_bytes; } -_SOKOL_PRIVATE void _sg_wgpu_update_image(_sg_image_t* img, const sg_image_content* data) { +_SOKOL_PRIVATE void _sg_wgpu_update_image(_sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(img && data); bool success = _sg_wgpu_staging_copy_to_texture(img, data); SOKOL_ASSERT(success); @@ -12459,17 +13089,17 @@ static inline void _sg_apply_bindings( #endif } -static inline void _sg_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { +static inline void _sg_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { #if defined(_SOKOL_ANY_GL) - _sg_gl_apply_uniforms(stage_index, ub_index, data, num_bytes); + _sg_gl_apply_uniforms(stage_index, ub_index, data); #elif defined(SOKOL_METAL) - _sg_mtl_apply_uniforms(stage_index, ub_index, data, num_bytes); + _sg_mtl_apply_uniforms(stage_index, ub_index, data); #elif defined(SOKOL_D3D11) - _sg_d3d11_apply_uniforms(stage_index, ub_index, data, num_bytes); + _sg_d3d11_apply_uniforms(stage_index, ub_index, data); #elif defined(SOKOL_WGPU) - _sg_wgpu_apply_uniforms(stage_index, ub_index, data, num_bytes); + _sg_wgpu_apply_uniforms(stage_index, ub_index, data); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_apply_uniforms(stage_index, ub_index, data, num_bytes); + _sg_dummy_apply_uniforms(stage_index, ub_index, data); #else #error("INVALID BACKEND"); #endif @@ -12507,39 +13137,39 @@ static inline void _sg_commit(void) { #endif } -static inline void _sg_update_buffer(_sg_buffer_t* buf, const void* data_ptr, uint32_t data_size) { +static inline void _sg_update_buffer(_sg_buffer_t* buf, const sg_range* data) { #if defined(_SOKOL_ANY_GL) - _sg_gl_update_buffer(buf, data_ptr, data_size); + _sg_gl_update_buffer(buf, data); #elif defined(SOKOL_METAL) - _sg_mtl_update_buffer(buf, data_ptr, data_size); + _sg_mtl_update_buffer(buf, data); #elif defined(SOKOL_D3D11) - _sg_d3d11_update_buffer(buf, data_ptr, data_size); + _sg_d3d11_update_buffer(buf, data); #elif defined(SOKOL_WGPU) - _sg_wgpu_update_buffer(buf, data_ptr, data_size); + _sg_wgpu_update_buffer(buf, data); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_update_buffer(buf, data_ptr, data_size); + _sg_dummy_update_buffer(buf, data); #else #error("INVALID BACKEND"); #endif } -static inline uint32_t _sg_append_buffer(_sg_buffer_t* buf, const void* data_ptr, uint32_t data_size, bool new_frame) { +static inline int _sg_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) { #if defined(_SOKOL_ANY_GL) - return _sg_gl_append_buffer(buf, data_ptr, data_size, new_frame); + return _sg_gl_append_buffer(buf, data, new_frame); #elif defined(SOKOL_METAL) - return _sg_mtl_append_buffer(buf, data_ptr, data_size, new_frame); + return _sg_mtl_append_buffer(buf, data, new_frame); #elif defined(SOKOL_D3D11) - return _sg_d3d11_append_buffer(buf, data_ptr, data_size, new_frame); + return _sg_d3d11_append_buffer(buf, data, new_frame); #elif defined(SOKOL_WGPU) - return _sg_wgpu_append_buffer(buf, data_ptr, data_size, new_frame); + return _sg_wgpu_append_buffer(buf, data, new_frame); #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_append_buffer(buf, data_ptr, data_size, new_frame); + return _sg_dummy_append_buffer(buf, data, new_frame); #else #error("INVALID BACKEND"); #endif } -static inline void _sg_update_image(_sg_image_t* img, const sg_image_content* data) { +static inline void _sg_update_image(_sg_image_t* img, const sg_image_data* data) { #if defined(_SOKOL_ANY_GL) _sg_gl_update_image(img, data); #elif defined(SOKOL_METAL) @@ -12563,12 +13193,12 @@ _SOKOL_PRIVATE void _sg_init_pool(_sg_pool_t* pool, int num) { pool->size = num + 1; pool->queue_top = 0; /* generation counters indexable by pool slot index, slot 0 is reserved */ - size_t gen_ctrs_size = sizeof(uint32_t) * pool->size; + size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; pool->gen_ctrs = (uint32_t*) SOKOL_MALLOC(gen_ctrs_size); SOKOL_ASSERT(pool->gen_ctrs); memset(pool->gen_ctrs, 0, gen_ctrs_size); /* it's not a bug to only reserve 'num' here */ - pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int)*num); + pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int) * (size_t)num); SOKOL_ASSERT(pool->free_queue); /* never allocate the zero-th pool item since the invalid id is 0 */ for (int i = pool->size-1; i >= 1; i--) { @@ -12617,34 +13247,57 @@ _SOKOL_PRIVATE void _sg_pool_free_index(_sg_pool_t* pool, int slot_index) { SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); } +_SOKOL_PRIVATE void _sg_reset_slot(_sg_slot_t* slot) { + SOKOL_ASSERT(slot); + memset(slot, 0, sizeof(_sg_slot_t)); +} + _SOKOL_PRIVATE void _sg_reset_buffer(_sg_buffer_t* buf) { SOKOL_ASSERT(buf); + _sg_slot_t slot = buf->slot; memset(buf, 0, sizeof(_sg_buffer_t)); + buf->slot = slot; + buf->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_reset_image(_sg_image_t* img) { SOKOL_ASSERT(img); + _sg_slot_t slot = img->slot; memset(img, 0, sizeof(_sg_image_t)); + img->slot = slot; + img->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_reset_shader(_sg_shader_t* shd) { SOKOL_ASSERT(shd); + _sg_slot_t slot = shd->slot; memset(shd, 0, sizeof(_sg_shader_t)); + shd->slot = slot; + shd->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_reset_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); + _sg_slot_t slot = pip->slot; memset(pip, 0, sizeof(_sg_pipeline_t)); + pip->slot = slot; + pip->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_reset_pass(_sg_pass_t* pass) { SOKOL_ASSERT(pass); + _sg_slot_t slot = pass->slot; memset(pass, 0, sizeof(_sg_pass_t)); + pass->slot = slot; + pass->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_reset_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); + _sg_slot_t slot = ctx->slot; memset(ctx, 0, sizeof(_sg_context_t)); + ctx->slot = slot; + ctx->slot.state = SG_RESOURCESTATE_ALLOC; } _SOKOL_PRIVATE void _sg_setup_pools(_sg_pools_t* p, const sg_desc* desc) { @@ -12653,42 +13306,42 @@ _SOKOL_PRIVATE void _sg_setup_pools(_sg_pools_t* p, const sg_desc* desc) { /* note: the pools here will have an additional item, since slot 0 is reserved */ SOKOL_ASSERT((desc->buffer_pool_size > 0) && (desc->buffer_pool_size < _SG_MAX_POOL_SIZE)); _sg_init_pool(&p->buffer_pool, desc->buffer_pool_size); - size_t buffer_pool_byte_size = sizeof(_sg_buffer_t) * p->buffer_pool.size; + size_t buffer_pool_byte_size = sizeof(_sg_buffer_t) * (size_t)p->buffer_pool.size; p->buffers = (_sg_buffer_t*) SOKOL_MALLOC(buffer_pool_byte_size); SOKOL_ASSERT(p->buffers); memset(p->buffers, 0, buffer_pool_byte_size); SOKOL_ASSERT((desc->image_pool_size > 0) && (desc->image_pool_size < _SG_MAX_POOL_SIZE)); _sg_init_pool(&p->image_pool, desc->image_pool_size); - size_t image_pool_byte_size = sizeof(_sg_image_t) * p->image_pool.size; + size_t image_pool_byte_size = sizeof(_sg_image_t) * (size_t)p->image_pool.size; p->images = (_sg_image_t*) SOKOL_MALLOC(image_pool_byte_size); SOKOL_ASSERT(p->images); memset(p->images, 0, image_pool_byte_size); SOKOL_ASSERT((desc->shader_pool_size > 0) && (desc->shader_pool_size < _SG_MAX_POOL_SIZE)); _sg_init_pool(&p->shader_pool, desc->shader_pool_size); - size_t shader_pool_byte_size = sizeof(_sg_shader_t) * p->shader_pool.size; + size_t shader_pool_byte_size = sizeof(_sg_shader_t) * (size_t)p->shader_pool.size; p->shaders = (_sg_shader_t*) SOKOL_MALLOC(shader_pool_byte_size); SOKOL_ASSERT(p->shaders); memset(p->shaders, 0, shader_pool_byte_size); SOKOL_ASSERT((desc->pipeline_pool_size > 0) && (desc->pipeline_pool_size < _SG_MAX_POOL_SIZE)); _sg_init_pool(&p->pipeline_pool, desc->pipeline_pool_size); - size_t pipeline_pool_byte_size = sizeof(_sg_pipeline_t) * p->pipeline_pool.size; + size_t pipeline_pool_byte_size = sizeof(_sg_pipeline_t) * (size_t)p->pipeline_pool.size; p->pipelines = (_sg_pipeline_t*) SOKOL_MALLOC(pipeline_pool_byte_size); SOKOL_ASSERT(p->pipelines); memset(p->pipelines, 0, pipeline_pool_byte_size); SOKOL_ASSERT((desc->pass_pool_size > 0) && (desc->pass_pool_size < _SG_MAX_POOL_SIZE)); _sg_init_pool(&p->pass_pool, desc->pass_pool_size); - size_t pass_pool_byte_size = sizeof(_sg_pass_t) * p->pass_pool.size; + size_t pass_pool_byte_size = sizeof(_sg_pass_t) * (size_t)p->pass_pool.size; p->passes = (_sg_pass_t*) SOKOL_MALLOC(pass_pool_byte_size); SOKOL_ASSERT(p->passes); memset(p->passes, 0, pass_pool_byte_size); SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SG_MAX_POOL_SIZE)); _sg_init_pool(&p->context_pool, desc->context_pool_size); - size_t context_pool_byte_size = sizeof(_sg_context_t) * p->context_pool.size; + size_t context_pool_byte_size = sizeof(_sg_context_t) * (size_t)p->context_pool.size; p->contexts = (_sg_context_t*) SOKOL_MALLOC(context_pool_byte_size); SOKOL_ASSERT(p->contexts); memset(p->contexts, 0, context_pool_byte_size); @@ -12904,8 +13557,9 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) { /* buffer creation validation errors */ case _SG_VALIDATE_BUFFERDESC_CANARY: return "sg_buffer_desc not initialized"; case _SG_VALIDATE_BUFFERDESC_SIZE: return "sg_buffer_desc.size cannot be 0"; - case _SG_VALIDATE_BUFFERDESC_CONTENT: return "immutable buffers must be initialized with content (sg_buffer_desc.content)"; - case _SG_VALIDATE_BUFFERDESC_NO_CONTENT: return "dynamic/stream usage buffers cannot be initialized with content"; + case _SG_VALIDATE_BUFFERDESC_DATA: return "immutable buffers must be initialized with data (sg_buffer_desc.data.ptr and sg_buffer_desc.data.size)"; + 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 creation validation errros */ case _SG_VALIDATE_IMAGEDESC_CANARY: return "sg_image_desc not initialized"; @@ -12916,9 +13570,9 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) { case _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT: return "non-render-target images cannot be multisampled"; 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_CONTENT: return "render target images cannot be initialized with content"; - case _SG_VALIDATE_IMAGEDESC_CONTENT: return "missing or invalid content for immutable image"; - case _SG_VALIDATE_IMAGEDESC_NO_CONTENT: return "dynamic/stream usage images cannot be initialized with content"; + 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"; /* shader creation */ case _SG_VALIDATE_SHADERDESC_CANARY: return "sg_shader_desc not initialized"; @@ -12955,7 +13609,6 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) { case _SG_VALIDATE_PASSDESC_LAYER: return "pass attachment image is array texture, but layer index is too big"; case _SG_VALIDATE_PASSDESC_SLICE: return "pass attachment image is 3d texture, but slice value is too big"; case _SG_VALIDATE_PASSDESC_IMAGE_NO_RT: return "pass attachment image must be render targets"; - case _SG_VALIDATE_PASSDESC_COLOR_PIXELFORMATS: return "all pass color attachment images must have the same pixel format"; case _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT: return "pass color-attachment images must have a renderable pixel format"; case _SG_VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT: return "pass depth-attachment image must have depth pixel format"; case _SG_VALIDATE_PASSDESC_IMAGE_SIZES: return "all pass attachments must have the same size"; @@ -12971,10 +13624,10 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) { case _SG_VALIDATE_APIP_PIPELINE_VALID: return "sg_apply_pipeline: pipeline object not in valid state"; case _SG_VALIDATE_APIP_SHADER_EXISTS: return "sg_apply_pipeline: shader object no longer alive"; case _SG_VALIDATE_APIP_SHADER_VALID: return "sg_apply_pipeline: shader object not in valid state"; - case _SG_VALIDATE_APIP_ATT_COUNT: return "sg_apply_pipeline: color_attachment_count in pipeline doesn't match number of pass color attachments"; - case _SG_VALIDATE_APIP_COLOR_FORMAT: return "sg_apply_pipeline: color_format in pipeline doesn't match pass color attachment pixel format"; - case _SG_VALIDATE_APIP_DEPTH_FORMAT: return "sg_apply_pipeline: depth_format in pipeline doesn't match pass depth attachment pixel format"; - case _SG_VALIDATE_APIP_SAMPLE_COUNT: return "sg_apply_pipeline: MSAA sample count in pipeline doesn't match render pass attachment sample count"; + case _SG_VALIDATE_APIP_ATT_COUNT: return "sg_apply_pipeline: number of pipeline color attachments doesn't match number of pass color attachments"; + case _SG_VALIDATE_APIP_COLOR_FORMAT: return "sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format"; + case _SG_VALIDATE_APIP_DEPTH_FORMAT: return "sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format"; + case _SG_VALIDATE_APIP_SAMPLE_COUNT: return "sg_apply_pipeline: pipeline MSAA sample count doesn't match render pass attachment sample count"; /* sg_apply_bindings */ case _SG_VALIDATE_ABND_PIPELINE: return "sg_apply_bindings: must be called after sg_apply_pipeline"; @@ -13066,10 +13719,11 @@ _SOKOL_PRIVATE bool _sg_validate_buffer_desc(const sg_buffer_desc* desc) { (0 != desc->d3d11_buffer) || (0 != desc->wgpu_buffer); if (!injected && (desc->usage == SG_USAGE_IMMUTABLE)) { - SOKOL_VALIDATE(0 != desc->content, _SG_VALIDATE_BUFFERDESC_CONTENT); + SOKOL_VALIDATE((0 != desc->data.ptr) && (desc->data.size > 0), _SG_VALIDATE_BUFFERDESC_DATA); + SOKOL_VALIDATE(desc->size == desc->data.size, _SG_VALIDATE_BUFFERDESC_DATA_SIZE); } else { - SOKOL_VALIDATE(0 == desc->content, _SG_VALIDATE_BUFFERDESC_NO_CONTENT); + SOKOL_VALIDATE(0 == desc->data.ptr, _SG_VALIDATE_BUFFERDESC_NO_DATA); } return SOKOL_VALIDATE_END(); #endif @@ -13106,7 +13760,7 @@ _SOKOL_PRIVATE bool _sg_validate_image_desc(const sg_image_desc* desc) { } #endif SOKOL_VALIDATE(usage == SG_USAGE_IMMUTABLE, _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE); - SOKOL_VALIDATE(desc->content.subimage[0][0].ptr==0, _SG_VALIDATE_IMAGEDESC_RT_NO_CONTENT); + SOKOL_VALIDATE(desc->data.subimage[0][0].ptr==0, _SG_VALIDATE_IMAGEDESC_RT_NO_DATA); } else { SOKOL_VALIDATE(desc->sample_count <= 1, _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT); @@ -13118,18 +13772,18 @@ _SOKOL_PRIVATE bool _sg_validate_image_desc(const sg_image_desc* desc) { 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->content.subimage[face_index][mip_index].ptr != 0; - const bool has_size = desc->content.subimage[face_index][mip_index].size > 0; - SOKOL_VALIDATE(has_data && has_size, _SG_VALIDATE_IMAGEDESC_CONTENT); + 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); } } } else { 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->content.subimage[face_index][mip_index].ptr; - const bool no_size = 0 == desc->content.subimage[face_index][mip_index].size; - SOKOL_VALIDATE(no_data && no_size, _SG_VALIDATE_IMAGEDESC_NO_CONTENT); + 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); } } } @@ -13158,12 +13812,12 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { SOKOL_VALIDATE(0 != desc->fs.source, _SG_VALIDATE_SHADERDESC_SOURCE); #elif defined(SOKOL_METAL) || defined(SOKOL_D3D11) /* on Metal or D3D11, must provide shader source code or byte code */ - SOKOL_VALIDATE((0 != desc->vs.source)||(0 != desc->vs.byte_code), _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); - SOKOL_VALIDATE((0 != desc->fs.source)||(0 != desc->fs.byte_code), _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); + SOKOL_VALIDATE((0 != desc->vs.source)||(0 != desc->vs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); + SOKOL_VALIDATE((0 != desc->fs.source)||(0 != desc->fs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE); #elif defined(SOKOL_WGPU) /* on WGPU byte code must be provided */ - SOKOL_VALIDATE((0 != desc->vs.byte_code), _SG_VALIDATE_SHADERDESC_BYTECODE); - SOKOL_VALIDATE((0 != desc->fs.byte_code), _SG_VALIDATE_SHADERDESC_BYTECODE); + SOKOL_VALIDATE((0 != desc->vs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_BYTECODE); + SOKOL_VALIDATE((0 != desc->fs.bytecode.ptr), _SG_VALIDATE_SHADERDESC_BYTECODE); #else /* Dummy Backend, don't require source or bytecode */ #endif @@ -13176,11 +13830,11 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { } } /* if shader byte code, the size must also be provided */ - if (0 != desc->vs.byte_code) { - SOKOL_VALIDATE(desc->vs.byte_code_size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); + if (0 != desc->vs.bytecode.ptr) { + SOKOL_VALIDATE(desc->vs.bytecode.size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); } - if (0 != desc->fs.byte_code) { - SOKOL_VALIDATE(desc->fs.byte_code_size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); + if (0 != desc->fs.bytecode.ptr) { + SOKOL_VALIDATE(desc->fs.bytecode.size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); } for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { const sg_shader_stage_desc* stage_desc = (stage_index == 0)? &desc->vs : &desc->fs; @@ -13208,7 +13862,7 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { } } #if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) - SOKOL_VALIDATE(uniform_offset == ub_desc->size, _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH); + 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); #endif } @@ -13219,7 +13873,7 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { bool images_continuous = true; for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - if (img_desc->type != _SG_IMAGETYPE_DEFAULT) { + if (img_desc->image_type != _SG_IMAGETYPE_DEFAULT) { SOKOL_VALIDATE(images_continuous, _SG_VALIDATE_SHADERDESC_NO_CONT_IMGS); #if defined(SOKOL_GLES2) SOKOL_VALIDATE(0 != img_desc->name, _SG_VALIDATE_SHADERDESC_IMG_NAME); @@ -13288,10 +13942,9 @@ _SOKOL_PRIVATE bool _sg_validate_pass_desc(const sg_pass_desc* desc) { SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_PASSDESC_CANARY); SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_PASSDESC_CANARY); bool atts_cont = true; - sg_pixel_format color_fmt = SG_PIXELFORMAT_NONE; int width = -1, height = -1, sample_count = -1; for (int att_index = 0; att_index < SG_MAX_COLOR_ATTACHMENTS; att_index++) { - const sg_attachment_desc* att = &desc->color_attachments[att_index]; + const sg_pass_attachment_desc* att = &desc->color_attachments[att_index]; if (att->image.id == SG_INVALID_ID) { SOKOL_VALIDATE(att_index > 0, _SG_VALIDATE_PASSDESC_NO_COLOR_ATTS); atts_cont = false; @@ -13299,26 +13952,25 @@ _SOKOL_PRIVATE bool _sg_validate_pass_desc(const sg_pass_desc* desc) { } SOKOL_VALIDATE(atts_cont, _SG_VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS); const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); - SOKOL_VALIDATE((0 != img) && (img->slot.state == SG_RESOURCESTATE_VALID), _SG_VALIDATE_PASSDESC_IMAGE); + SOKOL_ASSERT(img); + SOKOL_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_PASSDESC_IMAGE); SOKOL_VALIDATE(att->mip_level < img->cmn.num_mipmaps, _SG_VALIDATE_PASSDESC_MIPLEVEL); if (img->cmn.type == SG_IMAGETYPE_CUBE) { - SOKOL_VALIDATE(att->face < 6, _SG_VALIDATE_PASSDESC_FACE); + SOKOL_VALIDATE(att->slice < 6, _SG_VALIDATE_PASSDESC_FACE); } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - SOKOL_VALIDATE(att->layer < img->cmn.depth, _SG_VALIDATE_PASSDESC_LAYER); + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_LAYER); } else if (img->cmn.type == SG_IMAGETYPE_3D) { - SOKOL_VALIDATE(att->slice < img->cmn.depth, _SG_VALIDATE_PASSDESC_SLICE); + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_SLICE); } SOKOL_VALIDATE(img->cmn.render_target, _SG_VALIDATE_PASSDESC_IMAGE_NO_RT); if (att_index == 0) { - color_fmt = img->cmn.pixel_format; width = img->cmn.width >> att->mip_level; height = img->cmn.height >> att->mip_level; sample_count = img->cmn.sample_count; } else { - SOKOL_VALIDATE(img->cmn.pixel_format == color_fmt, _SG_VALIDATE_PASSDESC_COLOR_PIXELFORMATS); SOKOL_VALIDATE(width == img->cmn.width >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); SOKOL_VALIDATE(height == img->cmn.height >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); SOKOL_VALIDATE(sample_count == img->cmn.sample_count, _SG_VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS); @@ -13326,18 +13978,19 @@ _SOKOL_PRIVATE bool _sg_validate_pass_desc(const sg_pass_desc* desc) { SOKOL_VALIDATE(_sg_is_valid_rendertarget_color_format(img->cmn.pixel_format), _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT); } if (desc->depth_stencil_attachment.image.id != SG_INVALID_ID) { - const sg_attachment_desc* att = &desc->depth_stencil_attachment; + const sg_pass_attachment_desc* att = &desc->depth_stencil_attachment; const _sg_image_t* img = _sg_lookup_image(&_sg.pools, att->image.id); - SOKOL_VALIDATE((0 != img) && (img->slot.state == SG_RESOURCESTATE_VALID), _SG_VALIDATE_PASSDESC_IMAGE); + SOKOL_ASSERT(img); + SOKOL_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_PASSDESC_IMAGE); SOKOL_VALIDATE(att->mip_level < img->cmn.num_mipmaps, _SG_VALIDATE_PASSDESC_MIPLEVEL); if (img->cmn.type == SG_IMAGETYPE_CUBE) { - SOKOL_VALIDATE(att->face < 6, _SG_VALIDATE_PASSDESC_FACE); + SOKOL_VALIDATE(att->slice < 6, _SG_VALIDATE_PASSDESC_FACE); } else if (img->cmn.type == SG_IMAGETYPE_ARRAY) { - SOKOL_VALIDATE(att->layer < img->cmn.depth, _SG_VALIDATE_PASSDESC_LAYER); + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_LAYER); } else if (img->cmn.type == SG_IMAGETYPE_3D) { - SOKOL_VALIDATE(att->slice < img->cmn.depth, _SG_VALIDATE_PASSDESC_SLICE); + SOKOL_VALIDATE(att->slice < img->cmn.num_slices, _SG_VALIDATE_PASSDESC_SLICE); } SOKOL_VALIDATE(img->cmn.render_target, _SG_VALIDATE_PASSDESC_IMAGE_NO_RT); SOKOL_VALIDATE(width == img->cmn.width >> att->mip_level, _SG_VALIDATE_PASSDESC_IMAGE_SIZES); @@ -13358,7 +14011,7 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(_sg_pass_t* pass) { SOKOL_VALIDATE(pass->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_BEGINPASS_PASS); for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - const _sg_attachment_t* att = &pass->cmn.color_atts[i]; + const _sg_pass_attachment_t* att = &pass->cmn.color_atts[i]; const _sg_image_t* img = _sg_pass_color_image(pass, i); if (img) { SOKOL_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_BEGINPASS_IMAGE); @@ -13367,7 +14020,7 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(_sg_pass_t* pass) { } const _sg_image_t* ds_img = _sg_pass_ds_image(pass); if (ds_img) { - const _sg_attachment_t* att = &pass->cmn.ds_att; + const _sg_pass_attachment_t* att = &pass->cmn.ds_att; SOKOL_VALIDATE(ds_img->slot.state == SG_RESOURCESTATE_VALID, _SG_VALIDATE_BEGINPASS_IMAGE); SOKOL_VALIDATE(ds_img->slot.id == att->image_id.id, _SG_VALIDATE_BEGINPASS_IMAGE); } @@ -13397,10 +14050,12 @@ _SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) { const _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, _sg.cur_pass.id); if (pass) { /* an offscreen pass */ - const _sg_image_t* att_img = _sg_pass_color_image(pass, 0); SOKOL_VALIDATE(pip->cmn.color_attachment_count == pass->cmn.num_color_atts, _SG_VALIDATE_APIP_ATT_COUNT); - SOKOL_VALIDATE(pip->cmn.color_format == att_img->cmn.pixel_format, _SG_VALIDATE_APIP_COLOR_FORMAT); - SOKOL_VALIDATE(pip->cmn.sample_count == att_img->cmn.sample_count, _SG_VALIDATE_APIP_SAMPLE_COUNT); + for (int i = 0; i < pip->cmn.color_attachment_count; i++) { + const _sg_image_t* att_img = _sg_pass_color_image(pass, i); + SOKOL_VALIDATE(pip->cmn.color_formats[i] == att_img->cmn.pixel_format, _SG_VALIDATE_APIP_COLOR_FORMAT); + SOKOL_VALIDATE(pip->cmn.sample_count == att_img->cmn.sample_count, _SG_VALIDATE_APIP_SAMPLE_COUNT); + } const _sg_image_t* att_dsimg = _sg_pass_ds_image(pass); if (att_dsimg) { SOKOL_VALIDATE(pip->cmn.depth_format == att_dsimg->cmn.pixel_format, _SG_VALIDATE_APIP_DEPTH_FORMAT); @@ -13412,7 +14067,7 @@ _SOKOL_PRIVATE bool _sg_validate_apply_pipeline(sg_pipeline pip_id) { else { /* default pass */ SOKOL_VALIDATE(pip->cmn.color_attachment_count == 1, _SG_VALIDATE_APIP_ATT_COUNT); - SOKOL_VALIDATE(pip->cmn.color_format == _sg.desc.context.color_format, _SG_VALIDATE_APIP_COLOR_FORMAT); + SOKOL_VALIDATE(pip->cmn.color_formats[0] == _sg.desc.context.color_format, _SG_VALIDATE_APIP_COLOR_FORMAT); SOKOL_VALIDATE(pip->cmn.depth_format == _sg.desc.context.depth_format, _SG_VALIDATE_APIP_DEPTH_FORMAT); SOKOL_VALIDATE(pip->cmn.sample_count == _sg.desc.context.sample_count, _SG_VALIDATE_APIP_SAMPLE_COUNT); } @@ -13482,7 +14137,7 @@ _SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { const _sg_image_t* img = _sg_lookup_image(&_sg.pools, bindings->vs_images[i].id); SOKOL_VALIDATE(img != 0, _SG_VALIDATE_ABND_VS_IMG_EXISTS); if (img && img->slot.state == SG_RESOURCESTATE_VALID) { - SOKOL_VALIDATE(img->cmn.type == stage->images[i].type, _SG_VALIDATE_ABND_VS_IMG_TYPES); + SOKOL_VALIDATE(img->cmn.type == stage->images[i].image_type, _SG_VALIDATE_ABND_VS_IMG_TYPES); } } else { @@ -13498,7 +14153,7 @@ _SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { const _sg_image_t* img = _sg_lookup_image(&_sg.pools, bindings->fs_images[i].id); SOKOL_VALIDATE(img != 0, _SG_VALIDATE_ABND_FS_IMG_EXISTS); if (img && img->slot.state == SG_RESOURCESTATE_VALID) { - SOKOL_VALIDATE(img->cmn.type == stage->images[i].type, _SG_VALIDATE_ABND_FS_IMG_TYPES); + SOKOL_VALIDATE(img->cmn.type == stage->images[i].image_type, _SG_VALIDATE_ABND_FS_IMG_TYPES); } } else { @@ -13509,12 +14164,11 @@ _SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { #endif } -_SOKOL_PRIVATE bool _sg_validate_apply_uniforms(sg_shader_stage stage_index, int ub_index, const void* data, int num_bytes) { - _SOKOL_UNUSED(data); +_SOKOL_PRIVATE bool _sg_validate_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { #if !defined(SOKOL_DEBUG) _SOKOL_UNUSED(stage_index); _SOKOL_UNUSED(ub_index); - _SOKOL_UNUSED(num_bytes); + _SOKOL_UNUSED(data); return true; #else SOKOL_ASSERT((stage_index == SG_SHADERSTAGE_VS) || (stage_index == SG_SHADERSTAGE_FS)); @@ -13530,46 +14184,44 @@ _SOKOL_PRIVATE bool _sg_validate_apply_uniforms(sg_shader_stage stage_index, int SOKOL_VALIDATE(ub_index < stage->num_uniform_blocks, _SG_VALIDATE_AUB_NO_UB_AT_SLOT); /* check that the provided data size doesn't exceed the uniform block size */ - SOKOL_VALIDATE(num_bytes <= stage->uniform_blocks[ub_index].size, _SG_VALIDATE_AUB_SIZE); + SOKOL_VALIDATE(data->size <= stage->uniform_blocks[ub_index].size, _SG_VALIDATE_AUB_SIZE); return SOKOL_VALIDATE_END(); #endif } -_SOKOL_PRIVATE bool _sg_validate_update_buffer(const _sg_buffer_t* buf, const void* data, int size) { +_SOKOL_PRIVATE bool _sg_validate_update_buffer(const _sg_buffer_t* buf, const sg_range* data) { #if !defined(SOKOL_DEBUG) _SOKOL_UNUSED(buf); _SOKOL_UNUSED(data); - _SOKOL_UNUSED(size); return true; #else - SOKOL_ASSERT(buf && data); + SOKOL_ASSERT(buf && data && data->ptr); SOKOL_VALIDATE_BEGIN(); SOKOL_VALIDATE(buf->cmn.usage != SG_USAGE_IMMUTABLE, _SG_VALIDATE_UPDATEBUF_USAGE); - SOKOL_VALIDATE(buf->cmn.size >= size, _SG_VALIDATE_UPDATEBUF_SIZE); + SOKOL_VALIDATE(buf->cmn.size >= (int)data->size, _SG_VALIDATE_UPDATEBUF_SIZE); SOKOL_VALIDATE(buf->cmn.update_frame_index != _sg.frame_index, _SG_VALIDATE_UPDATEBUF_ONCE); SOKOL_VALIDATE(buf->cmn.append_frame_index != _sg.frame_index, _SG_VALIDATE_UPDATEBUF_APPEND); return SOKOL_VALIDATE_END(); #endif } -_SOKOL_PRIVATE bool _sg_validate_append_buffer(const _sg_buffer_t* buf, const void* data, int size) { +_SOKOL_PRIVATE bool _sg_validate_append_buffer(const _sg_buffer_t* buf, const sg_range* data) { #if !defined(SOKOL_DEBUG) _SOKOL_UNUSED(buf); _SOKOL_UNUSED(data); - _SOKOL_UNUSED(size); return true; #else - SOKOL_ASSERT(buf && data); + SOKOL_ASSERT(buf && data && data->ptr); SOKOL_VALIDATE_BEGIN(); SOKOL_VALIDATE(buf->cmn.usage != SG_USAGE_IMMUTABLE, _SG_VALIDATE_APPENDBUF_USAGE); - SOKOL_VALIDATE(buf->cmn.size >= (buf->cmn.append_pos+size), _SG_VALIDATE_APPENDBUF_SIZE); + SOKOL_VALIDATE(buf->cmn.size >= (buf->cmn.append_pos + (int)data->size), _SG_VALIDATE_APPENDBUF_SIZE); SOKOL_VALIDATE(buf->cmn.update_frame_index != _sg.frame_index, _SG_VALIDATE_APPENDBUF_UPDATE); return SOKOL_VALIDATE_END(); #endif } -_SOKOL_PRIVATE bool _sg_validate_update_image(const _sg_image_t* img, const sg_image_content* data) { +_SOKOL_PRIVATE bool _sg_validate_update_image(const _sg_image_t* img, const sg_image_data* data) { #if !defined(SOKOL_DEBUG) _SOKOL_UNUSED(img); _SOKOL_UNUSED(data); @@ -13588,8 +14240,8 @@ _SOKOL_PRIVATE bool _sg_validate_update_image(const _sg_image_t* img, const sg_i 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.depth; - SOKOL_VALIDATE(data->subimage[face_index][mip_index].size <= expected_size, _SG_VALIDATE_UPDIMG_SIZE); + 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); } } return SOKOL_VALIDATE_END(); @@ -13601,13 +14253,19 @@ _SOKOL_PRIVATE sg_buffer_desc _sg_buffer_desc_defaults(const sg_buffer_desc* des sg_buffer_desc def = *desc; def.type = _sg_def(def.type, SG_BUFFERTYPE_VERTEXBUFFER); def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); + if (def.size == 0) { + def.size = def.data.size; + } + else if (def.data.size == 0) { + def.data.size = def.size; + } return def; } _SOKOL_PRIVATE sg_image_desc _sg_image_desc_defaults(const sg_image_desc* desc) { sg_image_desc def = *desc; def.type = _sg_def(def.type, SG_IMAGETYPE_2D); - def.depth = _sg_def(def.depth, 1); + def.num_slices = _sg_def(def.num_slices, 1); def.num_mipmaps = _sg_def(def.num_mipmaps, 1); def.usage = _sg_def(def.usage, SG_USAGE_IMMUTABLE); if (desc->render_target) { @@ -13663,7 +14321,7 @@ _SOKOL_PRIVATE sg_shader_desc _sg_shader_desc_defaults(const sg_shader_desc* des } for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; - if (img_desc->type == _SG_IMAGETYPE_DEFAULT) { + if (img_desc->image_type == _SG_IMAGETYPE_DEFAULT) { break; } img_desc->sampler_type = _sg_def(img_desc->sampler_type, SG_SAMPLERTYPE_FLOAT); @@ -13677,43 +14335,44 @@ _SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_des def.primitive_type = _sg_def(def.primitive_type, SG_PRIMITIVETYPE_TRIANGLES); def.index_type = _sg_def(def.index_type, SG_INDEXTYPE_NONE); + def.cull_mode = _sg_def(def.cull_mode, SG_CULLMODE_NONE); + def.face_winding = _sg_def(def.face_winding, SG_FACEWINDING_CW); + def.sample_count = _sg_def(def.sample_count, _sg.desc.context.sample_count); - def.depth_stencil.stencil_front.fail_op = _sg_def(def.depth_stencil.stencil_front.fail_op, SG_STENCILOP_KEEP); - def.depth_stencil.stencil_front.depth_fail_op = _sg_def(def.depth_stencil.stencil_front.depth_fail_op, SG_STENCILOP_KEEP); - def.depth_stencil.stencil_front.pass_op = _sg_def(def.depth_stencil.stencil_front.pass_op, SG_STENCILOP_KEEP); - def.depth_stencil.stencil_front.compare_func = _sg_def(def.depth_stencil.stencil_front.compare_func, SG_COMPAREFUNC_ALWAYS); - def.depth_stencil.stencil_back.fail_op = _sg_def(def.depth_stencil.stencil_back.fail_op, SG_STENCILOP_KEEP); - def.depth_stencil.stencil_back.depth_fail_op = _sg_def(def.depth_stencil.stencil_back.depth_fail_op, SG_STENCILOP_KEEP); - def.depth_stencil.stencil_back.pass_op = _sg_def(def.depth_stencil.stencil_back.pass_op, SG_STENCILOP_KEEP); - def.depth_stencil.stencil_back.compare_func = _sg_def(def.depth_stencil.stencil_back.compare_func, SG_COMPAREFUNC_ALWAYS); - def.depth_stencil.depth_compare_func = _sg_def(def.depth_stencil.depth_compare_func, SG_COMPAREFUNC_ALWAYS); + def.stencil.front.compare = _sg_def(def.stencil.front.compare, SG_COMPAREFUNC_ALWAYS); + def.stencil.front.fail_op = _sg_def(def.stencil.front.fail_op, SG_STENCILOP_KEEP); + def.stencil.front.depth_fail_op = _sg_def(def.stencil.front.depth_fail_op, SG_STENCILOP_KEEP); + def.stencil.front.pass_op = _sg_def(def.stencil.front.pass_op, SG_STENCILOP_KEEP); + def.stencil.back.compare = _sg_def(def.stencil.back.compare, SG_COMPAREFUNC_ALWAYS); + def.stencil.back.fail_op = _sg_def(def.stencil.back.fail_op, SG_STENCILOP_KEEP); + def.stencil.back.depth_fail_op = _sg_def(def.stencil.back.depth_fail_op, SG_STENCILOP_KEEP); + def.stencil.back.pass_op = _sg_def(def.stencil.back.pass_op, SG_STENCILOP_KEEP); - def.blend.src_factor_rgb = _sg_def(def.blend.src_factor_rgb, SG_BLENDFACTOR_ONE); - def.blend.dst_factor_rgb = _sg_def(def.blend.dst_factor_rgb, SG_BLENDFACTOR_ZERO); - def.blend.op_rgb = _sg_def(def.blend.op_rgb, SG_BLENDOP_ADD); - def.blend.src_factor_alpha = _sg_def(def.blend.src_factor_alpha, SG_BLENDFACTOR_ONE); - def.blend.dst_factor_alpha = _sg_def(def.blend.dst_factor_alpha, SG_BLENDFACTOR_ZERO); - def.blend.op_alpha = _sg_def(def.blend.op_alpha, SG_BLENDOP_ADD); - if (def.blend.color_write_mask == SG_COLORMASK_NONE) { - def.blend.color_write_mask = 0; + def.depth.compare = _sg_def(def.depth.compare, SG_COMPAREFUNC_ALWAYS); + def.depth.pixel_format = _sg_def(def.depth.pixel_format, _sg.desc.context.depth_format); + def.color_count = _sg_def(def.color_count, 1); + if (def.color_count > SG_MAX_COLOR_ATTACHMENTS) { + def.color_count = SG_MAX_COLOR_ATTACHMENTS; } - else { - def.blend.color_write_mask = (uint8_t) _sg_def((sg_color_mask)def.blend.color_write_mask, SG_COLORMASK_RGBA); + for (int i = 0; i < def.color_count; i++) { + sg_color_state* cs = &def.colors[i]; + cs->pixel_format = _sg_def(cs->pixel_format, _sg.desc.context.color_format); + cs->write_mask = _sg_def(cs->write_mask, SG_COLORMASK_RGBA); + sg_blend_state* bs = &def.colors[i].blend; + bs->src_factor_rgb = _sg_def(bs->src_factor_rgb, SG_BLENDFACTOR_ONE); + bs->dst_factor_rgb = _sg_def(bs->dst_factor_rgb, SG_BLENDFACTOR_ZERO); + bs->op_rgb = _sg_def(bs->op_rgb, SG_BLENDOP_ADD); + bs->src_factor_alpha = _sg_def(bs->src_factor_alpha, SG_BLENDFACTOR_ONE); + bs->dst_factor_alpha = _sg_def(bs->dst_factor_alpha, SG_BLENDFACTOR_ZERO); + bs->op_alpha = _sg_def(bs->op_alpha, SG_BLENDOP_ADD); } - def.blend.color_attachment_count = _sg_def(def.blend.color_attachment_count, 1); - def.blend.color_format = _sg_def(def.blend.color_format, _sg.desc.context.color_format); - def.blend.depth_format = _sg_def(def.blend.depth_format, _sg.desc.context.depth_format); - - def.rasterizer.cull_mode = _sg_def(def.rasterizer.cull_mode, SG_CULLMODE_NONE); - def.rasterizer.face_winding = _sg_def(def.rasterizer.face_winding, SG_FACEWINDING_CW); - def.rasterizer.sample_count = _sg_def(def.rasterizer.sample_count, _sg.desc.context.sample_count); for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) { sg_vertex_attr_desc* a_desc = &def.layout.attrs[attr_index]; if (a_desc->format == SG_VERTEXFORMAT_INVALID) { break; } - SOKOL_ASSERT((a_desc->buffer_index >= 0) && (a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS)); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); sg_buffer_layout_desc* b_desc = &def.layout.buffers[a_desc->buffer_index]; b_desc->step_func = _sg_def(b_desc->step_func, SG_VERTEXSTEP_PER_VERTEX); b_desc->step_rate = _sg_def(b_desc->step_rate, 1); @@ -13734,7 +14393,7 @@ _SOKOL_PRIVATE sg_pipeline_desc _sg_pipeline_desc_defaults(const sg_pipeline_des if (a_desc->format == SG_VERTEXFORMAT_INVALID) { break; } - SOKOL_ASSERT((a_desc->buffer_index >= 0) && (a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS)); + SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); if (use_auto_offset) { a_desc->offset = auto_offset[a_desc->buffer_index]; } @@ -13823,6 +14482,46 @@ _SOKOL_PRIVATE sg_pass _sg_alloc_pass(void) { return res; } +_SOKOL_PRIVATE void _sg_dealloc_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(buf_id.id != SG_INVALID_ID); + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + SOKOL_ASSERT(buf && buf->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&buf->slot); + _sg_pool_free_index(&_sg.pools.buffer_pool, _sg_slot_index(buf_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_image(sg_image img_id) { + SOKOL_ASSERT(img_id.id != SG_INVALID_ID); + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + SOKOL_ASSERT(img && img->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&img->slot); + _sg_pool_free_index(&_sg.pools.image_pool, _sg_slot_index(img_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_shader(sg_shader shd_id) { + SOKOL_ASSERT(shd_id.id != SG_INVALID_ID); + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + SOKOL_ASSERT(shd && shd->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&shd->slot); + _sg_pool_free_index(&_sg.pools.shader_pool, _sg_slot_index(shd_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(pip_id.id != SG_INVALID_ID); + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + SOKOL_ASSERT(pip && pip->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&pip->slot); + _sg_pool_free_index(&_sg.pools.pipeline_pool, _sg_slot_index(pip_id.id)); +} + +_SOKOL_PRIVATE void _sg_dealloc_pass(sg_pass pass_id) { + SOKOL_ASSERT(pass_id.id != SG_INVALID_ID); + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); + _sg_reset_slot(&pass->slot); + _sg_pool_free_index(&_sg.pools.pass_pool, _sg_slot_index(pass_id.id)); +} + _SOKOL_PRIVATE void _sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc) { SOKOL_ASSERT(buf_id.id != SG_INVALID_ID && desc); _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); @@ -13920,12 +14619,92 @@ _SOKOL_PRIVATE void _sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { SOKOL_ASSERT((pass->slot.state == SG_RESOURCESTATE_VALID)||(pass->slot.state == SG_RESOURCESTATE_FAILED)); } +_SOKOL_PRIVATE bool _sg_uninit_buffer(sg_buffer buf_id) { + _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); + if (buf) { + if (buf->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_buffer(buf); + _sg_reset_buffer(buf); + return true; + } + else { + SOKOL_LOG("_sg_uninit_buffer: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_image(sg_image img_id) { + _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); + if (img) { + if (img->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_image(img); + _sg_reset_image(img); + return true; + } + else { + SOKOL_LOG("_sg_uninit_image: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_shader(sg_shader shd_id) { + _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); + if (shd) { + if (shd->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_shader(shd); + _sg_reset_shader(shd); + return true; + } + else { + SOKOL_LOG("_sg_uninit_shader: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_pipeline(sg_pipeline pip_id) { + _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); + if (pip) { + if (pip->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_pipeline(pip); + _sg_reset_pipeline(pip); + return true; + } + else { + SOKOL_LOG("_sg_uninit_pipeline: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + +_SOKOL_PRIVATE bool _sg_uninit_pass(sg_pass pass_id) { + _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); + if (pass) { + if (pass->slot.ctx_id == _sg.active_context.id) { + _sg_destroy_pass(pass); + _sg_reset_pass(pass); + return true; + } + else { + SOKOL_LOG("_sg_uninit_pass: active context mismatch (must be same as for creation)"); + _SG_TRACE_NOARGS(err_context_mismatch); + } + } + return false; +} + /*== PUBLIC API FUNCTIONS ====================================================*/ #if defined(SOKOL_METAL) // this is ARC compatible #if defined(__cplusplus) - #define _SG_CLEAR(type, item) { item = { }; } + #define _SG_CLEAR(type, item) { item = (type) { }; } #else #define _SG_CLEAR(type, item) { item = (type) { 0 }; } #endif @@ -14043,6 +14822,7 @@ SOKOL_API_IMPL void sg_discard_context(sg_context ctx_id) { if (ctx) { _sg_destroy_context(ctx); _sg_reset_context(ctx); + _sg_reset_slot(&ctx->slot); _sg_pool_free_index(&_sg.pools.context_pool, _sg_slot_index(ctx_id.id)); } _sg.active_context.id = SG_INVALID_ID; @@ -14106,6 +14886,36 @@ SOKOL_API_IMPL sg_pass sg_alloc_pass(void) { return res; } +SOKOL_API_IMPL void sg_dealloc_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_buffer(buf_id); + _SG_TRACE_ARGS(dealloc_buffer, buf_id); +} + +SOKOL_API_IMPL void sg_dealloc_image(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_image(img_id); + _SG_TRACE_ARGS(dealloc_image, img_id); +} + +SOKOL_API_IMPL void sg_dealloc_shader(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_shader(shd_id); + _SG_TRACE_ARGS(dealloc_shader, shd_id); +} + +SOKOL_API_IMPL void sg_dealloc_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_pipeline(pip_id); + _SG_TRACE_ARGS(dealloc_pipeline, pip_id); +} + +SOKOL_API_IMPL void sg_dealloc_pass(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + _sg_dealloc_pass(pass_id); + _SG_TRACE_ARGS(dealloc_pass, pass_id); +} + SOKOL_API_IMPL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc) { SOKOL_ASSERT(_sg.valid); sg_buffer_desc desc_def = _sg_buffer_desc_defaults(desc); @@ -14141,6 +14951,41 @@ SOKOL_API_IMPL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { _SG_TRACE_ARGS(init_pass, pass_id, &desc_def); } +SOKOL_API_IMPL bool sg_uninit_buffer(sg_buffer buf_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_buffer(buf_id); + _SG_TRACE_ARGS(uninit_buffer, buf_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_image(sg_image img_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_image(img_id); + _SG_TRACE_ARGS(uninit_image, img_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_shader(sg_shader shd_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_shader(shd_id); + _SG_TRACE_ARGS(uninit_shader, shd_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_pipeline(sg_pipeline pip_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_pipeline(pip_id); + _SG_TRACE_ARGS(uninit_pipeline, pip_id); + return res; +} + +SOKOL_API_IMPL bool sg_uninit_pass(sg_pass pass_id) { + SOKOL_ASSERT(_sg.valid); + bool res = _sg_uninit_pass(pass_id); + _SG_TRACE_ARGS(uninit_pass, pass_id); + return res; +} + /*-- set allocated resource to failed state ----------------------------------*/ SOKOL_API_IMPL void sg_fail_buffer(sg_buffer buf_id) { SOKOL_ASSERT(_sg.valid); @@ -14313,85 +15158,40 @@ SOKOL_API_IMPL sg_pass sg_make_pass(const sg_pass_desc* desc) { SOKOL_API_IMPL void sg_destroy_buffer(sg_buffer buf_id) { SOKOL_ASSERT(_sg.valid); _SG_TRACE_ARGS(destroy_buffer, buf_id); - _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if (buf) { - if (buf->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_buffer(buf); - _sg_reset_buffer(buf); - _sg_pool_free_index(&_sg.pools.buffer_pool, _sg_slot_index(buf_id.id)); - } - else { - SOKOL_LOG("sg_destroy_buffer: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + if (_sg_uninit_buffer(buf_id)) { + _sg_dealloc_buffer(buf_id); } } SOKOL_API_IMPL void sg_destroy_image(sg_image img_id) { SOKOL_ASSERT(_sg.valid); _SG_TRACE_ARGS(destroy_image, img_id); - _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); - if (img) { - if (img->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_image(img); - _sg_reset_image(img); - _sg_pool_free_index(&_sg.pools.image_pool, _sg_slot_index(img_id.id)); - } - else { - SOKOL_LOG("sg_destroy_image: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + if (_sg_uninit_image(img_id)) { + _sg_dealloc_image(img_id); } } SOKOL_API_IMPL void sg_destroy_shader(sg_shader shd_id) { SOKOL_ASSERT(_sg.valid); _SG_TRACE_ARGS(destroy_shader, shd_id); - _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); - if (shd) { - if (shd->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_shader(shd); - _sg_reset_shader(shd); - _sg_pool_free_index(&_sg.pools.shader_pool, _sg_slot_index(shd_id.id)); - } - else { - SOKOL_LOG("sg_destroy_shader: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + if (_sg_uninit_shader(shd_id)) { + _sg_dealloc_shader(shd_id); } } SOKOL_API_IMPL void sg_destroy_pipeline(sg_pipeline pip_id) { SOKOL_ASSERT(_sg.valid); _SG_TRACE_ARGS(destroy_pipeline, pip_id); - _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); - if (pip) { - if (pip->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_pipeline(pip); - _sg_reset_pipeline(pip); - _sg_pool_free_index(&_sg.pools.pipeline_pool, _sg_slot_index(pip_id.id)); - } - else { - SOKOL_LOG("sg_destroy_pipeline: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + if (_sg_uninit_pipeline(pip_id)) { + _sg_dealloc_pipeline(pip_id); } } SOKOL_API_IMPL void sg_destroy_pass(sg_pass pass_id) { SOKOL_ASSERT(_sg.valid); _SG_TRACE_ARGS(destroy_pass, pass_id); - _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); - if (pass) { - if (pass->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_pass(pass); - _sg_reset_pass(pass); - _sg_pool_free_index(&_sg.pools.pass_pool, _sg_slot_index(pass_id.id)); - } - else { - SOKOL_LOG("sg_destroy_pass: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + if (_sg_uninit_pass(pass_id)) { + _sg_dealloc_pass(pass_id); } } @@ -14407,6 +15207,10 @@ SOKOL_API_IMPL void sg_begin_default_pass(const sg_pass_action* pass_action, int _SG_TRACE_ARGS(begin_default_pass, pass_action, width, height); } +SOKOL_API_IMPL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height) { + sg_begin_default_pass(pass_action, (int)width, (int)height); +} + SOKOL_API_IMPL void sg_begin_pass(sg_pass pass_id, const sg_pass_action* pass_action) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT(pass_action); @@ -14440,6 +15244,10 @@ SOKOL_API_IMPL void sg_apply_viewport(int x, int y, int width, int height, bool _SG_TRACE_ARGS(apply_viewport, x, y, width, height, origin_top_left); } +SOKOL_API_IMPL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left) { + sg_apply_viewport((int)x, (int)y, (int)width, (int)height, origin_top_left); +} + SOKOL_API_IMPL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left) { SOKOL_ASSERT(_sg.valid); if (!_sg.pass_valid) { @@ -14450,6 +15258,10 @@ SOKOL_API_IMPL void sg_apply_scissor_rect(int x, int y, int width, int height, b _SG_TRACE_ARGS(apply_scissor_rect, x, y, width, height, origin_top_left); } +SOKOL_API_IMPL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left) { + sg_apply_scissor_rect((int)x, (int)y, (int)width, (int)height, origin_top_left); +} + SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) { SOKOL_ASSERT(_sg.valid); _sg.bindings_valid = false; @@ -14543,12 +15355,12 @@ SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { } } -SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const void* data, int num_bytes) { +SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT((stage == SG_SHADERSTAGE_VS) || (stage == SG_SHADERSTAGE_FS)); SOKOL_ASSERT((ub_index >= 0) && (ub_index < SG_MAX_SHADERSTAGE_UBS)); - SOKOL_ASSERT(data && (num_bytes > 0)); - if (!_sg_validate_apply_uniforms(stage, ub_index, data, num_bytes)) { + SOKOL_ASSERT(data && data->ptr && (data->size > 0)); + if (!_sg_validate_apply_uniforms(stage, ub_index, data)) { _sg.next_draw_valid = false; _SG_TRACE_NOARGS(err_draw_invalid); return; @@ -14560,13 +15372,15 @@ SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const if (!_sg.next_draw_valid) { _SG_TRACE_NOARGS(err_draw_invalid); } - _sg_apply_uniforms(stage, ub_index, data, num_bytes); - _SG_TRACE_ARGS(apply_uniforms, stage, ub_index, data, num_bytes); + _sg_apply_uniforms(stage, ub_index, data); + _SG_TRACE_ARGS(apply_uniforms, stage, ub_index, data); } SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instances) { SOKOL_ASSERT(_sg.valid); - SOKOL_ASSERT((base_element >= 0) && (num_elements >= 0) && (num_instances >= 0)); + SOKOL_ASSERT(base_element >= 0); + SOKOL_ASSERT(num_elements >= 0); + SOKOL_ASSERT(num_instances >= 0); #if defined(SOKOL_DEBUG) if (!_sg.bindings_valid) { SOKOL_LOG("attempting to draw without resource bindings"); @@ -14621,25 +15435,27 @@ SOKOL_API_IMPL void sg_reset_state_cache(void) { _SG_TRACE_NOARGS(reset_state_cache); } -SOKOL_API_IMPL void sg_update_buffer(sg_buffer buf_id, const void* data, int num_bytes) { +SOKOL_API_IMPL void sg_update_buffer(sg_buffer buf_id, const sg_range* data) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(data && data->ptr && (data->size > 0)); _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); - if ((num_bytes > 0) && buf && (buf->slot.state == SG_RESOURCESTATE_VALID)) { - if (_sg_validate_update_buffer(buf, data, num_bytes)) { - SOKOL_ASSERT(num_bytes <= buf->cmn.size); + if ((data->size > 0) && buf && (buf->slot.state == SG_RESOURCESTATE_VALID)) { + if (_sg_validate_update_buffer(buf, data)) { + SOKOL_ASSERT(data->size <= (size_t)buf->cmn.size); /* only one update allowed per buffer and frame */ SOKOL_ASSERT(buf->cmn.update_frame_index != _sg.frame_index); /* update and append on same buffer in same frame not allowed */ SOKOL_ASSERT(buf->cmn.append_frame_index != _sg.frame_index); - _sg_update_buffer(buf, data, (uint32_t)num_bytes); + _sg_update_buffer(buf, data); buf->cmn.update_frame_index = _sg.frame_index; } } - _SG_TRACE_ARGS(update_buffer, buf_id, data, num_bytes); + _SG_TRACE_ARGS(update_buffer, buf_id, data); } -SOKOL_API_IMPL int sg_append_buffer(sg_buffer buf_id, const void* data, int num_bytes) { +SOKOL_API_IMPL int sg_append_buffer(sg_buffer buf_id, const sg_range* data) { SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(data && data->ptr); _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); int result; if (buf) { @@ -14648,16 +15464,16 @@ SOKOL_API_IMPL int sg_append_buffer(sg_buffer buf_id, const void* data, int num_ buf->cmn.append_pos = 0; buf->cmn.append_overflow = false; } - if ((buf->cmn.append_pos + _sg_roundup(num_bytes, 4)) > buf->cmn.size) { + if ((buf->cmn.append_pos + _sg_roundup((int)data->size, 4)) > buf->cmn.size) { buf->cmn.append_overflow = true; } const int start_pos = buf->cmn.append_pos; if (buf->slot.state == SG_RESOURCESTATE_VALID) { - if (_sg_validate_append_buffer(buf, data, num_bytes)) { - if (!buf->cmn.append_overflow && (num_bytes > 0)) { + if (_sg_validate_append_buffer(buf, data)) { + if (!buf->cmn.append_overflow && (data->size > 0)) { /* update and append on same buffer in same frame not allowed */ SOKOL_ASSERT(buf->cmn.update_frame_index != _sg.frame_index); - uint32_t copied_num_bytes = _sg_append_buffer(buf, data, (uint32_t)num_bytes, buf->cmn.append_frame_index != _sg.frame_index); + int copied_num_bytes = _sg_append_buffer(buf, data, buf->cmn.append_frame_index != _sg.frame_index); buf->cmn.append_pos += copied_num_bytes; buf->cmn.append_frame_index = _sg.frame_index; } @@ -14669,7 +15485,7 @@ SOKOL_API_IMPL int sg_append_buffer(sg_buffer buf_id, const void* data, int num_ /* FIXME: should we return -1 here? */ result = 0; } - _SG_TRACE_ARGS(append_buffer, buf_id, data, num_bytes, result); + _SG_TRACE_ARGS(append_buffer, buf_id, data, result); return result; } @@ -14680,7 +15496,7 @@ SOKOL_API_IMPL bool sg_query_buffer_overflow(sg_buffer buf_id) { return result; } -SOKOL_API_IMPL void sg_update_image(sg_image img_id, const sg_image_content* data) { +SOKOL_API_IMPL void sg_update_image(sg_image img_id, const sg_image_data* data) { SOKOL_ASSERT(_sg.valid); _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); if (img && img->slot.state == SG_RESOURCESTATE_VALID) { @@ -14815,6 +15631,27 @@ SOKOL_API_IMPL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc) { return _sg_pass_desc_defaults(desc); } +SOKOL_API_IMPL const void* sg_d3d11_device(void) { +#if defined(SOKOL_D3D11) + return (const void*) _sg.d3d11.dev; +#else + return 0; +#endif +} + +SOKOL_API_IMPL const void* sg_mtl_device(void) { +#if defined(SOKOL_METAL) + if (nil != _sg.mtl.device) { + return (__bridge const void*) _sg.mtl.device; + } + else { + return 0; + } +#else + return 0; +#endif +} + SOKOL_API_IMPL const void* sg_mtl_render_command_encoder(void) { #if defined(SOKOL_METAL) if (nil != _sg.mtl.cmd_encoder) { @@ -14832,4 +15669,4 @@ SOKOL_API_IMPL const void* sg_mtl_render_command_encoder(void) { #pragma warning(pop) #endif -#endif /* SOKOL_IMPL */ +#endif /* SOKOL_GFX_IMPL */ diff --git a/thirdparty/sokol/util/sokol_fontstash.h b/thirdparty/sokol/util/sokol_fontstash.h index 81b35a97f7..9bb915fb02 100644 --- a/thirdparty/sokol/util/sokol_fontstash.h +++ b/thirdparty/sokol/util/sokol_fontstash.h @@ -1,3 +1,6 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_FONTSTASH_IMPL) +#define SOKOL_FONTSTASH_IMPL +#endif #ifndef SOKOL_FONTSTASH_INCLUDED /* sokol_fontstash.h -- renderer for https://github.com/memononen/fontstash @@ -6,7 +9,7 @@ Project URL: https://github.com/floooh/sokol Do this: - + #define SOKOL_IMPL or #define SOKOL_FONTSTASH_IMPL before you include this file in *one* C or C++ file to create the @@ -27,7 +30,8 @@ SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) SOKOL_FREE(p) - your own free function (default: free(p)) - SOKOL_API_DECL - public function declaration prefix (default: extern) + SOKOL_FONTSTASH_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) @@ -159,23 +163,26 @@ #error "Please include sokol_gfx.h before sokol_fontstash.h" #endif -#ifndef SOKOL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) -#define SOKOL_API_DECL __declspec(dllexport) +#if defined(SOKOL_API_DECL) && !defined(SOKOL_FONTSTASH_API_DECL) +#define SOKOL_FONTSTASH_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_FONTSTASH_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_FONTSTASH_IMPL) +#define SOKOL_FONTSTASH_API_DECL __declspec(dllexport) #elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_API_DECL __declspec(dllimport) +#define SOKOL_FONTSTASH_API_DECL __declspec(dllimport) #else -#define SOKOL_API_DECL extern +#define SOKOL_FONTSTASH_API_DECL extern #endif #endif #ifdef __cplusplus extern "C" { #endif -SOKOL_API_DECL FONScontext* sfons_create(int width, int height, int flags); -SOKOL_API_DECL void sfons_destroy(FONScontext* ctx); -SOKOL_API_DECL void sfons_flush(FONScontext* ctx); -SOKOL_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SOKOL_FONTSTASH_API_DECL FONScontext* sfons_create(int width, int height, int flags); +SOKOL_FONTSTASH_API_DECL void sfons_destroy(FONScontext* ctx); +SOKOL_FONTSTASH_API_DECL void sfons_flush(FONScontext* ctx); +SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); #ifdef __cplusplus } /* extern "C" */ @@ -1603,7 +1610,7 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; ub->uniforms[0].array_count = 8; shd_desc.fs.images[0].name = "tex"; - shd_desc.fs.images[0].type = SG_IMAGETYPE_2D; + shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; shd_desc.fs.images[0].sampler_type = SG_SAMPLERTYPE_FLOAT; shd_desc.label = "sokol-fontstash-shader"; #if defined(SOKOL_GLCORE33) @@ -1617,16 +1624,12 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { shd_desc.fs.entry = "main0"; switch (sg_query_backend()) { case SG_BACKEND_METAL_MACOS: - shd_desc.vs.byte_code = _sfons_vs_bytecode_metal_macos; - shd_desc.vs.byte_code_size = sizeof(_sfons_vs_bytecode_metal_macos); - shd_desc.fs.byte_code = _sfons_fs_bytecode_metal_macos; - shd_desc.fs.byte_code_size = sizeof(_sfons_fs_bytecode_metal_macos); + shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_metal_macos); + shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_macos); break; case SG_BACKEND_METAL_IOS: - shd_desc.vs.byte_code = _sfons_vs_bytecode_metal_ios; - shd_desc.vs.byte_code_size = sizeof(_sfons_vs_bytecode_metal_ios); - shd_desc.fs.byte_code = _sfons_fs_bytecode_metal_ios; - shd_desc.fs.byte_code_size = sizeof(_sfons_fs_bytecode_metal_ios); + shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_metal_ios); + shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_ios); break; default: shd_desc.vs.source = _sfons_vs_source_metal_sim; @@ -1634,10 +1637,8 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { break; } #elif defined(SOKOL_D3D11) - shd_desc.vs.byte_code = _sfons_vs_bytecode_hlsl4; - shd_desc.vs.byte_code_size = sizeof(_sfons_vs_bytecode_hlsl4); - shd_desc.fs.byte_code = _sfons_fs_bytecode_hlsl4; - shd_desc.fs.byte_code_size = sizeof(_sfons_fs_bytecode_hlsl4); + shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_hlsl4); + shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_hlsl4); #elif defined(SOKOL_WGPU) shd_desc.vs.byte_code = _sfons_vs_bytecode_wgpu; shd_desc.vs.byte_code_size = sizeof(_sfons_vs_bytecode_wgpu); @@ -1656,9 +1657,9 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { sg_pipeline_desc pip_desc; memset(&pip_desc, 0, sizeof(pip_desc)); pip_desc.shader = sfons->shd; - pip_desc.blend.enabled = true; - pip_desc.blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + pip_desc.colors[0].blend.enabled = true; + pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; + pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; sfons->pip = sgl_make_pipeline(&pip_desc); } @@ -1769,16 +1770,16 @@ SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) { _sfons_t* sfons = (_sfons_t*) ctx->params.userPtr; if (sfons->img_dirty) { sfons->img_dirty = false; - sg_image_content content; - memset(&content, 0, sizeof(content)); - content.subimage[0][0].ptr = ctx->texData; - content.subimage[0][0].size = sfons->width * sfons->height; - sg_update_image(sfons->img, &content); + sg_image_data data; + memset(&data, 0, sizeof(data)); + data.subimage[0][0].ptr = ctx->texData; + data.subimage[0][0].size = (size_t) (sfons->width * sfons->height); + sg_update_image(sfons->img, &data); } } SOKOL_API_IMPL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - return (r) | (g<<8) | (b<<16) | (a<<24); + return ((uint32_t)r) | ((uint32_t)g<<8) | ((uint32_t)b<<16) | ((uint32_t)a<<24); } #endif /* SOKOL_FONTSTASH_IMPL */ diff --git a/thirdparty/sokol/util/sokol_gl.h b/thirdparty/sokol/util/sokol_gl.h index e7b7b5537e..e41fc06bb1 100644 --- a/thirdparty/sokol/util/sokol_gl.h +++ b/thirdparty/sokol/util/sokol_gl.h @@ -1,3 +1,6 @@ +#if defined(SOKOL_IMPL) && !defined(SOKOL_GL_IMPL) +#define SOKOL_GL_IMPL +#endif #ifndef SOKOL_GL_INCLUDED /* sokol_gl.h -- OpenGL 1.x style rendering on top of sokol_gfx.h @@ -5,6 +8,7 @@ Project URL: https://github.com/floooh/sokol Do this: + #define SOKOL_IMPL or #define SOKOL_GL_IMPL before you include this file in *one* C or C++ file to create the implementation. @@ -25,7 +29,8 @@ SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) SOKOL_FREE(p) - your own free function (default: free(p)) - SOKOL_API_DECL - public function declaration prefix (default: extern) + SOKOL_GL_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_DECL - same as SOKOL_GL_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) @@ -35,7 +40,7 @@ SOKOL_DLL - On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport) + On Windows, SOKOL_DLL will define SOKOL_GL_API_DECL as __declspec(dllexport) or __declspec(dllimport) as needed. Include the following headers before including sokol_gl.h: @@ -201,6 +206,13 @@ sgl_viewport(int x, int y, int w, int h, bool origin_top_left) sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left) + ...or call these alternatives which take float arguments (this might allow + to avoid casting between float and integer in more strongly typed languages + when floating point pixel coordinates are used): + + sgl_viewportf(float x, float y, float w, float h, bool origin_top_left) + sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left) + ...these calls add a new command to the internal command queue, so that the viewport or scissor rect are set at the right time relative to other sokol-gl calls. @@ -445,13 +457,16 @@ #error "Please include sokol_gfx.h before sokol_gl.h" #endif -#ifndef SOKOL_API_DECL -#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) -#define SOKOL_API_DECL __declspec(dllexport) +#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL) +#define SOKOL_GL_API_DECL SOKOL_API_DECL +#endif +#ifndef SOKOL_GL_API_DECL +#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GL_IMPL) +#define SOKOL_GL_API_DECL __declspec(dllexport) #elif defined(_WIN32) && defined(SOKOL_DLL) -#define SOKOL_API_DECL __declspec(dllimport) +#define SOKOL_GL_API_DECL __declspec(dllimport) #else -#define SOKOL_API_DECL extern +#define SOKOL_GL_API_DECL extern #endif #endif @@ -488,92 +503,94 @@ typedef struct sgl_desc_t { } sgl_desc_t; /* setup/shutdown/misc */ -SOKOL_API_DECL void sgl_setup(const sgl_desc_t* desc); -SOKOL_API_DECL void sgl_shutdown(void); -SOKOL_API_DECL sgl_error_t sgl_error(void); -SOKOL_API_DECL void sgl_defaults(void); -SOKOL_API_DECL float sgl_rad(float deg); -SOKOL_API_DECL float sgl_deg(float rad); +SOKOL_GL_API_DECL void sgl_setup(const sgl_desc_t* desc); +SOKOL_GL_API_DECL void sgl_shutdown(void); +SOKOL_GL_API_DECL sgl_error_t sgl_error(void); +SOKOL_GL_API_DECL void sgl_defaults(void); +SOKOL_GL_API_DECL float sgl_rad(float deg); +SOKOL_GL_API_DECL float sgl_deg(float rad); /* create and destroy pipeline objects */ -SOKOL_API_DECL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc); -SOKOL_API_DECL void sgl_destroy_pipeline(sgl_pipeline pip); +SOKOL_GL_API_DECL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc); +SOKOL_GL_API_DECL void sgl_destroy_pipeline(sgl_pipeline pip); /* render state functions */ -SOKOL_API_DECL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left); -SOKOL_API_DECL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left); -SOKOL_API_DECL void sgl_enable_texture(void); -SOKOL_API_DECL void sgl_disable_texture(void); -SOKOL_API_DECL void sgl_texture(sg_image img); +SOKOL_GL_API_DECL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left); +SOKOL_GL_API_DECL void sgl_viewportf(float x, float y, float w, float h, bool origin_top_left); +SOKOL_GL_API_DECL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left); +SOKOL_GL_API_DECL void sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left); +SOKOL_GL_API_DECL void sgl_enable_texture(void); +SOKOL_GL_API_DECL void sgl_disable_texture(void); +SOKOL_GL_API_DECL void sgl_texture(sg_image img); /* pipeline stack functions */ -SOKOL_API_DECL void sgl_default_pipeline(void); -SOKOL_API_DECL void sgl_load_pipeline(sgl_pipeline pip); -SOKOL_API_DECL void sgl_push_pipeline(void); -SOKOL_API_DECL void sgl_pop_pipeline(void); +SOKOL_GL_API_DECL void sgl_default_pipeline(void); +SOKOL_GL_API_DECL void sgl_load_pipeline(sgl_pipeline pip); +SOKOL_GL_API_DECL void sgl_push_pipeline(void); +SOKOL_GL_API_DECL void sgl_pop_pipeline(void); /* matrix stack functions */ -SOKOL_API_DECL void sgl_matrix_mode_modelview(void); -SOKOL_API_DECL void sgl_matrix_mode_projection(void); -SOKOL_API_DECL void sgl_matrix_mode_texture(void); -SOKOL_API_DECL void sgl_load_identity(void); -SOKOL_API_DECL void sgl_load_matrix(const float m[16]); -SOKOL_API_DECL void sgl_load_transpose_matrix(const float m[16]); -SOKOL_API_DECL void sgl_mult_matrix(const float m[16]); -SOKOL_API_DECL void sgl_mult_transpose_matrix(const float m[16]); -SOKOL_API_DECL void sgl_rotate(float angle_rad, float x, float y, float z); -SOKOL_API_DECL void sgl_scale(float x, float y, float z); -SOKOL_API_DECL void sgl_translate(float x, float y, float z); -SOKOL_API_DECL void sgl_frustum(float l, float r, float b, float t, float n, float f); -SOKOL_API_DECL void sgl_ortho(float l, float r, float b, float t, float n, float f); -SOKOL_API_DECL void sgl_perspective(float fov_y, float aspect, float z_near, float z_far); -SOKOL_API_DECL void sgl_lookat(float eye_x, float eye_y, float eye_z, float center_x, float center_y, float center_z, float up_x, float up_y, float up_z); -SOKOL_API_DECL void sgl_push_matrix(void); -SOKOL_API_DECL void sgl_pop_matrix(void); +SOKOL_GL_API_DECL void sgl_matrix_mode_modelview(void); +SOKOL_GL_API_DECL void sgl_matrix_mode_projection(void); +SOKOL_GL_API_DECL void sgl_matrix_mode_texture(void); +SOKOL_GL_API_DECL void sgl_load_identity(void); +SOKOL_GL_API_DECL void sgl_load_matrix(const float m[16]); +SOKOL_GL_API_DECL void sgl_load_transpose_matrix(const float m[16]); +SOKOL_GL_API_DECL void sgl_mult_matrix(const float m[16]); +SOKOL_GL_API_DECL void sgl_mult_transpose_matrix(const float m[16]); +SOKOL_GL_API_DECL void sgl_rotate(float angle_rad, float x, float y, float z); +SOKOL_GL_API_DECL void sgl_scale(float x, float y, float z); +SOKOL_GL_API_DECL void sgl_translate(float x, float y, float z); +SOKOL_GL_API_DECL void sgl_frustum(float l, float r, float b, float t, float n, float f); +SOKOL_GL_API_DECL void sgl_ortho(float l, float r, float b, float t, float n, float f); +SOKOL_GL_API_DECL void sgl_perspective(float fov_y, float aspect, float z_near, float z_far); +SOKOL_GL_API_DECL void sgl_lookat(float eye_x, float eye_y, float eye_z, float center_x, float center_y, float center_z, float up_x, float up_y, float up_z); +SOKOL_GL_API_DECL void sgl_push_matrix(void); +SOKOL_GL_API_DECL void sgl_pop_matrix(void); /* these functions only set the internal 'current texcoord / color' (valid inside or outside begin/end) */ -SOKOL_API_DECL void sgl_t2f(float u, float v); -SOKOL_API_DECL void sgl_c3f(float r, float g, float b); -SOKOL_API_DECL void sgl_c4f(float r, float g, float b, float a); -SOKOL_API_DECL void sgl_c3b(uint8_t r, uint8_t g, uint8_t b); -SOKOL_API_DECL void sgl_c4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_API_DECL void sgl_c1i(uint32_t rgba); +SOKOL_GL_API_DECL void sgl_t2f(float u, float v); +SOKOL_GL_API_DECL void sgl_c3f(float r, float g, float b); +SOKOL_GL_API_DECL void sgl_c4f(float r, float g, float b, float a); +SOKOL_GL_API_DECL void sgl_c3b(uint8_t r, uint8_t g, uint8_t b); +SOKOL_GL_API_DECL void sgl_c4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SOKOL_GL_API_DECL void sgl_c1i(uint32_t rgba); /* define primitives, each begin/end is one draw command */ -SOKOL_API_DECL void sgl_begin_points(void); -SOKOL_API_DECL void sgl_begin_lines(void); -SOKOL_API_DECL void sgl_begin_line_strip(void); -SOKOL_API_DECL void sgl_begin_triangles(void); -SOKOL_API_DECL void sgl_begin_triangle_strip(void); -SOKOL_API_DECL void sgl_begin_quads(void); -SOKOL_API_DECL void sgl_v2f(float x, float y); -SOKOL_API_DECL void sgl_v3f(float x, float y, float z); -SOKOL_API_DECL void sgl_v2f_t2f(float x, float y, float u, float v); -SOKOL_API_DECL void sgl_v3f_t2f(float x, float y, float z, float u, float v); -SOKOL_API_DECL void sgl_v2f_c3f(float x, float y, float r, float g, float b); -SOKOL_API_DECL void sgl_v2f_c3b(float x, float y, uint8_t r, uint8_t g, uint8_t b); -SOKOL_API_DECL void sgl_v2f_c4f(float x, float y, float r, float g, float b, float a); -SOKOL_API_DECL void sgl_v2f_c4b(float x, float y, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_API_DECL void sgl_v2f_c1i(float x, float y, uint32_t rgba); -SOKOL_API_DECL void sgl_v3f_c3f(float x, float y, float z, float r, float g, float b); -SOKOL_API_DECL void sgl_v3f_c3b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b); -SOKOL_API_DECL void sgl_v3f_c4f(float x, float y, float z, float r, float g, float b, float a); -SOKOL_API_DECL void sgl_v3f_c4b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_API_DECL void sgl_v3f_c1i(float x, float y, float z, uint32_t rgba); -SOKOL_API_DECL void sgl_v2f_t2f_c3f(float x, float y, float u, float v, float r, float g, float b); -SOKOL_API_DECL void sgl_v2f_t2f_c3b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b); -SOKOL_API_DECL void sgl_v2f_t2f_c4f(float x, float y, float u, float v, float r, float g, float b, float a); -SOKOL_API_DECL void sgl_v2f_t2f_c4b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_API_DECL void sgl_v2f_t2f_c1i(float x, float y, float u, float v, uint32_t rgba); -SOKOL_API_DECL void sgl_v3f_t2f_c3f(float x, float y, float z, float u, float v, float r, float g, float b); -SOKOL_API_DECL void sgl_v3f_t2f_c3b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b); -SOKOL_API_DECL void sgl_v3f_t2f_c4f(float x, float y, float z, float u, float v, float r, float g, float b, float a); -SOKOL_API_DECL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -SOKOL_API_DECL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba); -SOKOL_API_DECL void sgl_end(void); +SOKOL_GL_API_DECL void sgl_begin_points(void); +SOKOL_GL_API_DECL void sgl_begin_lines(void); +SOKOL_GL_API_DECL void sgl_begin_line_strip(void); +SOKOL_GL_API_DECL void sgl_begin_triangles(void); +SOKOL_GL_API_DECL void sgl_begin_triangle_strip(void); +SOKOL_GL_API_DECL void sgl_begin_quads(void); +SOKOL_GL_API_DECL void sgl_v2f(float x, float y); +SOKOL_GL_API_DECL void sgl_v3f(float x, float y, float z); +SOKOL_GL_API_DECL void sgl_v2f_t2f(float x, float y, float u, float v); +SOKOL_GL_API_DECL void sgl_v3f_t2f(float x, float y, float z, float u, float v); +SOKOL_GL_API_DECL void sgl_v2f_c3f(float x, float y, float r, float g, float b); +SOKOL_GL_API_DECL void sgl_v2f_c3b(float x, float y, uint8_t r, uint8_t g, uint8_t b); +SOKOL_GL_API_DECL void sgl_v2f_c4f(float x, float y, float r, float g, float b, float a); +SOKOL_GL_API_DECL void sgl_v2f_c4b(float x, float y, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SOKOL_GL_API_DECL void sgl_v2f_c1i(float x, float y, uint32_t rgba); +SOKOL_GL_API_DECL void sgl_v3f_c3f(float x, float y, float z, float r, float g, float b); +SOKOL_GL_API_DECL void sgl_v3f_c3b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b); +SOKOL_GL_API_DECL void sgl_v3f_c4f(float x, float y, float z, float r, float g, float b, float a); +SOKOL_GL_API_DECL void sgl_v3f_c4b(float x, float y, float z, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SOKOL_GL_API_DECL void sgl_v3f_c1i(float x, float y, float z, uint32_t rgba); +SOKOL_GL_API_DECL void sgl_v2f_t2f_c3f(float x, float y, float u, float v, float r, float g, float b); +SOKOL_GL_API_DECL void sgl_v2f_t2f_c3b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b); +SOKOL_GL_API_DECL void sgl_v2f_t2f_c4f(float x, float y, float u, float v, float r, float g, float b, float a); +SOKOL_GL_API_DECL void sgl_v2f_t2f_c4b(float x, float y, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SOKOL_GL_API_DECL void sgl_v2f_t2f_c1i(float x, float y, float u, float v, uint32_t rgba); +SOKOL_GL_API_DECL void sgl_v3f_t2f_c3f(float x, float y, float z, float u, float v, float r, float g, float b); +SOKOL_GL_API_DECL void sgl_v3f_t2f_c3b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b); +SOKOL_GL_API_DECL void sgl_v3f_t2f_c4f(float x, float y, float z, float u, float v, float r, float g, float b, float a); +SOKOL_GL_API_DECL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float v, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +SOKOL_GL_API_DECL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba); +SOKOL_GL_API_DECL void sgl_end(void); /* render everything */ -SOKOL_API_DECL void sgl_draw(void); +SOKOL_GL_API_DECL void sgl_draw(void); #ifdef __cplusplus } /* extern "C" */ @@ -2070,12 +2087,12 @@ static void _sgl_init_pool(_sgl_pool_t* pool, int num) { pool->size = num + 1; pool->queue_top = 0; /* generation counters indexable by pool slot index, slot 0 is reserved */ - size_t gen_ctrs_size = sizeof(uint32_t) * pool->size; + size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size; pool->gen_ctrs = (uint32_t*) SOKOL_MALLOC(gen_ctrs_size); SOKOL_ASSERT(pool->gen_ctrs); memset(pool->gen_ctrs, 0, gen_ctrs_size); /* it's not a bug to only reserve 'num' here */ - pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int)*num); + pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int) * (size_t)num); SOKOL_ASSERT(pool->free_queue); /* never allocate the zero-th pool item since the invalid id is 0 */ for (int i = pool->size-1; i >= 1; i--) { @@ -2134,7 +2151,7 @@ static void _sgl_setup_pipeline_pool(const sgl_desc_t* desc) { /* note: the pools here will have an additional item, since slot 0 is reserved */ SOKOL_ASSERT((desc->pipeline_pool_size > 0) && (desc->pipeline_pool_size < _SGL_MAX_POOL_SIZE)); _sgl_init_pool(&_sgl.pip_pool.pool, desc->pipeline_pool_size); - size_t pool_byte_size = sizeof(_sgl_pipeline_t) * _sgl.pip_pool.pool.size; + size_t pool_byte_size = sizeof(_sgl_pipeline_t) * (size_t)_sgl.pip_pool.pool.size; _sgl.pip_pool.pips = (_sgl_pipeline_t*) SOKOL_MALLOC(pool_byte_size); SOKOL_ASSERT(_sgl.pip_pool.pips); memset(_sgl.pip_pool.pips, 0, pool_byte_size); @@ -2237,14 +2254,14 @@ static void _sgl_init_pipeline(sgl_pipeline pip_id, const sg_pipeline_desc* in_d desc.shader = _sgl.shd; } desc.index_type = SG_INDEXTYPE_NONE; - desc.blend.color_format = _sgl.desc.color_format; - desc.blend.depth_format = _sgl.desc.depth_format; - desc.rasterizer.sample_count = _sgl.desc.sample_count; - if (desc.rasterizer.face_winding == _SG_FACEWINDING_DEFAULT) { - desc.rasterizer.face_winding = _sgl.desc.face_winding; + desc.sample_count = _sgl.desc.sample_count; + if (desc.face_winding == _SG_FACEWINDING_DEFAULT) { + desc.face_winding = _sgl.desc.face_winding; } - if (desc.blend.color_write_mask == _SG_COLORMASK_DEFAULT) { - desc.blend.color_write_mask = SG_COLORMASK_RGB; + desc.depth.pixel_format = _sgl.desc.depth_format; + desc.colors[0].pixel_format = _sgl.desc.color_format; + if (desc.colors[0].write_mask == _SG_COLORMASK_DEFAULT) { + desc.colors[0].write_mask = SG_COLORMASK_RGB; } _sgl_pipeline_t* pip = _sgl_lookup_pipeline(pip_id.id); @@ -2639,11 +2656,11 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { _sgl.num_vertices = _sgl.desc.max_vertices; _sgl.num_uniforms = _sgl.desc.max_commands; _sgl.num_commands = _sgl.num_uniforms; - _sgl.vertices = (_sgl_vertex_t*) SOKOL_MALLOC(_sgl.num_vertices * sizeof(_sgl_vertex_t)); + _sgl.vertices = (_sgl_vertex_t*) SOKOL_MALLOC((size_t)_sgl.num_vertices * sizeof(_sgl_vertex_t)); SOKOL_ASSERT(_sgl.vertices); - _sgl.uniforms = (_sgl_uniform_t*) SOKOL_MALLOC(_sgl.num_uniforms * sizeof(_sgl_uniform_t)); + _sgl.uniforms = (_sgl_uniform_t*) SOKOL_MALLOC((size_t)_sgl.num_uniforms * sizeof(_sgl_uniform_t)); SOKOL_ASSERT(_sgl.uniforms); - _sgl.commands = (_sgl_command_t*) SOKOL_MALLOC(_sgl.num_commands * sizeof(_sgl_command_t)); + _sgl.commands = (_sgl_command_t*) SOKOL_MALLOC((size_t)_sgl.num_commands * sizeof(_sgl_command_t)); SOKOL_ASSERT(_sgl.commands); _sgl_setup_pipeline_pool(&_sgl.desc); @@ -2652,7 +2669,7 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { sg_buffer_desc vbuf_desc; memset(&vbuf_desc, 0, sizeof(vbuf_desc)); - vbuf_desc.size = _sgl.num_vertices * sizeof(_sgl_vertex_t); + vbuf_desc.size = (size_t)_sgl.num_vertices * sizeof(_sgl_vertex_t); vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; vbuf_desc.usage = SG_USAGE_STREAM; vbuf_desc.label = "sgl-vertex-buffer"; @@ -2672,8 +2689,7 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; img_desc.min_filter = SG_FILTER_NEAREST; img_desc.mag_filter = SG_FILTER_NEAREST; - img_desc.content.subimage[0][0].ptr = pixels; - img_desc.content.subimage[0][0].size = sizeof(pixels); + img_desc.data.subimage[0][0] = SG_RANGE(pixels); img_desc.label = "sgl-default-texture"; _sgl.def_img = sg_make_image(&img_desc); SOKOL_ASSERT(SG_INVALID_ID != _sgl.def_img.id); @@ -2696,7 +2712,7 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT4; ub->uniforms[0].array_count = 8; shd_desc.fs.images[0].name = "tex"; - shd_desc.fs.images[0].type = SG_IMAGETYPE_2D; + shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; shd_desc.fs.images[0].sampler_type = SG_SAMPLERTYPE_FLOAT; shd_desc.label = "sgl-shader"; #if defined(SOKOL_GLCORE33) @@ -2710,16 +2726,12 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { shd_desc.fs.entry = "main0"; switch (sg_query_backend()) { case SG_BACKEND_METAL_MACOS: - shd_desc.vs.byte_code = _sgl_vs_bytecode_metal_macos; - shd_desc.vs.byte_code_size = sizeof(_sgl_vs_bytecode_metal_macos); - shd_desc.fs.byte_code = _sgl_fs_bytecode_metal_macos; - shd_desc.fs.byte_code_size = sizeof(_sgl_fs_bytecode_metal_macos); + shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_metal_macos); + shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_macos); break; case SG_BACKEND_METAL_IOS: - shd_desc.vs.byte_code = _sgl_vs_bytecode_metal_ios; - shd_desc.vs.byte_code_size = sizeof(_sgl_vs_bytecode_metal_ios); - shd_desc.fs.byte_code = _sgl_fs_bytecode_metal_ios; - shd_desc.fs.byte_code_size = sizeof(_sgl_fs_bytecode_metal_ios); + shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_metal_ios); + shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_ios); break; default: shd_desc.vs.source = _sgl_vs_source_metal_sim; @@ -2727,15 +2739,11 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { break; } #elif defined(SOKOL_D3D11) - shd_desc.vs.byte_code = _sgl_vs_bytecode_hlsl4; - shd_desc.vs.byte_code_size = sizeof(_sgl_vs_bytecode_hlsl4); - shd_desc.fs.byte_code = _sgl_fs_bytecode_hlsl4; - shd_desc.fs.byte_code_size = sizeof(_sgl_fs_bytecode_hlsl4); + shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_hlsl4); + shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_hlsl4); #elif defined(SOKOL_WGPU) - shd_desc.vs.byte_code = _sgl_vs_bytecode_wgpu; - shd_desc.vs.byte_code_size = sizeof(_sgl_vs_bytecode_wgpu); - shd_desc.fs.byte_code = _sgl_fs_bytecode_wgpu; - shd_desc.fs.byte_code_size = sizeof(_sgl_fs_bytecode_wgpu); + shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_wgpu); + shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_wgpu); #else shd_desc.vs.source = _sgl_vs_src_dummy; shd_desc.fs.source = _sgl_fs_src_dummy; @@ -2746,7 +2754,7 @@ SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) { /* create default pipeline object */ sg_pipeline_desc def_pip_desc; memset(&def_pip_desc, 0, sizeof(def_pip_desc)); - def_pip_desc.depth_stencil.depth_write_enabled = true; + def_pip_desc.depth.write_enabled = true; _sgl.def_pip = _sgl_make_pipeline(&def_pip_desc); sg_pop_debug_group(); @@ -2861,6 +2869,10 @@ SOKOL_API_IMPL void sgl_viewport(int x, int y, int w, int h, bool origin_top_lef } } +SOKOL_API_IMPL void sgl_viewportf(float x, float y, float w, float h, bool origin_top_left) { + sgl_viewport((int)x, (int)y, (int)w, (int)h, origin_top_left); +} + SOKOL_API_IMPL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left) { SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); SOKOL_ASSERT(!_sgl.in_begin); @@ -2875,6 +2887,10 @@ SOKOL_API_IMPL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top } } +SOKOL_API_IMPL void sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left) { + sgl_scissor_rect((int)x, (int)y, (int)w, (int)h, origin_top_left); +} + SOKOL_API_IMPL void sgl_enable_texture(void) { SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); SOKOL_ASSERT(!_sgl.in_begin); @@ -3193,7 +3209,7 @@ SOKOL_API_IMPL void sgl_lookat(float eye_x, float eye_y, float eye_z, float cent _sgl_lookat(_sgl_matrix(), eye_x, eye_y, eye_z, center_x, center_y, center_z, up_x, up_y, up_z); } -SOKOL_API_DECL void sgl_push_matrix(void) { +SOKOL_GL_API_DECL void sgl_push_matrix(void) { SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); SOKOL_ASSERT((_sgl.cur_matrix_mode >= 0) && (_sgl.cur_matrix_mode < SGL_NUM_MATRIXMODES)); _sgl.matrix_dirty = true; @@ -3208,7 +3224,7 @@ SOKOL_API_DECL void sgl_push_matrix(void) { } } -SOKOL_API_DECL void sgl_pop_matrix(void) { +SOKOL_GL_API_DECL void sgl_pop_matrix(void) { SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); SOKOL_ASSERT((_sgl.cur_matrix_mode >= 0) && (_sgl.cur_matrix_mode < SGL_NUM_MATRIXMODES)); _sgl.matrix_dirty = true; @@ -3228,7 +3244,8 @@ SOKOL_API_IMPL void sgl_draw(void) { uint32_t cur_img_id = SG_INVALID_ID; int cur_uniform_index = -1; sg_push_debug_group("sokol-gl"); - sg_update_buffer(_sgl.vbuf, _sgl.vertices, _sgl.cur_vertex * sizeof(_sgl_vertex_t)); + const sg_range range = { _sgl.vertices, (size_t)_sgl.cur_vertex * sizeof(_sgl_vertex_t) }; + sg_update_buffer(_sgl.vbuf, &range); _sgl.bind.vertex_buffers[0] = _sgl.vbuf; for (int i = 0; i < _sgl.cur_command; i++) { const _sgl_command_t* cmd = &_sgl.commands[i]; @@ -3261,7 +3278,8 @@ SOKOL_API_IMPL void sgl_draw(void) { cur_img_id = args->img.id; } if (cur_uniform_index != args->uniform_index) { - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &_sgl.uniforms[args->uniform_index], sizeof(_sgl_uniform_t)); + const sg_range ub_range = { &_sgl.uniforms[args->uniform_index], sizeof(_sgl_uniform_t) }; + sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &ub_range); cur_uniform_index = args->uniform_index; } /* FIXME: what if number of vertices doesn't match the primitive type? */ diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index d37cb0d624..508405e949 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -191,9 +191,16 @@ fn gg_init_sokol_window(user_data voidptr) { // mut pipdesc := C.sg_pipeline_desc{} unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } - pipdesc.blend.enabled = true - pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) - pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } + } + pipdesc.colors[0] = color_state + g.timage_pip = sgl.make_pipeline(&pipdesc) // if g.config.init_fn != voidptr(0) { @@ -203,6 +210,7 @@ fn gg_init_sokol_window(user_data voidptr) { if g.native_rendering { return } + for i in 0 .. g.image_cache.len { g.image_cache[i].init_sokol_image() } @@ -216,6 +224,7 @@ fn gg_frame_fn(user_data voidptr) { if ctx.native_rendering { // return } + if ctx.ui_mode && !ctx.needs_refresh { // Draw 3 more frames after the "stop refresh" command ctx.ticks++ @@ -334,7 +343,7 @@ pub fn new_context(cfg Config) &Context { sample_count: cfg.sample_count high_dpi: true fullscreen: cfg.fullscreen - native_render: cfg.native_rendering + __v_native_render: cfg.native_rendering } if cfg.use_ortho { } else { @@ -422,6 +431,12 @@ pub fn (ctx &Context) draw_empty_square(x f32, y f32, s f32, c gx.Color) { } pub fn (ctx &Context) draw_circle_line(x f32, y f32, r int, segments int, c gx.Color) { + $if macos { + if ctx.native_rendering { + C.darwin_draw_circle(x - r + 1, ctx.height - (y + r + 3), r, c) + return + } + } if c.a != 255 { sgl.load_pipeline(ctx.timage_pip) } @@ -440,12 +455,6 @@ pub fn (ctx &Context) draw_circle_line(x f32, y f32, r int, segments int, c gx.C } pub fn (ctx &Context) draw_circle(x f32, y f32, r f32, c gx.Color) { - $if macos { - if ctx.native_rendering { - C.darwin_draw_circle(x - r + 1, ctx.height - (y + r + 3), r, c) - return - } - } if ctx.scale == 1 { ctx.draw_circle_with_segments(x, y, r, 10, c) } else { diff --git a/vlib/gg/gg_darwin.m b/vlib/gg/gg_darwin.m index 4342d6ca3a..6d0671c502 100644 --- a/vlib/gg/gg_darwin.m +++ b/vlib/gg/gg_darwin.m @@ -80,9 +80,12 @@ void darwin_draw_rect(float x, float y, float width, float height, gx__Color c) void darwin_window_refresh() { //[g_view setNeedsDisplay:YES]; // update UI on the main thread TODO separate fn - dispatch_async(dispatch_get_main_queue(), ^{ + + /* + dispatch_async(dispatch_get_main_queue(), ^{ [g_view setNeedsDisplay:YES]; }); + */ //puts("refresh"); //[g_view drawRect:NSMakeRect(0,0,2000,2000)]; diff --git a/vlib/gg/image.v b/vlib/gg/image.v index 5deab213c4..f7d7977217 100644 --- a/vlib/gg/image.v +++ b/vlib/gg/image.v @@ -149,9 +149,9 @@ pub fn (mut img Image) init_sokol_image() &Image { label: &byte(0) d3d11_texture: 0 } - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: img.data - size: img.nr_channels * img.width * img.height + size: size_t(img.nr_channels * img.width * img.height) } img.simg = C.sg_make_image(&img_desc) img.simg_ok = true diff --git a/vlib/sokol/gfx/enums.v b/vlib/sokol/gfx/enums.v index d4aef911af..4d0339e68e 100644 --- a/vlib/sokol/gfx/enums.v +++ b/vlib/sokol/gfx/enums.v @@ -126,13 +126,14 @@ pub enum ImageType { } pub enum CubeFace { - pos_x - neg_x - pos_y - neg_y - pos_z - neg_z - num + pos_x + neg_x + pos_y + neg_y + pos_z + neg_z + num + _force_u32 = 0x7fffffff } pub enum ShaderStage { diff --git a/vlib/sokol/gfx/gfx.v b/vlib/sokol/gfx/gfx.v index 927a587a1c..86de35ae75 100644 --- a/vlib/sokol/gfx/gfx.v +++ b/vlib/sokol/gfx/gfx.v @@ -75,18 +75,18 @@ pub fn destroy_pass(pass C.sg_pass) { } [inline] -pub fn update_buffer(buf C.sg_buffer, ptr voidptr, num_bytes int) { - C.sg_update_buffer(buf, ptr, num_bytes) +pub fn update_buffer(buf C.sg_buffer, data &C.sg_range) { + C.sg_update_buffer(buf, data) } [inline] -pub fn update_image(img C.sg_image, content &C.sg_image_content) { - C.sg_update_image(img, content) +pub fn update_image(img C.sg_image, data &C.sg_image_data) { + C.sg_update_image(img, data) } [inline] -pub fn append_buffer(buf C.sg_buffer, ptr voidptr, num_bytes int) int { - return C.sg_append_buffer(buf, ptr, num_bytes) +pub fn append_buffer(buf C.sg_buffer, data &C.sg_range) int { + return C.sg_append_buffer(buf, data) } [inline] @@ -126,8 +126,8 @@ pub fn apply_bindings(bindings &C.sg_bindings) { } [inline] -pub fn apply_uniforms(stage int, ub_index int, data voidptr, num_bytes int) { - C.sg_apply_uniforms(stage, ub_index, data, num_bytes) +pub fn apply_uniforms(stage int, ub_index int, data &C.sg_range) { + C.sg_apply_uniforms(stage, ub_index, data) } [inline] diff --git a/vlib/sokol/gfx/gfx_funcs.v b/vlib/sokol/gfx/gfx_funcs.v index b4ba4e3049..d0cec2770c 100644 --- a/vlib/sokol/gfx/gfx_funcs.v +++ b/vlib/sokol/gfx/gfx_funcs.v @@ -16,20 +16,22 @@ fn C.sg_destroy_image(img C.sg_image) fn C.sg_destroy_shader(shd C.sg_shader) fn C.sg_destroy_pipeline(pip C.sg_pipeline) fn C.sg_destroy_pass(pass C.sg_pass) -fn C.sg_update_buffer(buf C.sg_buffer, ptr voidptr, num_bytes int) -fn C.sg_update_image(img C.sg_image, content &C.sg_image_content) -fn C.sg_append_buffer(buf C.sg_buffer, ptr voidptr, num_bytes int) int +fn C.sg_update_buffer(buf C.sg_buffer, data &C.sg_range) +fn C.sg_update_image(img C.sg_image, data &C.sg_image_data) +fn C.sg_append_buffer(buf C.sg_buffer, data &C.sg_range) int fn C.sg_query_buffer_overflow(buf C.sg_buffer) bool // rendering functions fn C.sg_begin_default_pass(actions &C.sg_pass_action, width int, height int) fn C.sg_begin_pass(pass C.sg_pass, actions &C.sg_pass_action) fn C.sg_apply_viewport(x int, y int, width int, height int, origin_top_left bool) +fn C.sg_apply_viewportf(x f32, y f32, width f32, height f32, origin_top_left bool) fn C.sg_apply_scissor_rect(x int, y int, width int, height int, origin_top_left bool) +fn C.sg_apply_scissor_rectf(x f32, y f32, width f32, height f32, origin_top_left bool) fn C.sg_apply_pipeline(pip C.sg_pipeline) fn C.sg_apply_bindings(bindings &C.sg_bindings) // stage == sg_shader_stage -fn C.sg_apply_uniforms(stage int, ub_index int, data voidptr, num_bytes int) +fn C.sg_apply_uniforms(stage int, ub_index int, data &C.sg_range) fn C.sg_draw(base_element int, num_elements int, num_instances int) fn C.sg_end_pass() fn C.sg_commit() diff --git a/vlib/sokol/gfx/gfx_structs.v b/vlib/sokol/gfx/gfx_structs.v index 8f032bb583..a766454969 100644 --- a/vlib/sokol/gfx/gfx_structs.v +++ b/vlib/sokol/gfx/gfx_structs.v @@ -36,7 +36,7 @@ pub struct C.sg_context_desc { */ sample_count int gl C.sg_gl_context_desc - metal C.sg_mtl_context_desc + metal C.sg_metal_context_desc d3d11 C.sg_d3d11_context_desc color_format PixelFormat depth_format PixelFormat @@ -46,7 +46,7 @@ pub struct C.sg_gl_context_desc { gl_force_gles2 bool } -pub struct C.sg_mtl_context_desc { +pub struct C.sg_metal_context_desc { device voidptr renderpass_descriptor_cb fn () voidptr drawable_cb fn () voidptr @@ -59,18 +59,31 @@ pub struct C.sg_d3d11_context_desc { depth_stencil_view_cb fn () voidptr } +pub struct C.sg_color_state { +pub mut: + pixel_format PixelFormat + write_mask ColorMask + blend C.sg_blend_state +} + pub struct C.sg_pipeline_desc { pub mut: - _start_canary u32 - layout C.sg_layout_desc - shader C.sg_shader - primitive_type PrimitiveType - index_type IndexType - depth_stencil C.sg_depth_stencil_state - blend C.sg_blend_state - rasterizer C.sg_rasterizer_state - label byteptr - _end_canary u32 + _start_canary u32 + shader C.sg_shader + layout C.sg_layout_desc + depth C.sg_depth_state + stencil C.sg_stencil_state + color_count int + colors [4]C.sg_color_state // C.SG_MAX_COLOR_ATTACHMENTS + primitive_type PrimitiveType + index_type IndexType + cull_mode CullMode + face_winding FaceWinding + sample_count int + blend_color C.sg_color + alpha_to_coverage_enabled bool + label byteptr + _end_canary u32 } pub struct C.sg_pipeline_info { @@ -106,19 +119,35 @@ pub fn (mut b C.sg_bindings) set_frag_image(index int, img C.sg_image) { } pub fn (b &C.sg_bindings) update_vert_buffer(index int, data voidptr, element_size int, element_count int) { - C.sg_update_buffer(b.vertex_buffers[index], data, element_size * element_count) + range := C.sg_range{ + ptr: data + size: size_t(element_size * element_count) + } + C.sg_update_buffer(b.vertex_buffers[index], &range) } pub fn (b &C.sg_bindings) append_vert_buffer(index int, data voidptr, element_size int, element_count int) int { - return C.sg_append_buffer(b.vertex_buffers[index], data, element_size * element_count) + range := C.sg_range{ + ptr: data + size: size_t(element_size * element_count) + } + return C.sg_append_buffer(b.vertex_buffers[index], &range) } pub fn (b &C.sg_bindings) update_index_buffer(data voidptr, element_size int, element_count int) { - C.sg_update_buffer(b.index_buffer, data, element_size * element_count) + range := C.sg_range{ + ptr: data + size: size_t(element_size * element_count) + } + C.sg_update_buffer(b.index_buffer, &range) } pub fn (b &C.sg_bindings) append_index_buffer(data voidptr, element_size int, element_count int) int { - return C.sg_append_buffer(b.index_buffer, data, element_size * element_count) + range := C.sg_range{ + ptr: data + size: size_t(element_size * element_count) + } + return C.sg_append_buffer(b.index_buffer, &range) } pub struct C.sg_shader_desc { @@ -143,22 +172,22 @@ pub fn (mut desc C.sg_shader_desc) set_frag_src(src string) &C.sg_shader_desc { pub fn (mut desc C.sg_shader_desc) set_vert_image(index int, name string) &C.sg_shader_desc { desc.vs.images[index].name = name.str - desc.vs.images[index].@type = ._2d + desc.vs.images[index].image_type = ._2d return desc } pub fn (mut desc C.sg_shader_desc) set_frag_image(index int, name string) &C.sg_shader_desc { desc.fs.images[index].name = name.str - desc.fs.images[index].@type = ._2d + desc.fs.images[index].image_type = ._2d return desc } -pub fn (mut desc C.sg_shader_desc) set_vert_uniform_block_size(block_index int, size int) &C.sg_shader_desc { +pub fn (mut desc C.sg_shader_desc) set_vert_uniform_block_size(block_index int, size size_t) &C.sg_shader_desc { desc.vs.uniform_blocks[block_index].size = size return desc } -pub fn (mut desc C.sg_shader_desc) set_frag_uniform_block_size(block_index int, size int) &C.sg_shader_desc { +pub fn (mut desc C.sg_shader_desc) set_frag_uniform_block_size(block_index int, size size_t) &C.sg_shader_desc { desc.fs.uniform_blocks[block_index].size = size return desc } @@ -189,8 +218,7 @@ pub mut: pub struct C.sg_shader_stage_desc { pub mut: source byteptr - byte_code &byte - byte_code_size int + bytecode C.sg_range entry byteptr uniform_blocks [4]C.sg_shader_uniform_block_desc images [12]C.sg_shader_image_desc @@ -198,13 +226,13 @@ pub mut: pub fn (mut desc C.sg_shader_stage_desc) set_image(index int, name string) C.sg_shader_stage_desc { desc.images[index].name = name.str - desc.images[index].@type = ._2d + desc.images[index].image_type = ._2d return *desc } pub struct C.sg_shader_uniform_block_desc { pub mut: - size int + size size_t uniforms [16]C.sg_shader_uniform_desc } @@ -218,7 +246,7 @@ pub mut: pub struct C.sg_shader_image_desc { pub mut: name byteptr - @type ImageType + image_type ImageType } pub struct C.sg_shader_info { @@ -228,6 +256,20 @@ pub struct C.sg_context { id u32 } +pub struct C.sg_range { +pub mut: + ptr voidptr + size size_t +} + +pub struct C.sg_color { +pub mut: + r f32 + g f32 + b f32 + a f32 +} + pub struct C.sg_shader { pub: id u32 @@ -240,8 +282,8 @@ pub fn (s C.sg_shader) free() { pub struct C.sg_pass_desc { pub mut: _start_canary u32 - color_attachments [4]C.sg_attachment_desc - depth_stencil_attachment C.sg_attachment_desc + color_attachments [4]C.sg_pass_attachment_desc + depth_stencil_attachment C.sg_pass_attachment_desc label byteptr _end_canary u32 } @@ -270,10 +312,10 @@ pub fn (p C.sg_pass) free() { pub struct C.sg_buffer_desc { pub mut: _start_canary u32 - size int + size size_t @type BufferType usage Usage - content byteptr + data C.sg_range label byteptr // GL specific gl_buffers [2]u32 @@ -307,12 +349,7 @@ pub mut: render_target bool width int height int - depth DepthLayers - // depth int - // union { - // int depth; - // int layers; - // }; + num_slices int num_mipmaps int usage Usage pixel_format PixelFormat @@ -326,14 +363,18 @@ pub mut: max_anisotropy u32 min_lod f32 max_lod f32 - content C.sg_image_content + data C.sg_image_data label byteptr // GL specific gl_textures [2]u32 + gl_texture_target u32 // Metal specific mtl_textures [2]voidptr // D3D11 specific d3d11_texture voidptr + d3d11_shader_resource_view voidptr + // WebGPU specific + wgpu_texture voidptr _end_canary u32 } @@ -354,26 +395,23 @@ pub fn (i C.sg_image) free() { C.sg_destroy_image(i) } -pub struct C.sg_image_content { +pub struct C.sg_image_data { pub mut: - subimage [6][16]C.sg_subimage_content -} - -pub struct C.sg_subimage_content { -pub mut: - ptr voidptr // pointer to subimage data - size int // size in bytes of pointed-to subimage data + //subimage [C.SG_CUBEFACE_NUM][C.SG_MAX_MIPMAPS]C.sg_range + subimage [6][16]C.sg_range } pub struct C.sg_features { pub: - instancing bool // hardware instancing supported - origin_top_left bool // framebuffer and texture origin is in top left corner - multiple_render_targets bool // offscreen render passes can have multiple render targets attached - msaa_render_targets bool // offscreen render passes support MSAA antialiasing - imagetype_3d bool // creation of SG_IMAGETYPE_3D images is supported - imagetype_array bool // creation of SG_IMAGETYPE_ARRAY images is supported - image_clamp_to_border bool // border color and clamp-to-border UV-wrap mode is supported + instancing bool // hardware instancing supported + origin_top_left bool // framebuffer and texture origin is in top left corner + multiple_render_targets bool // offscreen render passes can have multiple render targets attached + msaa_render_targets bool // offscreen render passes support MSAA antialiasing + imagetype_3d bool // creation of SG_IMAGETYPE_3D images is supported + imagetype_array bool // creation of SG_IMAGETYPE_ARRAY images is supported + image_clamp_to_border bool // border color and clamp-to-border UV-wrap mode is supported + mrt_independent_blend_state bool // multiple-render-target rendering can use per-render-target blend state + mrt_independent_write_mask bool // multiple-render-target rendering can use per-render-target color write masks } pub struct C.sg_limits { @@ -406,18 +444,25 @@ pub mut: format VertexFormat } -pub struct C.sg_depth_stencil_state { - stencil_front C.sg_stencil_state - stencil_back C.sg_stencil_state - depth_compare_func CompareFunc - depth_write_enabled bool - stencil_enabled bool - stencil_read_mask byte - stencil_write_mask byte - stencil_ref byte +pub struct C.sg_stencil_state { + enabled bool + front C.sg_stencil_face_state + back C.sg_stencil_face_state + read_mask byte + write_mask byte + ref byte } -pub struct C.sg_stencil_state { +pub struct C.sg_depth_state { + pixel_format PixelFormat + compare CompareFunc + write_enabled bool + bias f32 + bias_slope_scale f32 + bias_clamp f32 +} + +pub struct C.sg_stencil_face_state { fail_op StencilOp depth_fail_op StencilOp pass_op StencilOp @@ -433,28 +478,12 @@ pub mut: src_factor_alpha BlendFactor dst_factor_alpha BlendFactor op_alpha BlendOp - color_write_mask byte - color_attachment_count int - color_format PixelFormat - depth_format PixelFormat - blend_color [4]f32 -} - -pub struct C.sg_rasterizer_state { -pub mut: - alpha_to_coverage_enabled bool - cull_mode CullMode - face_winding FaceWinding - sample_count int - depth_bias f32 - depth_bias_slope_scale f32 - depth_bias_clamp f32 } pub struct C.sg_color_attachment_action { pub mut: action Action - val [4]f32 + value C.sg_color } /* @@ -468,13 +497,13 @@ pub fn (mut action C.sg_color_attachment_action) set_color_values(r, g, b, a f32 pub struct C.sg_depth_attachment_action { pub mut: action Action - val f32 + value f32 } pub struct C.sg_stencil_attachment_action { pub mut: action Action - val byte + value byte } pub struct C.sg_pixelformat_info { @@ -487,7 +516,7 @@ pub: depth bool // pixel format is a depth format } -pub struct C.sg_attachment_desc { +pub struct C.sg_pass_attachment_desc { pub mut: image C.sg_image mip_level int diff --git a/vlib/sokol/gfx/gfx_utils.v b/vlib/sokol/gfx/gfx_utils.v index 320a89bd30..0c872ceeeb 100644 --- a/vlib/sokol/gfx/gfx_utils.v +++ b/vlib/sokol/gfx/gfx_utils.v @@ -3,12 +3,14 @@ module gfx pub fn create_clear_pass(r f32, g f32, b f32, a f32) C.sg_pass_action { mut color_action := C.sg_color_attachment_action{ action: gfx.Action(C.SG_ACTION_CLEAR) + value: C.sg_color { + r: r + g: g + b: b + a: a + } } // color_action.set_color_values(r, g, b, a) - color_action.val[0] = r - color_action.val[1] = g - color_action.val[2] = b - color_action.val[3] = a mut pass_action := C.sg_pass_action{} pass_action.colors[0] = color_action return pass_action diff --git a/vlib/sokol/sapp/sapp.v b/vlib/sokol/sapp/sapp.v index df7c23fa84..0fd4deb71c 100644 --- a/vlib/sokol/sapp/sapp.v +++ b/vlib/sokol/sapp/sapp.v @@ -10,7 +10,7 @@ pub const ( __global ( g_desc C.sapp_desc ) pub fn create_desc() C.sg_desc { - mtl_desc := C.sg_mtl_context_desc{ + metal_desc := C.sg_metal_context_desc{ device: metal_get_device() renderpass_descriptor_cb: metal_get_renderpass_descriptor drawable_cb: metal_get_drawable @@ -23,7 +23,7 @@ pub fn create_desc() C.sg_desc { } return C.sg_desc{ context: C.sg_context_desc{ - metal: mtl_desc + metal: metal_desc d3d11: d3d11_desc } image_pool_size: 1000 @@ -140,9 +140,9 @@ pub fn get_clipboard_string() byteptr { // special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) [inline] -pub fn run(desc &C.sapp_desc) int { +pub fn run(desc &C.sapp_desc) { g_desc = desc - return C.sapp_run(desc) + C.sapp_run(desc) } // GL: return true when GLES2 fallback is active (to detect fallback from GLES3) diff --git a/vlib/sokol/sapp/sapp_funcs.v b/vlib/sokol/sapp/sapp_funcs.v index 48633e8c17..f49382d663 100644 --- a/vlib/sokol/sapp/sapp_funcs.v +++ b/vlib/sokol/sapp/sapp_funcs.v @@ -4,8 +4,10 @@ module sapp fn C.sapp_isvalid() bool /* returns the current framebuffer width in pixels */ fn C.sapp_width() int +fn C.sapp_widthf() f32 /* returns the current framebuffer height in pixels */ fn C.sapp_height() int +fn C.sapp_heightf() f32 /* returns true when high_dpi was requested and actually running in a high-dpi scenario */ fn C.sapp_high_dpi() bool /* returns the dpi scaling factor (window pixels to framebuffer pixels) */ diff --git a/vlib/sokol/sapp/sapp_structs.v b/vlib/sokol/sapp/sapp_structs.v index 594f1c5873..b0cbfa69b1 100644 --- a/vlib/sokol/sapp/sapp_structs.v +++ b/vlib/sokol/sapp/sapp_structs.v @@ -7,12 +7,14 @@ pub: cleanup_cb fn () event_cb fn (&C.sapp_event) //&sapp_event) fail_cb fn (&byte) + user_data voidptr // these are the user-provided callbacks with user data init_userdata_cb fn (voidptr) frame_userdata_cb fn (voidptr) cleanup_userdata_cb fn (voidptr) event_userdata_cb fn (&C.sapp_event, voidptr) fail_userdata_cb fn (&char, voidptr) + width int // the preferred width of the window / canvas height int // the preferred height of the window / canvas sample_count int // MSAA sample count @@ -20,18 +22,26 @@ pub: high_dpi bool // whether the rendering canvas is full-resolution on HighDPI displays fullscreen bool // whether the window should be created in fullscreen mode alpha bool // whether the framebuffer should have an alpha channel (ignored on some platforms) - window_title &byte // the window title as UTF-8 encoded string + window_title &char // the window title as UTF-8 encoded string user_cursor bool // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR enable_clipboard bool // enable clipboard access, default is false clipboard_size int // max size of clipboard content in bytes - html5_canvas_name &byte // the name (id) of the HTML5 canvas element, default is "canvas" + enable_dragndrop bool // enable file dropping (drag'n'drop), default is false + max_dropped_files int // max number of dropped files to process (default: 1) + max_dropped_file_path_length int // max length in bytes of a dropped UTF-8 file path (default: 2048) + /* backend-specific options */ + gl_force_gles2 bool // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available + win32_console_utf8 bool // if true, set the output console codepage to UTF-8 + win32_console_create bool // if true, attach stdout/stderr to a new console window + win32_console_attach bool // if true, attach stdout/stderr to parent process + html5_canvas_name &char // the name (id) of the HTML5 canvas element, default is "canvas" html5_canvas_resize bool // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked html5_preserve_drawing_buffer bool // HTML5 only: whether to preserve default framebuffer content between frames html5_premultiplied_alpha bool // HTML5 only: whether the rendered pixels use premultiplied alpha convention html5_ask_leave_site bool // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) ios_keyboard_resizes_canvas bool // if true, showing the iOS keyboard shrinks the canvas - gl_force_gles2 bool // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available - native_render bool + /* V patches */ + __v_native_render bool // V patch to allow for native rendering } pub struct Event { diff --git a/vlib/sokol/sgl/sgl_funcs.v b/vlib/sokol/sgl/sgl_funcs.v index 88618a11fd..6991eea01d 100644 --- a/vlib/sokol/sgl/sgl_funcs.v +++ b/vlib/sokol/sgl/sgl_funcs.v @@ -14,7 +14,9 @@ fn C.sgl_destroy_pipeline(pip C.sgl_pipeline) /* render state functions */ fn C.sgl_viewport(x int, y int, w int, h int, origin_top_left bool) +fn C.sgl_viewportf(x f32, y f32, w f32, h f32, origin_top_left bool) fn C.sgl_scissor_rect(x int, y int, w int, h int, origin_top_left bool) +fn C.sgl_scissor_rectf(x f32, y f32, w f32, h f32, origin_top_left bool) fn C.sgl_enable_texture() fn C.sgl_disable_texture() fn C.sgl_texture(img C.sg_image) diff --git a/vlib/x/ttf/render_sokol_cpu.v b/vlib/x/ttf/render_sokol_cpu.v index c7e4668175..61ef89365a 100644 --- a/vlib/x/ttf/render_sokol_cpu.v +++ b/vlib/x/ttf/render_sokol_cpu.v @@ -10,7 +10,7 @@ module ttf * * Note: * -* TODO: +* TODO: **********************************************************************/ import math import gg @@ -131,9 +131,9 @@ pub fn (mut tf_skl TTF_render_Sokol) create_texture() { d3d11_texture: 0 } // comment for dynamic - img_desc.content.subimage[0][0] = C.sg_subimage_content{ + img_desc.data.subimage[0][0] = C.sg_range{ ptr: tf_skl.bmp.buf - size: sz + size: size_t(sz) } simg := C.sg_make_image(&img_desc) @@ -148,10 +148,10 @@ pub fn (tf_skl TTF_render_Sokol) destroy_texture() { // Use only if usage: .dynamic pub fn (mut tf_skl TTF_render_Sokol) update_text_texture() { sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp - mut tmp_sbc := C.sg_image_content{} - tmp_sbc.subimage[0][0] = C.sg_subimage_content{ + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ ptr: tf_skl.bmp.buf - size: sz + size: size_t(sz) } C.sg_update_image(tf_skl.sg_img, &tmp_sbc) }