diff --git a/scripts/prosperon.js b/scripts/prosperon.js index 7c1a585e..7c995a22 100644 --- a/scripts/prosperon.js +++ b/scripts/prosperon.js @@ -176,29 +176,22 @@ function create_image(path) switch(path.ext()) { case 'gif': newimg = os.make_gif(data); - if (newimg.surface) { + if (newimg.surface) newimg.texture = render._main.load_texture(newimg.surface); - newimg.texture.mode(0); - } else - for (var frame of newimg.frames) { + for (var frame of newimg.frames) frame.texture = render._main.load_texture(frame.surface); - frame.texture.mode(0); - } break; case 'ase': case 'aseprite': newimg = os.make_aseprite(data); - if (newimg.surface) { + if (newimg.surface) newimg.texture = render._main.load_texture(newimg.surface); - newimg.texture.mode(0); - } else { + else { for (var anim in newimg) { var a = newimg[anim]; - for (var frame of a.frames) { + for (var frame of a.frames) frame.texture = render._main.load_texture(frame.surface); - frame.texture.mode(0) - } } } break; @@ -207,7 +200,6 @@ function create_image(path) surface: os.make_texture(data) }; newimg.texture = render._main.load_texture(newimg.surface); - newimg.texture.mode(0); break; } return newimg; diff --git a/scripts/render.js b/scripts/render.js index ebf27c7b..c4ed1820 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -13,7 +13,7 @@ cur.samplers = []; function bind_pipeline(pass, pipeline) { make_pipeline(pipeline) - pass.bind_pipeline(pipeline) + pass.bind_pipeline(pipeline.gpu) pass.pipeline = pipeline; } @@ -52,11 +52,11 @@ var base_pipeline = { }, blend: { enabled: false, - src_factor_rgb: "one", // zero/one/src_color/one_minus_src_color/dst_color/one_minus_dst_color/src_alpha/one_minus_src_alpha/dst_alpha/one_minus_dst_alpha/constant_color/one_minus_constant_color/src_alpha_saturate - dst_factor_rgb: "zero", + src_rgb: "one", // zero/one/src_color/one_minus_src_color/dst_color/one_minus_dst_color/src_alpha/one_minus_src_alpha/dst_alpha/one_minus_dst_alpha/constant_color/one_minus_constant_color/src_alpha_saturate + dst_rgb: "zero", op_rgb: "add", // add/sub/rev_sub/min/max - src_factor_alpha: "one", - dst_factor_alpha: "zero", + src_alpha: "one", + dst_alpha: "zero", op_alpha: "add" }, cull: "none", // none/front/back @@ -68,12 +68,19 @@ var base_pipeline = { domask: false }, label: "scripted pipeline", - target: "main" + target: {} } var cornflower = [62/255,96/255,113/255,1]; var sprite_pipeline = Object.create(base_pipeline); +sprite_pipeline.target = { + color_targets: [{ + format:"rgba8", + blend:base_pipeline.blend + }], + depth: "d32 float s8" +}; var post_pipeline = Object.create(base_pipeline); post_pipeline.stencil = { @@ -337,7 +344,21 @@ render.device = { var render_queue = []; render.device.doc = `Device resolutions given as [x,y,inches diagonal].`; -var std_sampler; +var std_sampler = { + min_filter: "nearest", + mag_filter: "nearest", + mipmap: "linear", + u: "repeat", + v: "repeat", + w: "repeat", + mip_bias: 0, + max_anisotropy: 0, + compare_op: "none", + min_lod: 0, + max_lod: 0, + anisotropy: false, + compare: false +}; var tbuffer; @@ -408,14 +429,57 @@ function group_sprites_by_texture(sprites) return groups; } -function render_camera(camera) +var main_color = { + type:"2d", + format: "rgba8", + layers: 1, + mip_levels: 1, + samples: 0, + sampler:true, + color_target:true +}; + +var main_depth = { + type: "2d", + format: "d32 float s8", + layers:1, + mip_levels:1, + samples:0, + sampler:true, + depth_target:true +}; + +function render_camera(cmds, camera) { if (render_queue.length == 0) return; - camera.target ??= render._main.mainRT(prosperon.camera.size); - var cmds = render._main.acquire_cmd_buffer(); + if (!camera.target) { + main_color.width = main_depth.width = prosperon.camera.size.x; + main_color.height = main_depth.height = prosperon.camera.size.y; + camera.target = { + color_targets: [{ + texture: render._main.texture(main_color), + mip_level:0, + layer: 0, + load:"clear", + store:"store", + clear: cornflower + } + ], + depth_stencil: { + texture: render._main.texture(main_depth), + clear:1, + load:"clear", + store:"dont_care", + stencil_load:"clear", + stencil_store:"dont_care", + stencil_clear:0 + } + }; + } + var spritemesh = render._main.make_sprite_mesh(render_queue); cmds.upload_model(spritemesh); - var pass = cmds.render_pass(camera.target, cornflower); + var pass = cmds.render_pass(camera.target); var camera = prosperon.camera; var draw_cmds = group_sprites_by_texture(render_queue); @@ -440,45 +504,25 @@ function render_camera(camera) pass.end(); - cmds.submit(); render_queue.length = 0; } - +var swaps = []; function gpupresent() { try{ - render_camera(prosperon.camera); - } catch(e) { console.error(e); } finally { var cmds = render._main.acquire_cmd_buffer(); - var winsize = render._main.window.size; - var pipeline = post_pipeline; - var T = os.make_transform(); - T.trs([0,0],undefined, [winsize.x, winsize.y]); - var pass = cmds.swapchain_pass(); - bind_pipeline(pass,pipeline); - bind_model(pass,pipeline,quad_model); - var camslot = get_pipeline_ubo_slot(pipeline, 'TransformBuffer'); - - if (typeof camslot !== 'undefined') { - post_camera.size = render._main.window.size; - cmds.camera(post_camera, pass, undefined, camslot); + render_camera(cmds, prosperon.camera); + } catch(e) { console.error(e); } finally { + var swapchain_tex = cmds.acquire_swapchain(); + if (!swapchain_tex) + cmds.cancel(); + else { + if (swapchain_tex) cmds.blit({ + src: prosperon.camera.target.color_targets[0].texture, + dst: swapchain_tex, + }); + cmds.submit() } - - var modelslot = get_pipeline_ubo_slot(pipeline, "model"); - if (typeof modelslot !== 'undefined') { - var ubo = ubo_obj_to_array(pipeline, 'model', {model:T, color:[1,1,1,1]}); - cmds.push_vertex_uniform_data(modelslot, ubo); - } - - var mat = {}; - mat.diffuse = { - texture:prosperon.camera.target.color_targets[0].texture, - sampler:std_sampler - }; - bind_mat(pass, pipeline, mat); - pass.draw_indexed(quad_model.num_indices,1,quad_model.first_index,0,0); - pass.end(); - cmds.submit(); } } @@ -493,16 +537,14 @@ var quad_model; render.init = function () { shader_type = render._main.shader_format()[0]; - console.log(render._main.shader_format()) - console.log(`shader format ${shader_type}`) std_sampler = render._main.make_sampler({ min_filter: "nearest", mag_filter: "nearest", mipmap_mode: "nearest", - address_mode_u: "clamp_edge", - address_mode_v: "clamp_edge", - address_mode_w: "clamp_edge" + address_mode_u: "repeat", + address_mode_v: "repeat", + address_mode_w: "repeat" }); quad_model = render._main.make_quad(); io.mount("core"); @@ -514,7 +556,6 @@ render.init = function () { var img = {}; img.surface = os.make_texture(mat[i]); img.texture = render._main.load_texture(img.surface); - img.texture.mode(0); img.sampler = std_sampler; mat[i] = img; } diff --git a/scripts/std.js b/scripts/std.js index d6cd8cd8..fdc809ee 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -247,9 +247,22 @@ Cmdline.register_order( else console.warn("No config.js file found. Starting with default parameters."); prosperon.window = game.engine_start(prosperon); - render._main = prosperon.window.make_gpu(); + var driver = "vulkan" + switch(os.sys()) { + case "Linux": + driver = "vulkan" + break + case "Windows": + driver = "direct3d12" + break + case "Mac OS X": + driver = "metal" + break + } + render._main = prosperon.window.make_gpu(false, driver); render._main.window = prosperon.window; render._main.claim_window(prosperon.window); + render._main.set_swapchain("sdr", "immediate"); var tt = game.texture('moon'); tt.texture.__proto__.toString = function() { return os.value_id(this); } diff --git a/source/jsffi.c b/source/jsffi.c index 1caf90f3..1b571965 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -1,5 +1,4 @@ #include "jsffi.h" - #include "script.h" #include "font.h" #include "datastream.h" @@ -180,8 +179,10 @@ JSValue val = JS_GetPropertyUint32(JS,VAL,I); \ TO = js2##TYPE(JS, val); \ JS_FreeValue(JS, val); } \ -static SDL_GPUGraphicsPipelineTargetInfo main_info = {0}; -static SDL_GPUGraphicsPipelineTargetInfo post_info = {0}; +static inline int js2bool(JSContext *js, JSValue v) +{ + return JS_ToBool(js,v); +} JSValue number2js(JSContext *js, double g) { return JS_NewFloat64(js,g); } double js2number(JSContext *js, JSValue v) { @@ -230,14 +231,22 @@ STR = js2##TYPE(JS, __v); \ JS_FreeValue(JS, __v); } #define JS_GETPROPSTR(JS, VALUE, TARGET, STR, TYPE) {\ -JSValue __v = JS_GetPropertyStr(JS,VALUE,#STR); \ -TARGET.STR = js2##TYPE(JS, __v); \ -JS_FreeValue(JS,__v); }\ +JSValue STR##__v = JS_GetPropertyStr(JS,VALUE,#STR); \ +TARGET.STR = js2##TYPE(JS, STR##__v); \ +JS_FreeValue(JS,STR##__v); }\ -#define JS_GETPROP(JS, VALUE, TARGET, PROP, TYPE) {\ -JSValue __v = JS_GetProperty(JS,VALUE,PROP); \ -TARGET.STR = js2##TYPE(JS, __v); \ -JS_FreeValue(JS,__v); }\ +#define JS_GETPROP(JS, TARGET, VALUE, PROP, TYPE) {\ +JSValue VALUE##__##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \ +TARGET = js2##TYPE(JS, VALUE##__##PROP##__v); \ +JS_FreeValue(JS,VALUE##__##PROP##__v); }\ + +int JS_GETBOOL(JSContext *js, JSValue v, const char *prop) +{ + JSValue __v = JS_GetPropertyStr(js,v,prop); + int r = JS_ToBool(js,__v); + JS_FreeValue(js,__v); + return r; +} JSValue js_getpropertystr(JSContext *js, JSValue v, const char *str) { @@ -345,6 +354,657 @@ struct lrtb { static SDL_GPUDevice *global_gpu; +SDL_GPUGraphicsPipelineTargetInfo js2SDL_GPUGraphicsPipelineTargetInfo(JSContext *js, JSValue v) +{ +} + +SDL_GPUSampleCount js2SDL_GPUSampleCount(JSContext *js, JSValue v) +{ + int n = js2number(js,v); + switch(n) { + case 1: return SDL_GPU_SAMPLECOUNT_1; + case 2: return SDL_GPU_SAMPLECOUNT_2; + case 4: return SDL_GPU_SAMPLECOUNT_4; + case 8: return SDL_GPU_SAMPLECOUNT_8; + } + return -1; +} + +#define JS2ENUM(NAME, RETS, VALS) \ +int js2##NAME(JSContext *js, JSValue v) { \ + if (JS_IsUndefined(v)) return 0; \ + const char *str = JS_ToCString(js, v); \ + int *rets = (RETS); \ + const char **vals = (VALS); \ + /* Compute how many entries are in the arrays */ \ + int n = (int)(sizeof((RETS)) / sizeof((RETS)[0])); \ + for(int i = 0; i < n; i++) \ + if(!strcmp(vals[i], str)) { \ + JS_FreeCString(js, str); \ + return rets[i]; \ + } \ + JS_FreeCString(js, str); \ + return 0; \ +} + +static int rets_SDL_GPUSwapchainComposition[] = { + SDL_GPU_SWAPCHAINCOMPOSITION_SDR, + SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR, + SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR, + SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2048 +}; + +static const char *vals_SDL_GPUSwapchainComposition[] = { + "sdr", + "linear", + "hdr", + "hdr10" +}; + +JS2ENUM(SDL_GPUSwapchainComposition, rets_SDL_GPUSwapchainComposition, vals_SDL_GPUSwapchainComposition) + +static int rets_SDL_FlipMode[] = { + SDL_FLIP_NONE, + SDL_FLIP_HORIZONTAL, + SDL_FLIP_VERTICAL +}; + +static const char *vals_SDL_FlipMode[] = { + "none", + "horizontal", + "vertical" +}; + +JS2ENUM(SDL_FlipMode, rets_SDL_FlipMode, vals_SDL_FlipMode) + +/* ------------------------------------------------------- + 1) SDL_GPUBlendFactor + ------------------------------------------------------- */ + +static int rets_SDL_GPUBlendFactor[] = { + SDL_GPU_BLENDFACTOR_INVALID, + SDL_GPU_BLENDFACTOR_ZERO, + SDL_GPU_BLENDFACTOR_ONE, + SDL_GPU_BLENDFACTOR_SRC_COLOR, + SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_COLOR, + SDL_GPU_BLENDFACTOR_DST_COLOR, + SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_COLOR, + SDL_GPU_BLENDFACTOR_SRC_ALPHA, + SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + SDL_GPU_BLENDFACTOR_DST_ALPHA, + SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_ALPHA, + SDL_GPU_BLENDFACTOR_CONSTANT_COLOR, + SDL_GPU_BLENDFACTOR_ONE_MINUS_CONSTANT_COLOR, + SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE +}; +static const char *vals_SDL_GPUBlendFactor[] = { + "invalid", + "zero", + "one", + "src_color", + "one_minus_src_color", + "dst_color", + "one_minus_dst_color", + "src_alpha", + "one_minus_src_alpha", + "dst_alpha", + "one_minus_dst_alpha", + "constant_color", + "one_minus_constant_color", + "src_alpha_saturate" +}; + +JS2ENUM(SDL_GPUBlendFactor, rets_SDL_GPUBlendFactor, vals_SDL_GPUBlendFactor) + +/* ------------------------------------------------------- + 2) SDL_GPUBlendOp + ------------------------------------------------------- */ +static int rets_SDL_GPUBlendOp[] = { + SDL_GPU_BLENDOP_INVALID, + SDL_GPU_BLENDOP_ADD, + SDL_GPU_BLENDOP_SUBTRACT, + SDL_GPU_BLENDOP_REVERSE_SUBTRACT, + SDL_GPU_BLENDOP_MIN, + SDL_GPU_BLENDOP_MAX +}; +static const char *vals_SDL_GPUBlendOp[] = { + "invalid", + "add", + "subtract", + "reverse_subtract", + "min", + "max" +}; + +JS2ENUM(SDL_GPUBlendOp, rets_SDL_GPUBlendOp, vals_SDL_GPUBlendOp) + +/* ------------------------------------------------------- + 3) SDL_GPUCompareOp + ------------------------------------------------------- */ +static int rets_SDL_GPUCompareOp[] = { + SDL_GPU_COMPAREOP_INVALID, + SDL_GPU_COMPAREOP_NEVER, + SDL_GPU_COMPAREOP_LESS, + SDL_GPU_COMPAREOP_EQUAL, + SDL_GPU_COMPAREOP_LESS_OR_EQUAL, + SDL_GPU_COMPAREOP_GREATER, + SDL_GPU_COMPAREOP_NOT_EQUAL, + SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, + SDL_GPU_COMPAREOP_ALWAYS +}; +static const char *vals_SDL_GPUCompareOp[] = { + "invalid", + "never", + "less", + "equal", + "less_or_equal", + "greater", + "not_equal", + "greater_or_equal", + "always" +}; + +JS2ENUM(SDL_GPUCompareOp, rets_SDL_GPUCompareOp, vals_SDL_GPUCompareOp) + +/* ------------------------------------------------------- + 4) SDL_GPUCullMode + ------------------------------------------------------- */ +static int rets_SDL_GPUCullMode[] = { + SDL_GPU_CULLMODE_NONE, + SDL_GPU_CULLMODE_FRONT, + SDL_GPU_CULLMODE_BACK +}; +static const char *vals_SDL_GPUCullMode[] = { + "none", + "front", + "back" +}; + +JS2ENUM(SDL_GPUCullMode, rets_SDL_GPUCullMode, vals_SDL_GPUCullMode) + +/* ------------------------------------------------------- + 5) SDL_GPUFillMode + ------------------------------------------------------- */ +static int rets_SDL_GPUFillMode[] = { + SDL_GPU_FILLMODE_FILL, + SDL_GPU_FILLMODE_LINE +}; +static const char *vals_SDL_GPUFillMode[] = { + "fill", + "line" +}; + +JS2ENUM(SDL_GPUFillMode, rets_SDL_GPUFillMode, vals_SDL_GPUFillMode) + +/* ------------------------------------------------------- + 6) SDL_GPUFilter + ------------------------------------------------------- */ +static int rets_SDL_GPUFilter[] = { + SDL_GPU_FILTER_NEAREST, + SDL_GPU_FILTER_LINEAR +}; +static const char *vals_SDL_GPUFilter[] = { + "nearest", + "linear" +}; + +JS2ENUM(SDL_GPUFilter, rets_SDL_GPUFilter, vals_SDL_GPUFilter) + +/* ------------------------------------------------------- + 7) SDL_GPUFrontFace + ------------------------------------------------------- */ +static int rets_SDL_GPUFrontFace[] = { + SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, + SDL_GPU_FRONTFACE_CLOCKWISE +}; +static const char *vals_SDL_GPUFrontFace[] = { + "counter_clockwise", + "clockwise" +}; + +JS2ENUM(SDL_GPUFrontFace, rets_SDL_GPUFrontFace, vals_SDL_GPUFrontFace) + +/* ------------------------------------------------------- + 8) SDL_GPULoadOp + ------------------------------------------------------- */ +static int rets_SDL_GPULoadOp[] = { + SDL_GPU_LOADOP_LOAD, + SDL_GPU_LOADOP_CLEAR, + SDL_GPU_LOADOP_DONT_CARE +}; +static const char *vals_SDL_GPULoadOp[] = { + "load", + "clear", + "dont_care" +}; + +JS2ENUM(SDL_GPULoadOp, rets_SDL_GPULoadOp, vals_SDL_GPULoadOp) + +/* ------------------------------------------------------- + 9) SDL_GPUPresentMode + ------------------------------------------------------- */ +static int rets_SDL_GPUPresentMode[] = { + SDL_GPU_PRESENTMODE_VSYNC, + SDL_GPU_PRESENTMODE_IMMEDIATE, + SDL_GPU_PRESENTMODE_MAILBOX +}; +static const char *vals_SDL_GPUPresentMode[] = { + "vsync", + "immediate", + "mailbox" +}; + +JS2ENUM(SDL_GPUPresentMode, rets_SDL_GPUPresentMode, vals_SDL_GPUPresentMode) + +/* ------------------------------------------------------- + 10) SDL_GPUPrimitiveType + ------------------------------------------------------- */ +static int rets_SDL_GPUPrimitiveType[] = { + SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP, + SDL_GPU_PRIMITIVETYPE_LINELIST, + SDL_GPU_PRIMITIVETYPE_LINESTRIP, + SDL_GPU_PRIMITIVETYPE_POINTLIST +}; +static const char *vals_SDL_GPUPrimitiveType[] = { + "triangle", + "trianglestrip", + "line", + "linestrip", + "point" +}; + +JS2ENUM(SDL_GPUPrimitiveType, rets_SDL_GPUPrimitiveType, vals_SDL_GPUPrimitiveType) + +/* ------------------------------------------------------- + 11) SDL_GPUSamplerAddressMode + ------------------------------------------------------- */ +static int rets_SDL_GPUSamplerAddressMode[] = { + SDL_GPU_SAMPLERADDRESSMODE_REPEAT, + SDL_GPU_SAMPLERADDRESSMODE_MIRRORED_REPEAT, + SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE +}; +static const char *vals_SDL_GPUSamplerAddressMode[] = { + "repeat", + "mirrored_repeat", + "clamp" +}; + +JS2ENUM(SDL_GPUSamplerAddressMode, rets_SDL_GPUSamplerAddressMode, vals_SDL_GPUSamplerAddressMode) + +/* ------------------------------------------------------- + 12) SDL_GPUSamplerMipmapMode + ------------------------------------------------------- */ +static int rets_SDL_GPUSamplerMipmapMode[] = { + SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, + SDL_GPU_SAMPLERMIPMAPMODE_LINEAR +}; +static const char *vals_SDL_GPUSamplerMipmapMode[] = { + "nearest", + "linear" +}; + +JS2ENUM(SDL_GPUSamplerMipmapMode, rets_SDL_GPUSamplerMipmapMode, vals_SDL_GPUSamplerMipmapMode) + +/* ------------------------------------------------------- + 13) SDL_GPUStencilOp + ------------------------------------------------------- */ +static int rets_SDL_GPUStencilOp[] = { + SDL_GPU_STENCILOP_INVALID, + SDL_GPU_STENCILOP_KEEP, + SDL_GPU_STENCILOP_ZERO, + SDL_GPU_STENCILOP_REPLACE, + SDL_GPU_STENCILOP_INCREMENT_AND_CLAMP, + SDL_GPU_STENCILOP_DECREMENT_AND_CLAMP, + SDL_GPU_STENCILOP_INVERT, + SDL_GPU_STENCILOP_INCREMENT_AND_WRAP, + SDL_GPU_STENCILOP_DECREMENT_AND_WRAP +}; +static const char *vals_SDL_GPUStencilOp[] = { + "invalid", + "keep", + "zero", + "replace", + "increment_and_clamp", + "decrement_and_clamp", + "invert", + "increment_and_wrap", + "decrement_and_wrap" +}; + +JS2ENUM(SDL_GPUStencilOp, rets_SDL_GPUStencilOp, vals_SDL_GPUStencilOp) + +static int rets_SDL_GPUTextureType[] = { + SDL_GPU_TEXTURETYPE_2D, /**< The texture is a 2-dimensional image. */ + SDL_GPU_TEXTURETYPE_2D_ARRAY, /**< The texture is a 2-dimensional array image. */ + SDL_GPU_TEXTURETYPE_3D, /**< The texture is a 3-dimensional image. */ + SDL_GPU_TEXTURETYPE_CUBE, /**< The texture is a cube image. */ + SDL_GPU_TEXTURETYPE_CUBE_ARRAY /**< The texture is a cube array image. */ +}; + +static const char *vals_SDL_GPUTextureType[] = { + "2d", + "2d array", + "3d", + "cube", + "cube array" +}; + +JS2ENUM(SDL_GPUTextureType, rets_SDL_GPUTextureType, vals_SDL_GPUTextureType) + +/* ------------------------------------------------------- + 14) SDL_GPUStoreOp + ------------------------------------------------------- */ +static int rets_SDL_GPUStoreOp[] = { + SDL_GPU_STOREOP_STORE, + SDL_GPU_STOREOP_DONT_CARE, + SDL_GPU_STOREOP_RESOLVE, + SDL_GPU_STOREOP_RESOLVE_AND_STORE +}; + +static const char *vals_SDL_GPUStoreOp[] = { + "store", + "dont_care", + "resolve", + "resolve_and_store" +}; + +JS2ENUM(SDL_GPUStoreOp, rets_SDL_GPUStoreOp, vals_SDL_GPUStoreOp) + +/* ------------------------------------------------------- + X) SDL_GPUTextureType + ------------------------------------------------------- */ +static int rets_SDL_GPUTextureFormat[] = { + SDL_GPU_TEXTUREFORMAT_INVALID, + + /* Unsigned Normalized Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_A8_UNORM, + SDL_GPU_TEXTUREFORMAT_R8_UNORM, + SDL_GPU_TEXTUREFORMAT_R8G8_UNORM, + SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, + SDL_GPU_TEXTUREFORMAT_R16_UNORM, + SDL_GPU_TEXTUREFORMAT_R16G16_UNORM, + SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM, + SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM, + SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM, + SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM, + SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM, + SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, + /* Compressed Unsigned Normalized Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM, + SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM, + SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM, + SDL_GPU_TEXTUREFORMAT_BC4_R_UNORM, + SDL_GPU_TEXTUREFORMAT_BC5_RG_UNORM, + SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM, + /* Compressed Signed Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT, + /* Compressed Unsigned Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT, + /* Signed Normalized Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_R8_SNORM, + SDL_GPU_TEXTUREFORMAT_R8G8_SNORM, + SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM, + SDL_GPU_TEXTUREFORMAT_R16_SNORM, + SDL_GPU_TEXTUREFORMAT_R16G16_SNORM, + SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM, + /* Signed Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_R16_FLOAT, + SDL_GPU_TEXTUREFORMAT_R16G16_FLOAT, + SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT, + SDL_GPU_TEXTUREFORMAT_R32_FLOAT, + SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT, + SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT, + /* Unsigned Float Color Formats */ + SDL_GPU_TEXTUREFORMAT_R11G11B10_UFLOAT, + /* Unsigned Integer Color Formats */ + SDL_GPU_TEXTUREFORMAT_R8_UINT, + SDL_GPU_TEXTUREFORMAT_R8G8_UINT, + SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT, + SDL_GPU_TEXTUREFORMAT_R16_UINT, + SDL_GPU_TEXTUREFORMAT_R16G16_UINT, + SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT, + SDL_GPU_TEXTUREFORMAT_R32_UINT, + SDL_GPU_TEXTUREFORMAT_R32G32_UINT, + SDL_GPU_TEXTUREFORMAT_R32G32B32A32_UINT, + /* Signed Integer Color Formats */ + SDL_GPU_TEXTUREFORMAT_R8_INT, + SDL_GPU_TEXTUREFORMAT_R8G8_INT, + SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT, + SDL_GPU_TEXTUREFORMAT_R16_INT, + SDL_GPU_TEXTUREFORMAT_R16G16_INT, + SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT, + SDL_GPU_TEXTUREFORMAT_R32_INT, + SDL_GPU_TEXTUREFORMAT_R32G32_INT, + SDL_GPU_TEXTUREFORMAT_R32G32B32A32_INT, + /* SRGB Unsigned Normalized Color Formats */ + SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, + /* Compressed SRGB Unsigned Normalized Color Formats */ + SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB, + /* Depth Formats */ + SDL_GPU_TEXTUREFORMAT_D16_UNORM, + SDL_GPU_TEXTUREFORMAT_D24_UNORM, + SDL_GPU_TEXTUREFORMAT_D32_FLOAT, + SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT, + SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT, + /* Compressed ASTC Normalized Float Color Formats*/ + SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM, + SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM, + /* Compressed SRGB ASTC Normalized Float Color Formats*/ + SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB, + SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB, + /* Compressed ASTC Signed Float Color Formats*/ + SDL_GPU_TEXTUREFORMAT_ASTC_4x4_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_5x4_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_5x5_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_6x5_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_6x6_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_8x5_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_8x6_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_8x8_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_10x5_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_10x6_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_10x8_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_10x10_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_12x10_FLOAT, + SDL_GPU_TEXTUREFORMAT_ASTC_12x12_FLOAT +}; + +static const char *vals_SDL_GPUTextureFormat[] = { + "invalid", + "a8", + "r8", + "rg8", + "rgba8", + "r16", + "rg16", + "rgba16", + "r10g10b10a2", + "b5g6r5", + "b5g5r5a1", + "b4g4r4a4", + "b8g8r8a8", + + "bc1", + "bc2", + "bc3", + "bc4", + "bc5", + "bc7", + "bc6h float", + "bc6h ufloat", + + "r8 snorm", + "rg8 snorm", + "rgba8 snorm", + "r16 snorm", + "rg16 snorm", + "rgba16 snorm", + + "r16 float", + "rg16 float", + "rgba16 float", + "r32 float", + "rg32 float", + "rgba32 float", + + "r11g11b10", + + "r8 uint", + "rg8 uint", + "rgba8 uint", + "r16 uint", + "rg16 uint", + "rgba16 uint", + "r32 uint", + "rg32 uint", + "rgba32 uint", + + "r8 int", + "rg8 int", + "rgba8 int", + "r16 int", + "rg16 int", + "rgba16 int", + "r32 int", + "rg32 int", + "rgba32 int", + + "rgba8 srgb", + "b8g8r8a8 srgb", + "bc1 srgb", + "bc2 srgb", + "bc3 srgb", + "bc7 srgb", + + "d16", + "d24", + "d32 float", + "d24 s8", + "d32 float s8", + + "astc 4x4", + "astc 5x4", + "astc 5x5", + "astc 6x5", + "astc 6x6", + "astc 8x5", + "astc 8x6", + "astc 8x8", + "astc 10x5", + "astc 10x6", + "astc 10x8", + "astc 10x10", + "astc 12x10", + "astc 12x12", + + "astc 4x4 srgb", + "astc 5x4 srgb", + "astc 5x5 srgb", + "astc 6x5 srgb", + "astc 6x6 srgb", + "astc 8x5 srgb", + "astc 8x6 srgb", + "astc 8x8 srgb", + "astc 10x5 srgb", + "astc 10x6 srgb", + "astc 10x8 srgb", + "astc 10x10 srgb", + "astc 12x10 srgb", + "astc 12x12 srgb", + + "astc 4x4 float", + "astc 5x4 float", + "astc 5x5 float", + "astc 6x5 float", + "astc 6x6 float", + "astc 8x5 float", + "astc 8x6 float", + "astc 8x8 float", + "astc 10x5 float", + "astc 10x6 float", + "astc 10x8 float", + "astc 10x10 float", + "astc 12x10 float", + "astc 12x12 float" +}; + +JS2ENUM(SDL_GPUTextureFormat, rets_SDL_GPUTextureFormat, vals_SDL_GPUTextureFormat); + +SDL_GPUColorTargetBlendState js2SDL_GPUColorTargetBlendState(JSContext *js, JSValue v) +{ + SDL_GPUColorTargetBlendState state = {0}; + JS_GETPROP(js,state.src_color_blendfactor,v,src_rgb,SDL_GPUBlendFactor); + JS_GETPROP(js,state.dst_color_blendfactor,v,dst_rgb,SDL_GPUBlendFactor); + JS_GETPROP(js,state.src_alpha_blendfactor,v,src_alpha,SDL_GPUBlendFactor); + JS_GETPROP(js,state.dst_alpha_blendfactor,v,src_alpha,SDL_GPUBlendFactor); + JS_GETPROP(js,state.color_blend_op,v,op_rgb,SDL_GPUBlendOp) + JS_GETPROP(js,state.alpha_blend_op,v,op_alpha,SDL_GPUBlendOp) + JS_GETPROP(js,state.enable_blend,v,enabled,bool) + return state; +} + +SDL_GPUColorTargetDescription js2SDL_GPUColorTargetDescription(JSContext *js, JSValue v) +{ + SDL_GPUColorTargetDescription dsc = {0}; + JS_GETPROP(js,dsc.format,v,format,SDL_GPUTextureFormat) + JS_GETPROP(js,dsc.blend_state,v,blend,SDL_GPUColorTargetBlendState) + return dsc; +} + +SDL_GPUStencilOpState js2SDL_GPUStencilOpState(JSContext *js, JSValue v) +{ + SDL_GPUStencilOpState state; + memset(&state, 0, sizeof(state)); + + JSValue compare_val = JS_GetPropertyStr(js, v, "compare"); + if(!JS_IsUndefined(compare_val)) state.compare_op = js2SDL_GPUCompareOp(js, compare_val); + JS_FreeValue(js, compare_val); + + JSValue fail_val = JS_GetPropertyStr(js, v, "fail"); + if(!JS_IsUndefined(fail_val)) state.fail_op = js2SDL_GPUStencilOp(js, fail_val); + JS_FreeValue(js, fail_val); + + JSValue depth_fail_val = JS_GetPropertyStr(js, v, "depth_fail"); + if(!JS_IsUndefined(depth_fail_val)) state.depth_fail_op = js2SDL_GPUStencilOp(js, depth_fail_val); + JS_FreeValue(js, depth_fail_val); + + JSValue pass_val = JS_GetPropertyStr(js, v, "pass"); + if(!JS_IsUndefined(pass_val)) state.pass_op = js2SDL_GPUStencilOp(js, pass_val); + JS_FreeValue(js, pass_val); + + return state; +} + + typedef struct lrtb lrtb; lrtb js2lrtb(JSContext *js, JSValue v) @@ -424,7 +1084,7 @@ void SDL_GPUCopyPass_free(JSRuntime *rt, SDL_GPUCopyPass *c) { } void SDL_GPURenderPass_free(JSRuntime *rt, SDL_GPURenderPass *c) { } #define GPURELEASECLASS(NAME) \ -void SDL_GPU##NAME##_free(JSRuntime *rt, SDL_GPU##NAME *c) { printf("releasing...\n"); SDL_ReleaseGPU##NAME(global_gpu, c); } \ +void SDL_GPU##NAME##_free(JSRuntime *rt, SDL_GPU##NAME *c) { SDL_ReleaseGPU##NAME(global_gpu, c); } \ QJSCLASS(SDL_GPU##NAME) \ QJSCLASS(transform) @@ -532,7 +1192,6 @@ void *get_typed_buffer(JSContext *js, JSValue argv, size_t *len) float *js2floatarray(JSContext *js, JSValue v) { JSClassID class = JS_GetClassID(v); if (class == JS_CLASS_FLOAT32_ARRAY) { - printf("FAST PATH\n"); size_t len; return get_typed_buffer(js,v, &len); } @@ -571,6 +1230,12 @@ colorf js2color(JSContext *js,JSValue v) { return color; } +SDL_FColor js2SDL_FColor(JSContext *js, JSValue v) +{ + colorf color = js2color(js,v); + return (SDL_FColor){color.r,color.g,color.b,color.a}; +} + JSValue color2js(JSContext *js, colorf color) { JSValue arr = JS_NewArray(js); @@ -2004,11 +2669,31 @@ JSC_SCALL(SDL_Window_make_renderer, return SDL_Renderer2js(js,r); ) +SDL_GPUShaderFormat js2SDL_GPUShaderFormat(JSContext *js, JSValue v) +{ + const char *format_str = JS_ToCString(js, v); + SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_SPIRV; // default to SPIR-V + if (format_str) { + if (!strcmp(format_str, "private")) format = SDL_GPU_SHADERFORMAT_PRIVATE; + else if (!strcmp(format_str, "spv")) format = SDL_GPU_SHADERFORMAT_SPIRV; + else if (!strcmp(format_str, "dxbc")) format = SDL_GPU_SHADERFORMAT_DXBC; + else if (!strcmp(format_str, "dxil")) format = SDL_GPU_SHADERFORMAT_DXIL; + else if (!strcmp(format_str, "msl")) format = SDL_GPU_SHADERFORMAT_MSL; + else if (!strcmp(format_str, "metallib")) format = SDL_GPU_SHADERFORMAT_METALLIB; + JS_FreeCString(js, format_str); + } + return format; +} + JSC_SCALL(SDL_Window_make_gpu, SDL_Window *win = js2SDL_Window(js,self); - SDL_GPUDevice *gpu = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, 1, NULL); - global_gpu = gpu; + const char *name = JS_ToCString(js,argv[1]); + SDL_GPUDevice *gpu = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_MSL, JS_ToBool(js,argv[0]), name); + JS_FreeCString(js,name); + if (!gpu) return JS_ThrowReferenceError("Could not create GPU device! %s", SDL_GetError()); + + global_gpu = gpu; return SDL_GPUDevice2js(js,gpu); ) @@ -2156,6 +2841,20 @@ JSC_CCALL(SDL_Renderer_rect, SDL_RenderRect(r, &rect); ) +SDL_GPUColorTargetInfo js2SDL_GPUColorTargetInfo(JSContext *js, JSValue v) +{ + SDL_GPUColorTargetInfo info = {0}; + JS_GETPROP(js, info.texture, v, texture, SDL_GPUTexture) + JS_GETPROP(js,info.mip_level,v,mip_level,number) + JS_GETPROP(js,info.layer_or_depth_plane, v, layer, number) + JS_GETPROP(js,info.load_op,v,load,SDL_GPULoadOp) + JS_GETPROP(js,info.store_op,v,store,SDL_GPUStoreOp) + JS_GETPROP(js,info.resolve_mip_level,v,resolve_mip_level,number) + JS_GETPROP(js,info.resolve_layer,v,resolve_layer,number) + JS_GETPROP(js,info.clear_color,v,clear,SDL_FColor) + return info; +} + JSC_CCALL(renderer_load_texture, SDL_Renderer *r = js2SDL_Renderer(js,self); SDL_Surface *surf = js2SDL_Surface(js,argv[0]); @@ -2524,187 +3223,6 @@ static void generate_normals(float* positions, size_t vertex_count, uint16_t* in free(temp_normals); } -JSC_CCALL(gpu_load_gltf_model, - const char* path = JS_ToCString(js, argv[0]); - if (!path) { - // Handle error - return JS_EXCEPTION; - } - - cgltf_options options = {0}; - cgltf_data* data = NULL; - - cgltf_result result = cgltf_parse_file(&options, path, &data); - if (result != cgltf_result_success) { - JS_FreeCString(js, path); - return JS_EXCEPTION; - } - - result = cgltf_load_buffers(&options, data, path); - JS_FreeCString(js, path); - if (result != cgltf_result_success) { - cgltf_free(data); - return JS_EXCEPTION; - } - - if (data->meshes_count == 0 || data->meshes[0].primitives_count == 0) { - cgltf_free(data); - return JS_EXCEPTION; - } - - cgltf_primitive* prim = &data->meshes[0].primitives[0]; - cgltf_accessor* indices_accessor = prim->indices; - - // Load indices first, so we have them for normal generation if needed. - size_t index_count = 0; - uint16_t* indices_data = NULL; - if (indices_accessor) { - index_count = indices_accessor->count; - // Check if we can fit indices into uint16 - // For simplicity, assume we can (if index accessor max index > 65535, we must use bigger type) - indices_data = malloc(sizeof(uint16_t)*index_count); - for (size_t i = 0; i < index_count; i++) { - size_t idx = cgltf_accessor_read_index(indices_accessor, i); - indices_data[i] = (uint16_t)idx; - } - } - - // We'll fill these out as we find attributes - float* positions = NULL; size_t vertex_count = 0; - int16_t* normals_packed = NULL; - int have_normals = 0; - uint16_t* uvs_packed = NULL; - - ret = JS_NewObject(js); - - // Iterate over attributes and handle them immediately - for (size_t i = 0; i < prim->attributes_count; i++) { - cgltf_attribute* attr = &prim->attributes[i]; - cgltf_accessor* accessor = attr->data; - - switch (attr->type) { - case cgltf_attribute_type_position: { - // Load positions immediately - vertex_count = accessor->count; - positions = malloc(sizeof(float)*3*vertex_count); - for (size_t v = 0; v < vertex_count; v++) { - cgltf_accessor_read_float(accessor, v, &positions[v*3], 3); - } - - // Create a JS buffer for positions right now - // Positions remain float32. - JS_SetProperty(js, ret, pos_atom, - make_gpu_buffer(js, positions, sizeof(float)*3*vertex_count, JS_TYPED_ARRAY_FLOAT32, 3, 0,0)); - - break; - } - case cgltf_attribute_type_normal: { - // Load normals and pack into int16 right away - // If no positions yet, we must assume they come first or handle after we find positions. - // We'll assume position found first as per instructions. - have_normals = 1; - normals_packed = malloc(sizeof(int16_t)*3*accessor->count); - - for (size_t v = 0; v < accessor->count; v++) { - float n[3]; - cgltf_accessor_read_float(accessor, v, n, 3); - // Normalize just in case (should be normalized anyway) - float len = sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); - if (len > 1e-6f) { n[0]/=len; n[1]/=len; n[2]/=len; } else { n[0]=0; n[1]=0; n[2]=1; } - - normals_packed[v*3+0] = (int16_t)(n[0] * 32767.0f); - normals_packed[v*3+1] = (int16_t)(n[1] * 32767.0f); - normals_packed[v*3+2] = (int16_t)(n[2] * 32767.0f); - } - - // Immediately store normals - JS_SetProperty(js, ret, norm_atom, - make_gpu_buffer(js, normals_packed, sizeof(int16_t)*3*accessor->count, JS_TYPED_ARRAY_INT16, 3, 1 /* normalized */,0)); - break; - } - case cgltf_attribute_type_texcoord: { - // Assume texcoord_0 only - if (attr->index == 0) { - // Pack UVs into uint16 normalized - uvs_packed = malloc(sizeof(uint16_t)*2*accessor->count); - for (size_t v = 0; v < accessor->count; v++) { - float uv[2]; - cgltf_accessor_read_float(accessor, v, uv, 2); - // Clamp and convert to [0,1] - float u = uv[0]; if (u < 0) u=0; if (u>1) u=1; - float vv = uv[1]; if (vv < 0) vv=0; if (vv>1) vv=1; - uvs_packed[v*2+0] = (uint16_t)(u * 65535.0f); - uvs_packed[v*2+1] = (uint16_t)(vv * 65535.0f); - } - - // Immediately store UVs - JS_SetProperty(js, ret, uv_atom, - make_gpu_buffer(js, uvs_packed, sizeof(uint16_t)*2*accessor->count, JS_TYPED_ARRAY_UINT16, 2, 1 /* normalized */,0)); - } - break; - } - default: - // Other attributes not handled here. - break; - } - } - - // If we didn't find normals, generate them now. - if (!have_normals) { - if (!positions) { - // Can't generate normals without positions - cgltf_free(data); - if (positions) free(positions); - if (indices_data) free(indices_data); - if (uvs_packed) free(uvs_packed); - return JS_EXCEPTION; - } - - // If we have no indices, we can generate normals in a non-indexed fashion, - // but here we assume we have indices. If not, handle that case as needed. - if (indices_data && index_count > 0) { - normals_packed = malloc(sizeof(int16_t)*3*vertex_count); - generate_normals(positions, vertex_count, indices_data, index_count, normals_packed); - - JS_SetProperty(js, ret, norm_atom, - make_gpu_buffer(js, normals_packed, sizeof(int16_t)*3*vertex_count, JS_TYPED_ARRAY_INT16, 3, 1 /* normalized */,0)); - } else { - // Non-indexed normal generation would go here if needed. - // For simplicity, just create default normals (0,0,1) - normals_packed = malloc(sizeof(int16_t)*3*vertex_count); - for (size_t i = 0; i < vertex_count; i++) { - normals_packed[i*3+0] = 0; - normals_packed[i*3+1] = 0; - normals_packed[i*3+2] = 32767; // (0,0,1) - } - JS_SetProperty(js, ret, norm_atom, - make_gpu_buffer(js, normals_packed, sizeof(int16_t)*3*vertex_count, JS_TYPED_ARRAY_INT16, 3, 1,0)); - } - } - - // Store indices if we have them - if (indices_data && index_count > 0) { - JS_SetProperty(js, ret, indices_atom, - make_gpu_buffer(js, indices_data, sizeof(uint16_t)*index_count, JS_TYPED_ARRAY_UINT16, 1, 0,1)); - } - - // Store vertices and count - // count is usually the number of indices if available, else vertex_count - JS_SetProperty(js, ret, vertices_atom, number2js(js, vertex_count)); - JS_SetProperty(js, ret, count_atom, number2js(js, index_count > 0 ? index_count : vertex_count)); - JS_SetPropertyStr(js,ret,"num_indices", number2js(js, index_count > 0 ? index_count : vertex_count)); - - // Cleanup - free(positions); - free(normals_packed); - free(uvs_packed); - free(indices_data); - - cgltf_free(data); - - return ret; -) - // Given an array of sprites, make the necessary geometry // A sprite is expected to have: // transform: a transform encoding position and rotation. its scale is in pixels - so a scale of 1 means the image will draw only on a single pixel. @@ -2816,26 +3334,38 @@ JSC_CCALL(gpu_claim_window, SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); SDL_Window *win = js2SDL_Window(js, argv[0]); SDL_ClaimWindowForGPUDevice(gpu,win); - if (!SDL_SetGPUSwapchainParameters(gpu,win,SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_IMMEDIATE)) - printf("Could not set: %s\n", SDL_GetError()); -// SDL_SetGPUAllowedFramesInFlight(gpu, 1); +) - SDL_GPUColorTargetDescription *dsc = calloc(sizeof(*dsc),1); - dsc->format = SDL_GetGPUSwapchainTextureFormat(gpu, win); -main_info =(SDL_GPUGraphicsPipelineTargetInfo) { - .num_color_targets = 1, - .color_target_descriptions = dsc, - .has_depth_stencil_target = 1, - .depth_stencil_format = RT_DEPTH, - }; +JSC_CCALL(gpu_set_swapchain, + if (!SDL_SetGPUSwapchainParameters(global_gpu,global_window, js2SDL_GPUSwapchainComposition(js,argv[0]), js2SDL_GPUPresentMode(js,argv[1]))) + return JS_ThrowReferenceError("Could not set: %s\n", SDL_GetError()); +) +static JSValue *js_swapchains; -post_info =(SDL_GPUGraphicsPipelineTargetInfo) { - .num_color_targets = 1, - .color_target_descriptions = dsc, - .has_depth_stencil_target = 0, - }; - +JSC_CCALL(cmd_acquire_swapchain, + SDL_GPUCommandBuffer *cmds = js2SDL_GPUCommandBuffer(js, self); + Uint32 w,h; + SDL_GPUTexture *texture; + SDL_AcquireGPUSwapchainTexture(cmds,global_window, &texture, &w, &h); + if (!texture) return JS_UNDEFINED; + JSValue swap = JS_UNDEFINED; + + for (int i = 0; i < arrlen(js_swapchains); i++) { + if (js2SDL_GPUTexture(js,js_swapchains[i]) == texture) { + swap = js_swapchains[i]; + break; + } + } + + if (JS_IsUndefined(swap)) { + swap = SDL_GPUTexture2js(js,texture); + arrput(js_swapchains,swap); + } + + JS_SetPropertyStr(js,swap,"width", number2js(js,w)); + JS_SetPropertyStr(js,swap,"height", number2js(js,h)); + return JS_DupValue(js,swap); ) JSC_CCALL(cmd_swapchain_pass, @@ -2859,59 +3389,6 @@ JSC_CCALL(cmd_swapchain_pass, return jspass; ) -JSC_CCALL(gpu_mainRT, - SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); - HMM_Vec2 size = js2vec2(js,argv[0]); - JSValue color_targets = JS_NewArray(js); - SDL_GPUTexture *colortex = SDL_CreateGPUTexture(gpu, &(SDL_GPUTextureCreateInfo) { - .type = SDL_GPU_TEXTURETYPE_2D, - .format = SDL_GetGPUSwapchainTextureFormat(gpu,global_window), - .usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER, - .width = size.x, - .height = size.y, - .layer_count_or_depth = 1, - .num_levels = 1, - .sample_count = 0 - }); - SDL_GPUTexture *depthtex = SDL_CreateGPUTexture(gpu, &(SDL_GPUTextureCreateInfo) { - .type = SDL_GPU_TEXTURETYPE_2D, - .format = RT_DEPTH, - .usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER, - .width = size.x, - .height = size.y, - .layer_count_or_depth = 1, - .num_levels = 1, - .sample_count = 0 - }); - JSValue color_tar = JS_NewObject(js); - JS_SetPropertyStr(js,color_tar, "texture", SDL_GPUTexture2js(js,colortex)); - JS_SetPropertyStr(js,color_tar,"mip_level", number2js(js,0)); - JS_SetPropertyStr(js,color_tar,"load_op", JS_NewString(js,"clear")); - JS_SetPropertyStr(js,color_tar,"store_op", JS_NewString(js,"store")); - - JSValue depth_tar = JS_NewObject(js); - JSValue js_depthtex = SDL_GPUTexture2js(js,depthtex); - JS_SetPropertyStr(js,js_depthtex, "format", number2js(js,RT_DEPTH)); - JS_SetPropertyStr(js,depth_tar, "texture", js_depthtex); - JS_SetPropertyStr(js,depth_tar,"mip_level", number2js(js,0)); - JS_SetPropertyStr(js,depth_tar,"load_op", JS_NewString(js,"clear")); - JS_SetPropertyStr(js,depth_tar,"store_op", JS_NewString(js,"store")); - JS_SetPropertyStr(js,depth_tar,"stencil_store_op", JS_NewString(js,"store")); - JS_SetPropertyStr(js,depth_tar,"stencil_load_op", JS_NewString(js,"clear")); - JS_SetPropertyStr(js,depth_tar,"clear_stencil", number2js(js,0)); - JS_SetPropertyStr(js,depth_tar,"clear_depth", number2js(js,1)); - - SDL_SetGPUTextureName(gpu, depthtex, "main pass depth"); - - JS_SetPropertyUint32(js,color_targets,0,color_tar); - - JSValue rt = JS_NewObject(js); - - JS_SetPropertyStr(js,rt,"color_targets",color_targets); - JS_SetPropertyStr(js,rt,"depth_stencil", depth_tar); - return rt; -) - JSC_CCALL(gpu_load_texture, SDL_GPUDevice *gpu = js2SDL_GPUDevice(js, self); SDL_Surface *surf = js2SDL_Surface(js, argv[0]); @@ -2951,43 +3428,36 @@ switch (sfmt) { case SDL_PIXELFORMAT_ABGR32: case SDL_PIXELFORMAT_ARGB32: case SDL_PIXELFORMAT_BGRA32: - // 8-8-8-8 format with alpha present - chosen_format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - break; - case SDL_PIXELFORMAT_RGBX8888: case SDL_PIXELFORMAT_XRGB8888: case SDL_PIXELFORMAT_BGRX8888: case SDL_PIXELFORMAT_XBGR8888: - // 8-8-8-8 format no alpha - chosen_format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - break; + chosen_format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + break; case SDL_PIXELFORMAT_RGBA4444: case SDL_PIXELFORMAT_ABGR4444: case SDL_PIXELFORMAT_ARGB4444: case SDL_PIXELFORMAT_BGRA4444: - // 4-4-4-4 format - chosen_format = SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM; - break; + // 4-4-4-4 format + chosen_format = SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM; + break; case SDL_PIXELFORMAT_RGB565: case SDL_PIXELFORMAT_BGR565: - // 5-6-5 format - chosen_format = SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM; - break; + // 5-6-5 format + chosen_format = SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM; + break; case SDL_PIXELFORMAT_RGBA5551: case SDL_PIXELFORMAT_ARGB1555: case SDL_PIXELFORMAT_BGRA5551: case SDL_PIXELFORMAT_ABGR1555: - // 5-5-5-1 format - chosen_format = SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM; - break; + // 5-5-5-1 format + chosen_format = SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM; + break; default: - // If no direct mapping, convert to RGBA8888 - // Note: If we reach here, we probably don't have a direct map surf = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_RGBA8888); dofree = 1; sfmt = SDL_PIXELFORMAT_RGBA8888; @@ -3129,7 +3599,7 @@ SDL_SubmitGPUCommandBuffer(uploadcmd); SDL_ReleaseGPUTransferBuffer(gpu, tex_buffer); if (compress) { - free(upload_data); + free(upload_data); } ret = SDL_GPUTexture2js(js, tex); @@ -3143,82 +3613,6 @@ JSC_CCALL(gpu_logical_size, ) -int atom2front_face(JSAtom atom) -{ - if(atom == cw_atom) return SDL_GPU_FRONTFACE_CLOCKWISE; - else return SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE; -} - -int atom2cull_mode(JSAtom atom) -{ - if(atom == front_atom) return SDL_GPU_CULLMODE_FRONT; - else if(atom == back_atom) return SDL_GPU_CULLMODE_BACK; - else return SDL_GPU_CULLMODE_NONE; -} - -int atom2primitive_type(JSAtom atom) -{ - if(atom == point_atom) return SDL_GPU_PRIMITIVETYPE_POINTLIST; - else if(atom == line_atom) return SDL_GPU_PRIMITIVETYPE_LINELIST; - else if(atom == linestrip_atom) return SDL_GPU_PRIMITIVETYPE_LINESTRIP; - else if(atom == trianglestrip_atom) return SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP; - else return SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; -} - -int atom2compare_op(JSAtom atom) -{ - if(atom == never_atom) return SDL_GPU_COMPAREOP_NEVER; - else if(atom == less_atom) return SDL_GPU_COMPAREOP_LESS; - else if(atom == equal_atom) return SDL_GPU_COMPAREOP_EQUAL; - else if(atom == less_equal_atom) return SDL_GPU_COMPAREOP_LESS_OR_EQUAL; - else if(atom == greater_atom) return SDL_GPU_COMPAREOP_GREATER; - else if(atom == not_equal_atom) return SDL_GPU_COMPAREOP_NOT_EQUAL; - else if(atom == greater_equal_atom) return SDL_GPU_COMPAREOP_GREATER_OR_EQUAL; - else return SDL_GPU_COMPAREOP_ALWAYS; -} - -int atom2stencil_op(JSAtom atom) -{ - if(atom == keep_atom) return SDL_GPU_STENCILOP_KEEP; - else if(atom == zero_stencil_atom) return SDL_GPU_STENCILOP_ZERO; - else if(atom == replace_atom) return SDL_GPU_STENCILOP_REPLACE; - else if(atom == incr_clamp_atom) return SDL_GPU_STENCILOP_INCREMENT_AND_CLAMP; - else if(atom == decr_clamp_atom) return SDL_GPU_STENCILOP_DECREMENT_AND_CLAMP; - else if(atom == invert_atom) return SDL_GPU_STENCILOP_INVERT; - else if(atom == incr_wrap_atom) return SDL_GPU_STENCILOP_INCREMENT_AND_WRAP; - else if(atom == decr_wrap_atom) return SDL_GPU_STENCILOP_DECREMENT_AND_WRAP; - else return SDL_GPU_STENCILOP_KEEP; -} - -int atom2blend_factor(JSAtom atom) -{ - if(atom == zero_atom) return SDL_GPU_BLENDFACTOR_ZERO; - else if(atom == one_atom) return SDL_GPU_BLENDFACTOR_ONE; - else if(atom == src_color_atom) return SDL_GPU_BLENDFACTOR_SRC_COLOR; - else if(atom == one_minus_src_color_atom) return SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_COLOR; - else if(atom == dst_color_atom) return SDL_GPU_BLENDFACTOR_DST_COLOR; - else if(atom == one_minus_dst_color_atom) return SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_COLOR; - else if(atom == src_alpha_atom) return SDL_GPU_BLENDFACTOR_SRC_ALPHA; - else if(atom == one_minus_src_alpha_atom) return SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - else if(atom == dst_alpha_atom) return SDL_GPU_BLENDFACTOR_DST_ALPHA; - else if(atom == one_minus_dst_alpha_atom) return SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_ALPHA; - else if(atom == constant_color_atom) return SDL_GPU_BLENDFACTOR_CONSTANT_COLOR; - else if(atom == one_minus_constant_color_atom) return SDL_GPU_BLENDFACTOR_ONE_MINUS_CONSTANT_COLOR; - else if(atom == src_alpha_saturate_atom) return SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE; - else return SDL_GPU_BLENDFACTOR_ONE; -} - -int atom2blend_op(JSAtom atom) -{ - if(atom == add_atom) return SDL_GPU_BLENDOP_ADD; - else if(atom == sub_atom) return SDL_GPU_BLENDOP_SUBTRACT; - else if(atom == rev_sub_atom) return SDL_GPU_BLENDOP_REVERSE_SUBTRACT; - else if(atom == min_atom) return SDL_GPU_BLENDOP_MIN; - else if(atom == max_atom) return SDL_GPU_BLENDOP_MAX; - else return SDL_GPU_BLENDOP_ADD; -} - - static JSValue js_gpu_make_pipeline(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) { SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); if (argc < 1) @@ -3344,623 +3738,143 @@ static JSValue js_gpu_make_pipeline(JSContext *js, JSValueConst self, int argc, // Vertex Shader JSValue vertex_val = JS_GetPropertyStr(js, pipe, "vertex"); - if (JS_IsUndefined(vertex_val)) { - JS_FreeValue(js, vertex_val); - return JS_ThrowTypeError(js, "pipeline object must have a 'vertex' property"); - } - - JSValue vertex_gpu_val = JS_GetPropertyStr(js, vertex_val, "gpu"); - if (JS_IsUndefined(vertex_gpu_val)) { - JS_FreeValue(js, vertex_gpu_val); - JS_FreeValue(js, vertex_val); - return JS_ThrowTypeError(js, "pipeline.vertex must have a 'gpu' property"); - } - info.vertex_shader = js2SDL_GPUShader(js, vertex_gpu_val); - JS_FreeValue(js, vertex_gpu_val); + JSValue fragment_val = JS_GetPropertyStr(js,pipe,"fragment"); + JS_GETPROP(js,info.vertex_shader, vertex_val, gpu, SDL_GPUShader) + JS_GETPROP(js, info.fragment_shader, fragment_val, gpu, SDL_GPUShader) + JS_FreeValue(js, vertex_val); - - // Fragment Shader - JSValue fragment_val = JS_GetPropertyStr(js, pipe, "fragment"); - if (JS_IsUndefined(fragment_val)) { - JS_FreeValue(js, fragment_val); - return JS_ThrowTypeError(js, "pipeline object must have a 'fragment' property"); - } - - JSValue fragment_gpu_val = JS_GetPropertyStr(js, fragment_val, "gpu"); - if (JS_IsUndefined(fragment_gpu_val)) { - JS_FreeValue(js, fragment_gpu_val); - JS_FreeValue(js, fragment_val); - return JS_ThrowTypeError(js, "pipeline.fragment must have a 'gpu' property"); - } - info.fragment_shader = js2SDL_GPUShader(js, fragment_gpu_val); - JS_FreeValue(js, fragment_gpu_val); JS_FreeValue(js, fragment_val); // Primitive Type - JSValue primitive_val = JS_GetPropertyStr(js, pipe, "primitive"); - JSAtom primitive_atom = JS_ValueToAtom(js, primitive_val); - info.primitive_type = atom2primitive_type(primitive_atom); - JS_FreeAtom(js, primitive_atom); - JS_FreeValue(js, primitive_val); - + JS_GETPROP(js, info.primitive_type, pipe, primitive, SDL_GPUPrimitiveType) + // Rasterizer State - // Fill Mode - JSValue fill_val = JS_GetPropertyStr(js, pipe, "fill"); - info.rasterizer_state.fill_mode = JS_ToBool(js, fill_val) ? SDL_GPU_FILLMODE_FILL : SDL_GPU_FILLMODE_LINE; - JS_FreeValue(js, fill_val); - - // Cull Mode - JSValue cull_val = JS_GetPropertyStr(js, pipe, "cull"); - JSAtom cull_atom = JS_ValueToAtom(js, cull_val); - info.rasterizer_state.cull_mode = atom2cull_mode(cull_atom); - JS_FreeAtom(js, cull_atom); - JS_FreeValue(js, cull_val); - - // Front Face - JSValue face_val = JS_GetPropertyStr(js, pipe, "face"); - JSAtom face_atom = JS_ValueToAtom(js, face_val); - info.rasterizer_state.front_face = atom2front_face(face_atom); - JS_FreeAtom(js, face_atom); - JS_FreeValue(js, face_val); - + JS_GETPROP(js, info.rasterizer_state.fill_mode, pipe, fill, SDL_GPUFillMode) + JS_GETPROP(js, info.rasterizer_state.cull_mode, pipe, cull, SDL_GPUCullMode) + JS_GETPROP(js, info.rasterizer_state.front_face, pipe, face, SDL_GPUFrontFace) + // Depth Stencil State JSValue depth_val = JS_GetPropertyStr(js, pipe, "depth"); if (JS_IsObject(depth_val)) { - JSValue compare_val = JS_GetPropertyStr(js, depth_val, "compare"); - if (!JS_IsUndefined(compare_val)) { - JSAtom compare_atom = JS_ValueToAtom(js, compare_val); - info.depth_stencil_state.compare_op = atom2compare_op(compare_atom); - JS_FreeAtom(js, compare_atom); - } - JS_FreeValue(js, compare_val); - - // Enable Depth Test - JSValue test_val = JS_GetPropertyStr(js, depth_val, "test"); - if (!JS_IsUndefined(test_val)) - info.depth_stencil_state.enable_depth_test = JS_ToBool(js, test_val); - - JS_FreeValue(js, test_val); - - // Enable Depth Write - JSValue write_val = JS_GetPropertyStr(js, depth_val, "write"); - if (!JS_IsUndefined(write_val)) - info.depth_stencil_state.enable_depth_write = JS_ToBool(js, write_val); - JS_FreeValue(js, write_val); - - // Depth Bias Factors - JSValue bias_val = JS_GetPropertyStr(js, depth_val, "bias"); - if (!JS_IsUndefined(bias_val)) - JS_ToFloat64(js, &info.rasterizer_state.depth_bias_constant_factor, bias_val); - JS_FreeValue(js, bias_val); - - JSValue bias_slope_scale_val = JS_GetPropertyStr(js, depth_val, "bias_slope_scale"); - if (!JS_IsUndefined(bias_slope_scale_val)) - JS_ToFloat64(js, &info.rasterizer_state.depth_bias_slope_factor, bias_slope_scale_val); - JS_FreeValue(js, bias_slope_scale_val); - - JSValue bias_clamp_val = JS_GetPropertyStr(js, depth_val, "bias_clamp"); - if (!JS_IsUndefined(bias_clamp_val)) - JS_ToFloat64(js, &info.rasterizer_state.depth_bias_clamp, bias_clamp_val); - JS_FreeValue(js, bias_clamp_val); + JS_GETPROP(js,info.depth_stencil_state.compare_op, depth_val, compare, SDL_GPUCompareOp) + JS_GETPROP(js,info.depth_stencil_state.enable_depth_test, depth_val, test, bool) + JS_GETPROP(js,info.depth_stencil_state.enable_depth_write, depth_val, write, bool) + JS_GETPROP(js,info.rasterizer_state.depth_bias_constant_factor, depth_val, bias, number) + JS_GETPROP(js,info.rasterizer_state.depth_bias_slope_factor, depth_val,bias_slope_scale, number) + JS_GETPROP(js,info.rasterizer_state.depth_bias_clamp, depth_val,bias_clamp_val, number) } JS_FreeValue(js, depth_val); // Stencil State JSValue stencil_val = JS_GetPropertyStr(js, pipe, "stencil"); if (JS_IsObject(stencil_val)) { - JSValue enabled_val = JS_GetPropertyStr(js, stencil_val, "enabled"); - if (!JS_IsUndefined(enabled_val)) - info.depth_stencil_state.enable_stencil_test = JS_ToBool(js, enabled_val); - JS_FreeValue(js, enabled_val); - // Front Stencil - JSValue front_val = JS_GetPropertyStr(js, stencil_val, "front"); - if (JS_IsObject(front_val)) { - JSValue compare_val = JS_GetPropertyStr(js, front_val, "compare"); - if (!JS_IsUndefined(compare_val)) { - JSAtom compare_atom = JS_ValueToAtom(js, compare_val); - info.depth_stencil_state.front_stencil_state.compare_op = atom2compare_op(compare_atom); - JS_FreeAtom(js, compare_atom); - } - JS_FreeValue(js, compare_val); - JSValue fail_val = JS_GetPropertyStr(js, front_val, "fail"); - if (!JS_IsUndefined(fail_val)) { - JSAtom fail_atom = JS_ValueToAtom(js, fail_val); - info.depth_stencil_state.front_stencil_state.fail_op = atom2stencil_op(fail_atom); - JS_FreeAtom(js, fail_atom); - } - JS_FreeValue(js, fail_val); + JS_GETPROP(js,info.depth_stencil_state.enable_stencil_test, stencil_val, enabled, bool) + if (info.depth_stencil_state.enable_stencil_test) { + JS_GETPROP(js, info.depth_stencil_state.front_stencil_state, stencil_val, front, SDL_GPUStencilOpState) + JS_GETPROP(js, info.depth_stencil_state.back_stencil_state, stencil_val, back, SDL_GPUStencilOpState) - JSValue depth_fail_val = JS_GetPropertyStr(js, front_val, "depth_fail"); - if (!JS_IsUndefined(depth_fail_val)) { - JSAtom depth_fail_atom = JS_ValueToAtom(js, depth_fail_val); - info.depth_stencil_state.front_stencil_state.depth_fail_op = atom2stencil_op(depth_fail_atom); - JS_FreeAtom(js, depth_fail_atom); - } - JS_FreeValue(js, depth_fail_val); - JSValue pass_val = JS_GetPropertyStr(js, front_val, "pass"); - if (!JS_IsUndefined(pass_val)) { - JSAtom pass_atom = JS_ValueToAtom(js, pass_val); - info.depth_stencil_state.front_stencil_state.pass_op = atom2stencil_op(pass_atom); - JS_FreeAtom(js, pass_atom); - } - JS_FreeValue(js, pass_val); - } - JS_FreeValue(js, front_val); - // Back Stencil - JSValue back_val = JS_GetPropertyStr(js, stencil_val, "back"); - if (JS_IsObject(back_val)) { - JSValue compare_val = JS_GetPropertyStr(js, back_val, "compare"); - if (!JS_IsUndefined(compare_val)) { - JSAtom compare_atom = JS_ValueToAtom(js, compare_val); - info.depth_stencil_state.back_stencil_state.compare_op = atom2compare_op(compare_atom); - JS_FreeAtom(js, compare_atom); - } - JS_FreeValue(js, compare_val); + JSValue compare_mask_val = JS_GetPropertyStr(js, stencil_val, "compare_mask"); + uint32_t tmp; + JS_ToUint32(js, &tmp, compare_mask_val); + info.depth_stencil_state.compare_mask = tmp; + JS_FreeValue(js, compare_mask_val); - JSValue fail_val = JS_GetPropertyStr(js, back_val, "fail"); - if (!JS_IsUndefined(fail_val)) { - JSAtom fail_atom = JS_ValueToAtom(js, fail_val); - info.depth_stencil_state.back_stencil_state.fail_op = atom2stencil_op(fail_atom); - JS_FreeAtom(js, fail_atom); - } - JS_FreeValue(js, fail_val); - JSValue depth_fail_val = JS_GetPropertyStr(js, back_val, "depth_fail"); - if (!JS_IsUndefined(depth_fail_val)) { - JSAtom depth_fail_atom = JS_ValueToAtom(js, depth_fail_val); - info.depth_stencil_state.back_stencil_state.depth_fail_op = atom2stencil_op(depth_fail_atom); - JS_FreeAtom(js, depth_fail_atom); - } - JS_FreeValue(js, depth_fail_val); - - JSValue pass_val = JS_GetPropertyStr(js, back_val, "pass"); - if (!JS_IsUndefined(pass_val)) { - JSAtom pass_atom = JS_ValueToAtom(js, pass_val); - info.depth_stencil_state.back_stencil_state.pass_op = atom2stencil_op(pass_atom); - JS_FreeAtom(js, pass_atom); - } - JS_FreeValue(js, pass_val); - } - JS_FreeValue(js, back_val); - - // Compare Mask - JSValue compare_mask_val = JS_GetPropertyStr(js, stencil_val, "compare_mask"); - if (!JS_IsUndefined(compare_mask_val)) { - uint32_t tmp; - JS_ToUint32(js, &tmp, compare_mask_val); - info.depth_stencil_state.compare_mask = tmp; - } - JS_FreeValue(js, compare_mask_val); - - // Write Mask - JSValue write_mask_val = JS_GetPropertyStr(js, stencil_val, "write_mask"); - if (!JS_IsUndefined(write_mask_val)) { - uint32_t tmp; - JS_ToUint32(js, &tmp, write_mask_val); - info.depth_stencil_state.write_mask = tmp; - } - JS_FreeValue(js, write_mask_val); + // Write Mask + JSValue write_mask_val = JS_GetPropertyStr(js, stencil_val, "write_mask"); + tmp; + JS_ToUint32(js, &tmp, write_mask_val); + info.depth_stencil_state.write_mask = tmp; } - JS_FreeValue(js, stencil_val); + } + JS_FreeValue(js, stencil_val); - // Blend State - JSValue blend_val = JS_GetPropertyStr(js, pipe, "blend"); - if (JS_IsObject(blend_val)) { - // Enable Blend - JSValue enabled_val = JS_GetPropertyStr(js, blend_val, "enabled"); - if (!JS_IsUndefined(enabled_val)) { - // Depending on SDL_GPU's API, adjust accordingly - // For now, we'll set blend_state fields - // But since target_info is separate, we need to handle it appropriately - // This depends on SDL_GPU's actual structure, which isn't fully detailed here - } - JS_FreeValue(js, enabled_val); + JSValue js_tar = JS_GetPropertyStr(js,pipe,"target"); - // Blend Factors and Operations - JSValue src_factor_rgb_val = JS_GetPropertyStr(js, blend_val, "src_factor_rgb"); - if (!JS_IsUndefined(src_factor_rgb_val)) { - JSAtom src_factor_rgb_atom = JS_ValueToAtom(js, src_factor_rgb_val); - info.target_info.color_target_descriptions = NULL; // Placeholder - // info.blend_state.src_factor_rgb = atom2blend_factor(src_factor_rgb_atom); - // Similarly set other blend factors and operations - // This depends on how SDL_GPU handles blending in target_info - // Since SDL_GPUGraphicsPipelineCreateInfo has target_info, blending might be part of color_target_descriptions - // Adjust accordingly based on SDL_GPU's API - // For demonstration, we'll skip detailed blend state handling here - JS_FreeAtom(js, src_factor_rgb_atom); - } - JS_FreeValue(js, src_factor_rgb_val); + SDL_GPUGraphicsPipelineTargetInfo target_info = {0}; + JSValue color_tars = JS_GetPropertyStr(js,js_tar,"color_targets"); + target_info.num_color_targets = js_arrlen(js,color_tars); + SDL_GPUColorTargetDescription dsc[target_info.num_color_targets]; + target_info.color_target_descriptions = dsc; - // Similarly handle other blend factors and operations - // Skipping detailed implementation due to lack of SDL_GPU specifics - } - JS_FreeValue(js, blend_val); + for (int i = 0; i < target_info.num_color_targets; i++) { + JSValue c = JS_GetPropertyUint32(js,color_tars,i); + dsc[i] = js2SDL_GPUColorTargetDescription(js,c); + JS_FreeValue(js,c); + } + JS_FreeValue(js,color_tars); - // Alpha to Coverage - JSValue atc_val = JS_GetPropertyStr(js, pipe, "alpha_to_coverage"); -// info.multisample_state.sample_mask = 0xFFFFFFFF; // Default -// info.multisample_state.enable_mask = JS_ToBool(js, JS_GetPropertyStr(js, pipe, "multisample.domask")) ? 1 : 0; -// info.multisample_state.sample_count = 1; // Default - // Adjust based on JS object -/* JSValue multisample_val = JS_GetPropertyStr(js, pipe, "multisample"); - if (JS_IsObject(multisample_val)) { - JSValue count_val = JS_GetPropertyStr(js, multisample_val, "count"); - if (!JS_IsUndefined(count_val)) { - JS_ToInt32(js, (int32_t*)&info.multisample_state.sample_count, count_val); - } - JS_FreeValue(js, count_val); + JS_GETPROP(js,target_info.depth_stencil_format,js_tar,depth,SDL_GPUTextureFormat); + if (target_info.depth_stencil_format) target_info.has_depth_stencil_target = 1; - JSValue mask_val = JS_GetPropertyStr(js, multisample_val, "mask"); - if (!JS_IsUndefined(mask_val)) { - JS_ToUint32(js, &info.multisample_state.sample_mask, mask_val); - } - JS_FreeValue(js, mask_val); + info.target_info = target_info; - JSValue domask_val = JS_GetPropertyStr(js, multisample_val, "domask"); - if (!JS_IsUndefined(domask_val)) { - info.multisample_state.enable_mask = JS_ToBool(js, domask_val); - } - JS_FreeValue(js, domask_val); - } - JS_FreeValue(js, multisample_val); -*/ -// info.blend_state.alpha_to_coverage = JS_ToBool(js, atc_val); - JS_FreeValue(js, atc_val); + JS_FreeValue(js, js_tar); - JSValue js_tar = JS_GetPropertyStr(js,pipe,"target"); - const char *tar = JS_ToCString(js,js_tar); - JS_FreeValue(js,js_tar); - if (!strcmp(tar,"post")) - info.target_info = post_info; - else - info.target_info = main_info; - - JS_FreeCString(js,tar); - - // Create the pipeline - SDL_GPUGraphicsPipeline *pipeline = SDL_CreateGPUGraphicsPipeline(gpu, &info); - if (!pipeline) return JS_ThrowInternalError(js, "Failed to create GPU pipeline"); + // Create the pipeline + SDL_GPUGraphicsPipeline *pipeline = SDL_CreateGPUGraphicsPipeline(gpu, &info); + if (!pipeline) return JS_ThrowInternalError(js, "Failed to create GPU pipeline"); return SDL_GPUGraphicsPipeline2js(js, pipeline); } -// Helper conversion functions: -int atom2filter(JSAtom atom) -{ - if (atom == nearest_atom) return SDL_GPU_FILTER_NEAREST; - if (atom == linear_atom) return SDL_GPU_FILTER_LINEAR; - // Default - return SDL_GPU_FILTER_LINEAR; -} - -int atom2mipmap_mode(JSAtom atom) -{ - if (atom == mipmap_nearest_atom) return SDL_GPU_SAMPLERMIPMAPMODE_NEAREST; - if (atom == mipmap_linear_atom) return SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; - return SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; -} - -int atom2address_mode(JSAtom atom) -{ - if (atom == repeat_atom) return SDL_GPU_SAMPLERADDRESSMODE_REPEAT; - if (atom == mirror_atom) return SDL_GPU_SAMPLERADDRESSMODE_MIRRORED_REPEAT; - if (atom == clamp_edge_atom) return SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; - return SDL_GPU_SAMPLERADDRESSMODE_REPEAT; // Default -} - // Now the function to create the sampler static JSValue js_gpu_make_sampler(JSContext *js, JSValueConst self, int argc, JSValueConst *argv) { - // We need at least 1 argument: the sampler description object - if (argc < 1) - return JS_ThrowTypeError(js, "gpu_sampler requires a sampler object"); + SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); + SDL_GPUSamplerCreateInfo info = {0}; + JSValue sampler = argv[0]; + + JS_GETPROP(js,info.min_filter,sampler,min_filter,SDL_GPUFilter) + JS_GETPROP(js,info.mag_filter,sampler,mag_filter,SDL_GPUFilter) + JS_GETPROP(js,info.mipmap_mode, sampler, mipmap, SDL_GPUSamplerMipmapMode) + JS_GETPROP(js,info.address_mode_u, sampler, u, SDL_GPUSamplerAddressMode) + JS_GETPROP(js,info.address_mode_v, sampler, v, SDL_GPUSamplerAddressMode) + JS_GETPROP(js,info.address_mode_w, sampler, w, SDL_GPUSamplerAddressMode) + JS_GETPROP(js,info.mip_lod_bias, sampler, mip_bias, number) + JS_GETPROP(js,info.max_anisotropy, sampler, max_anisotropy, number) + JS_GETPROP(js,info.compare_op,sampler,compare_op,SDL_GPUCompareOp) + JS_GETPROP(js,info.min_lod,sampler,min_lod,number) + JS_GETPROP(js,info.max_lod,sampler,max_lod,number) + JS_GETPROP(js, info.enable_anisotropy, sampler, anistropy, bool) + JS_GETPROP(js, info.enable_compare, sampler, compare, bool) + + // Create the sampler + SDL_GPUSampler *sdl_sampler = SDL_CreateGPUSampler(gpu, &info); + if (!sdl_sampler) return JS_ThrowInternalError(js, "Failed to create GPU sampler"); - JSValue sampler_obj = argv[0]; - if (!JS_IsObject(sampler_obj)) - return JS_ThrowTypeError(js, "gpu_sampler argument must be an object"); - - SDL_GPUDevice *device = js2SDL_GPUDevice(js, self); - if (!device) - return JS_ThrowInternalError(js, "Invalid GPU device"); - - SDL_GPUSamplerCreateInfo info; - SDL_memset(&info, 0, sizeof(info)); - - // Get min_filter - JSValue min_val = JS_GetPropertyStr(js, sampler_obj, "min_filter"); - if (!JS_IsUndefined(min_val)) { - JSAtom min_atom = JS_ValueToAtom(js, min_val); - info.min_filter = atom2filter(min_atom); - JS_FreeAtom(js, min_atom); - } else { - info.min_filter = SDL_GPU_FILTER_LINEAR; // default - } - JS_FreeValue(js, min_val); - - // Get mag_filter - JSValue mag_val = JS_GetPropertyStr(js, sampler_obj, "mag_filter"); - if (!JS_IsUndefined(mag_val)) { - JSAtom mag_atom = JS_ValueToAtom(js, mag_val); - info.mag_filter = atom2filter(mag_atom); - JS_FreeAtom(js, mag_atom); - } else { - info.mag_filter = SDL_GPU_FILTER_LINEAR; // default - } - JS_FreeValue(js, mag_val); - - // mipmap_mode - JSValue mipmap_val = JS_GetPropertyStr(js, sampler_obj, "mipmap_mode"); - if (!JS_IsUndefined(mipmap_val)) { - JSAtom mipmap_atom = JS_ValueToAtom(js, mipmap_val); - info.mipmap_mode = atom2mipmap_mode(mipmap_atom); - JS_FreeAtom(js, mipmap_atom); - } else { - info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; // default - } - JS_FreeValue(js, mipmap_val); - - // address_mode_u - JSValue address_u_val = JS_GetPropertyStr(js, sampler_obj, "address_mode_u"); - if (!JS_IsUndefined(address_u_val)) { - JSAtom address_u_atom = JS_ValueToAtom(js, address_u_val); - info.address_mode_u = atom2address_mode(address_u_atom); - JS_FreeAtom(js, address_u_atom); - } else { - info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; // default - } - JS_FreeValue(js, address_u_val); - - // address_mode_v - JSValue address_v_val = JS_GetPropertyStr(js, sampler_obj, "address_mode_v"); - if (!JS_IsUndefined(address_v_val)) { - JSAtom address_v_atom = JS_ValueToAtom(js, address_v_val); - info.address_mode_v = atom2address_mode(address_v_atom); - JS_FreeAtom(js, address_v_atom); - } else { - info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; // default - } - JS_FreeValue(js, address_v_val); - - // address_mode_w - JSValue address_w_val = JS_GetPropertyStr(js, sampler_obj, "address_mode_w"); - if (!JS_IsUndefined(address_w_val)) { - JSAtom address_w_atom = JS_ValueToAtom(js, address_w_val); - info.address_mode_w = atom2address_mode(address_w_atom); - JS_FreeAtom(js, address_w_atom); - } else { - info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT; // default - } - JS_FreeValue(js, address_w_val); - - // mip_lod_bias - JSValue mip_lod_bias_val = JS_GetPropertyStr(js, sampler_obj, "mip_lod_bias"); - if (!JS_IsUndefined(mip_lod_bias_val)) { - JS_ToFloat64(js, &info.mip_lod_bias, mip_lod_bias_val); - } else { - info.mip_lod_bias = 0.0f; // default - } - JS_FreeValue(js, mip_lod_bias_val); - - // max_anisotropy - JSValue max_anisotropy_val = JS_GetPropertyStr(js, sampler_obj, "max_anisotropy"); - if (!JS_IsUndefined(max_anisotropy_val)) { - JS_ToFloat64(js, &info.max_anisotropy, max_anisotropy_val); - } else { - info.max_anisotropy = 1.0f; // default - } - JS_FreeValue(js, max_anisotropy_val); - - // compare_op - JSValue compare_op_val = JS_GetPropertyStr(js, sampler_obj, "compare_op"); - if (!JS_IsUndefined(compare_op_val)) { - JSAtom compare_op_atom = JS_ValueToAtom(js, compare_op_val); - info.compare_op = atom2compare_op(compare_op_atom); - JS_FreeAtom(js, compare_op_atom); - } else { - info.compare_op = SDL_GPU_COMPAREOP_ALWAYS; // default - } - JS_FreeValue(js, compare_op_val); - - // min_lod - JSValue min_lod_val = JS_GetPropertyStr(js, sampler_obj, "min_lod"); - if (!JS_IsUndefined(min_lod_val)) { - JS_ToFloat64(js, &info.min_lod, min_lod_val); - } else { - info.min_lod = 0.0f; // default - } - JS_FreeValue(js, min_lod_val); - - // max_lod - JSValue max_lod_val = JS_GetPropertyStr(js, sampler_obj, "max_lod"); - if (!JS_IsUndefined(max_lod_val)) { - JS_ToFloat64(js, &info.max_lod, max_lod_val); - } else { - info.max_lod = 1000.0f; // arbitrary large number as default - } - JS_FreeValue(js, max_lod_val); - - // enable_anisotropy - JSValue enable_anisotropy_val = JS_GetPropertyStr(js, sampler_obj, "enable_anisotropy"); - if (!JS_IsUndefined(enable_anisotropy_val)) { - info.enable_anisotropy = JS_ToBool(js, enable_anisotropy_val); - } else { - info.enable_anisotropy = false; // default - } - JS_FreeValue(js, enable_anisotropy_val); - - // enable_compare - JSValue enable_compare_val = JS_GetPropertyStr(js, sampler_obj, "enable_compare"); - if (!JS_IsUndefined(enable_compare_val)) { - info.enable_compare = JS_ToBool(js, enable_compare_val); - } else { - info.enable_compare = false; // default - } - JS_FreeValue(js, enable_compare_val); - - // props (extensions) - // If you don't need extensions, set to 0. Otherwise retrieve from JS. - info.props = 0; - - // Create the sampler - SDL_GPUSampler *sampler = SDL_CreateGPUSampler(device, &info); - if (!sampler) { - return JS_ThrowInternalError(js, "Failed to create GPU sampler"); - } - - // Convert sampler pointer to JS object or handle as needed - return SDL_GPUSampler2js(js, sampler); // You need to implement SDL_GPUSampler2js similar to pipeline + return SDL_GPUSampler2js(js, sdl_sampler); // You need to implement SDL_GPUSampler2js similar to pipeline } -JSC_CCALL(gpu_scale, - -) - -/* -JSC_CCALL(gpu_geometry, - SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); - SDL_GPUTexture *tex = js2SDL_GPUTexture(js, argv[0]); - - // Extract geometry data from the JS object in argv[1] - JSValue geom_obj = argv[1]; - JSValue pos_val = JS_GetPropertyStr(js, geom_obj, "pos"); - JSValue color_val = JS_GetPropertyStr(js, geom_obj, "color"); - JSValue uv_val = JS_GetPropertyStr(js, geom_obj, "uv"); - JSValue indices_val = JS_GetPropertyStr(js, geom_obj, "indices"); - - int vertices = js_getnum_str(js, geom_obj, "vertices"); - int count = js_getnum_str(js, geom_obj, "count"); - - size_t pos_stride, color_stride, uv_stride, indices_stride; - void *posdata = get_gpu_buffer(js, pos_val, &pos_stride, NULL); - void *colordata = get_gpu_buffer(js, color_val, &color_stride, NULL); - void *uvdata = get_gpu_buffer(js, uv_val, &uv_stride, NULL); - void *idxdata = get_gpu_buffer(js, indices_val, &indices_stride, NULL); - - // Transform positions by camera matrix - // Assuming posdata is an array of HMM_Vec2 or {float x, float y} - HMM_Vec2 *trans_pos = malloc(vertices * sizeof(HMM_Vec2)); - memcpy(trans_pos, posdata, sizeof(HMM_Vec2)*vertices); - - for (int i = 0; i < vertices; i++) { - HMM_Vec3 p3 = {trans_pos[i].X, trans_pos[i].Y, 1.0f}; - HMM_Vec3 tp = HMM_MulM3V3(cam_mat, p3); - trans_pos[i].X = tp.X; - trans_pos[i].Y = tp.Y; - } - - // We'll read each vertex's data and push into global_verts as texture_vertex. - // Assume: - // - posdata: HMM_Vec2 per vertex - // - uvdata: HMM_Vec2 per vertex - // - colordata: float[4] per vertex (r,g,b,a) - // Adjust indexing according to strides if needed. For simplicity, assume contiguous arrays. - unsigned char *pPos = (unsigned char *)posdata; - unsigned char *pUV = (unsigned char *)uvdata; - unsigned char *pColor = (unsigned char *)colordata; - - // z coordinate (for 2D rendering, just 0) - float z = 0.0f; - - for (int i = 0; i < vertices; i++) { - // Position - float px = trans_pos[i].X; - float py = trans_pos[i].Y; - - // UV - HMM_Vec2 *uv_ptr = (HMM_Vec2*)(pUV + i * uv_stride); - float u = uv_ptr->X; - float v = uv_ptr->Y; - - // Color - float *c_ptr = (float *)(pColor + i * color_stride); - uint8_t r = (uint8_t)(c_ptr[0] * 255.0f); - uint8_t g = (uint8_t)(c_ptr[1] * 255.0f); - uint8_t b = (uint8_t)(c_ptr[2] * 255.0f); - uint8_t a = (uint8_t)(c_ptr[3] * 255.0f); - - texture_vertex vert = { - px, py, z, - u, v, - r, g, b, a - }; - - arrput(global_verts, vert); - } - - // Now handle indices - // Indices might be Uint16 or Uint32, check indices_stride or known format - // Suppose they are Uint16 - Uint16 *idx_ptr = (Uint16 *)idxdata; - - for (int i = 0; i < count; i++) { - // Adjust index by base_vert - arrput(global_indices, idx_ptr[i]); - } - - free(trans_pos); - - // Clean up JS values - JS_FreeValue(js, pos_val); - JS_FreeValue(js, color_val); - JS_FreeValue(js, uv_val); - JS_FreeValue(js, indices_val); -) -*/ JSC_CCALL(gpu_texture, -/* SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); - SDL_GPUTexture *tex = js2SDL_GPUTexture(js, argv[0]); + SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self); + SDL_GPUTextureCreateInfo info = {0}; + JSValue fmt = argv[0]; + JS_GETPROP(js, info.width, fmt, width, number) + JS_GETPROP(js, info.height, fmt, height, number) + JS_GETPROP(js, info.layer_count_or_depth, fmt, layers, number) + JS_GETPROP(js, info.num_levels, fmt, mip_levels, number) + JS_GETPROP(js, info.sample_count, fmt, samples, number) + JS_GETPROP(js, info.type, fmt, type, SDL_GPUTextureType) + JS_GETPROP(js, info.format, fmt, format, SDL_GPUTextureFormat) + if (JS_GETBOOL(js,fmt,"sampler")) + info.usage |= SDL_GPU_TEXTUREUSAGE_SAMPLER; + if (JS_GETBOOL(js,fmt,"color_target")) + info.usage |= SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; + if (JS_GETBOOL(js,fmt,"depth_target")) + info.usage |= SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; + if (JS_GETBOOL(js,fmt,"read")) + info.usage |= (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ); + if (JS_GETBOOL(js,fmt,"write")) + info.usage |= SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE; + if (JS_GETBOOL(js,fmt,"readwrite")) + info.usage |= SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE; - rect dst = js2rect(js,argv[1]); - - // Determine the coloring - uint8_t r = 255, g = 255, b = 255, a = 255; - if (!JS_IsUndefined(argv[3])) { - colorf color = js2color(js,argv[3]); - r = (uint8_t)(color.r * 255.0f); - g = (uint8_t)(color.g * 255.0f); - b = (uint8_t)(color.b * 255.0f); - a = (uint8_t)(color.a * 255.0f); - } - - // If source rect is provided, compute normalized UVs, else use full texture - float src_x = 0.0f; - float src_y = 0.0f; - float src_w = 1.0; - float src_h = 1.0; - - if (!JS_IsUndefined(argv[2])) { - rect src = js2rect(js, argv[2]); - src_x = (float)src.x; - src_y = (float)src.y; - src_w = (float)src.w; - src_h = (float)src.h; - } - - float u0 = src_x; - float v1 = src_y; - float u1 = (src_x + src_w); - float v0 = (src_y + src_h); - - // Set z = 0 for 2D rendering - float z = 0.0f; - - texture_vertex verts[4]; - - verts[0] = (texture_vertex){ (float)dst.x, (float)dst.y, z, u0, v0, r,g,b,a }; - verts[1] = (texture_vertex){ (float)(dst.x+dst.w), (float)dst.y, z, u1, v0, r,g,b,a }; - verts[2] = (texture_vertex){ (float)(dst.x+dst.w), (float)(dst.y+dst.h), z, u1, v1, r,g,b,a }; - verts[3] = (texture_vertex){ (float)dst.x, (float)(dst.y+dst.h), z, u0, v1, r,g,b,a }; - - size_t base_vert = arrlen(global_verts); - for (int i = 0; i < 4; i++) - arrput(global_verts,verts[i]); - - Uint16 indices[6] = {0, 1, 2, 2, 3, 0}; - for (int i = 0; i < 6; i++) - arrput(global_indices, indices[i]);*/ -) - -JSC_CCALL(gpu_viewport, - + SDL_GPUTexture *tex = SDL_CreateGPUTexture(gpu,&info); + if (!tex) return JS_ThrowReferenceError("Unable to create texture: %s", SDL_GetError()); + JSValue jstex = SDL_GPUTexture2js(js,tex); + JS_SetPropertyStr(js,jstex,"width", number2js(js,info.width)); + JS_SetPropertyStr(js,jstex,"height", number2js(js,info.height)); + return jstex; ) static HMM_Vec3 base_quad[4] = { @@ -4211,24 +4125,12 @@ static JSValue js_gpu_make_shader(JSContext *js, JSValueConst self, int argc, JS // format JSValue format_val = JS_GetPropertyStr(js, obj, "format"); - const char *format_str = JS_ToCString(js, format_val); - SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_SPIRV; // default to SPIR-V - if (format_str) { - if (!strcmp(format_str, "private")) format = SDL_GPU_SHADERFORMAT_PRIVATE; - else if (!strcmp(format_str, "spv")) format = SDL_GPU_SHADERFORMAT_SPIRV; - else if (!strcmp(format_str, "dxbc")) format = SDL_GPU_SHADERFORMAT_DXBC; - else if (!strcmp(format_str, "dxil")) format = SDL_GPU_SHADERFORMAT_DXIL; - else if (!strcmp(format_str, "msl")) format = SDL_GPU_SHADERFORMAT_MSL; - else if (!strcmp(format_str, "metallib")) format = SDL_GPU_SHADERFORMAT_METALLIB; - JS_FreeCString(js, format_str); - } + SDL_GPUShaderFormat format = js2SDL_GPUShaderFormat(js,format_val); JS_FreeValue(js, format_val); JSValue entry_val = JS_GetPropertyStr(js,obj,"entrypoint"); const char *entry = JS_ToCString(js,entry_val); JS_FreeValue(js,entry_val); - - printf("format str is %s; format value is %d\n", format_str, format); SDL_GPUShaderCreateInfo info = {0}; info.code_size = code_size; @@ -4259,18 +4161,6 @@ JSC_CCALL(gpu_acquire_cmd_buffer, return SDL_GPUCommandBuffer2js(js, cb); ) -static Uint32 atom2usage(JSContext *js, JSAtom atom) { - if (atom == vertex_atom) { - return SDL_GPU_BUFFERUSAGE_VERTEX; - } else if (atom == index_atom) { - return SDL_GPU_BUFFERUSAGE_INDEX; - } else if (atom == indirect_atom) { - return SDL_GPU_BUFFERUSAGE_INDIRECT; - } - // Default fallback if unrecognized - return SDL_GPU_BUFFERUSAGE_VERTEX; -} - /* takes argv 0: a command buffer to write to 1: a buffer or array of buffers to upload @@ -4428,22 +4318,19 @@ JSC_CCALL(gpu_shader_format, static const JSCFunctionListEntry js_SDL_GPUDevice_funcs[] = { MIST_FUNC_DEF(gpu, claim_window, 1), MIST_FUNC_DEF(gpu, make_pipeline, 1), // loads pipeline state into an object + MIST_FUNC_DEF(gpu, set_swapchain, 2), MIST_FUNC_DEF(gpu, make_sampler,1), MIST_FUNC_DEF(gpu, set_pipeline, 1), // grabs the gpu property off a pipeline value to load MIST_FUNC_DEF(gpu, load_texture, 2), MIST_FUNC_DEF(gpu, logical_size, 1), - MIST_FUNC_DEF(gpu, scale, 1), - MIST_FUNC_DEF(gpu, texture, 4), + MIST_FUNC_DEF(gpu, texture, 1), // MIST_FUNC_DEF(gpu, geometry, 2), - MIST_FUNC_DEF(gpu, viewport, 1), MIST_FUNC_DEF(gpu, make_sprite_mesh, 2), MIST_FUNC_DEF(gpu, make_quad, 0), MIST_FUNC_DEF(gpu, driver, 0), MIST_FUNC_DEF(gpu, make_shader, 1), - MIST_FUNC_DEF(gpu, load_gltf_model, 1), MIST_FUNC_DEF(gpu, acquire_cmd_buffer, 0), MIST_FUNC_DEF(gpu, upload, 3), - MIST_FUNC_DEF(gpu, mainRT, 1), MIST_FUNC_DEF(gpu, wait_for_fences, 2), MIST_FUNC_DEF(gpu, query_fence, 1), MIST_FUNC_DEF(gpu, shader_format, 0), @@ -4451,11 +4338,8 @@ static const JSCFunctionListEntry js_SDL_GPUDevice_funcs[] = { JSC_CCALL(renderpass_bind_pipeline, SDL_GPURenderPass *r = js2SDL_GPURenderPass(js,self); - JSValue pipe_gpu = JS_GetPropertyStr(js,argv[0],"gpu"); - SDL_GPUGraphicsPipeline *pipe = js2SDL_GPUGraphicsPipeline(js,pipe_gpu); - JS_FreeValue(js,pipe_gpu); + SDL_GPUGraphicsPipeline *pipe = js2SDL_GPUGraphicsPipeline(js,argv[0]); SDL_BindGPUGraphicsPipeline(r,pipe); - JS_SetPropertyStr(js,self, "pipeline", JS_DupValue(js,argv[0])); ) JSC_CCALL(renderpass_draw_indexed, @@ -4548,61 +4432,12 @@ JSC_CCALL(copypass_end, SDL_EndGPUCopyPass(pass); ) -float gw, gh; - -static SDL_GPULoadOp js2load_op(JSContext *ctx, JSValue val) { - if (!JS_IsString(val)) - return SDL_GPU_LOADOP_LOAD; // or handle as error / default - - const char *str = JS_ToCString(ctx, val); - if (!str) - return SDL_GPU_LOADOP_LOAD; // or handle error / default - - SDL_GPULoadOp op; - if (strcmp(str, "load") == 0) op = SDL_GPU_LOADOP_LOAD; - else if (strcmp(str, "clear") == 0) op = SDL_GPU_LOADOP_CLEAR; - else if (strcmp(str, "dont_care") == 0) op = SDL_GPU_LOADOP_DONT_CARE; - else { - // Either throw an error or pick a fallback - // return JS_ThrowTypeError(ctx, "invalid load_op string"); - op = SDL_GPU_LOADOP_LOAD; // fallback - } - - JS_FreeCString(ctx, str); - return op; -} - -static SDL_GPUStoreOp js2store_op(JSContext *ctx, JSValue val) { - if (!JS_IsString(val)) - return SDL_GPU_STOREOP_STORE; // or handle as error / default - - const char *str = JS_ToCString(ctx, val); - if (!str) - return SDL_GPU_STOREOP_STORE; // or handle error / default - - SDL_GPUStoreOp op; - if (strcmp(str, "store") == 0) op = SDL_GPU_STOREOP_STORE; - else if (strcmp(str, "dont_care") == 0) op = SDL_GPU_STOREOP_DONT_CARE; - else if (strcmp(str, "resolve") == 0) op = SDL_GPU_STOREOP_RESOLVE; - else if (strcmp(str, "resolve_and_store") == 0) op = SDL_GPU_STOREOP_RESOLVE_AND_STORE; - else { - // Either throw an error or pick a fallback - // return JS_ThrowTypeError(ctx, "invalid store_op string"); - op = SDL_GPU_STOREOP_STORE; // fallback - } - - JS_FreeCString(ctx, str); - return op; -} - JSC_CCALL(cmd_render_pass, SDL_GPUCommandBuffer *cmds = js2SDL_GPUCommandBuffer(js, self); if (!JS_IsObject(argv[0])) return JS_ThrowTypeError(js, "render_pass: Expected a render pass descriptor object"); JSValue passObj = argv[0]; - colorf clear_color = js2color(js,argv[1]); - // Get colorTargets array JSValue colorTargetsVal = JS_GetPropertyStr(js, passObj, "color_targets"); if (!JS_IsArray(js, colorTargetsVal)) return JS_ThrowTypeError(js, "render_pass: colorTargets must be an array"); @@ -4615,14 +4450,7 @@ JSC_CCALL(cmd_render_pass, // Fill colorInfos from JS array for (uint32_t i = 0; i < colorCount; i++) { JSValue ctargetVal = JS_GetPropertyUint32(js, colorTargetsVal, i); - JS_GETPROPSTR(js, ctargetVal, colortars[i], mip_level, number) - JS_GETPROPSTR(js, ctargetVal, colortars[i], layer_or_depth_plane, number) - JS_GETPROPSTR(js, ctargetVal, colortars[i], load_op, load_op) - JS_GETPROPSTR(js, ctargetVal, colortars[i], store_op, store_op) -// JS_GETPROPSTR(js, ctargetVal, colortars[i], clear_color, color) - colortars[i].clear_color = (SDL_FColor){clear_color.r,clear_color.g,clear_color.b,clear_color.a}; - JS_GETPROPSTR(js, ctargetVal, colortars[i], texture, SDL_GPUTexture) - // If you support resolve textures or other fields, retrieve them here. + colortars[i] = js2SDL_GPUColorTargetInfo(js,ctargetVal); JS_FreeValue(js, ctargetVal); } @@ -4630,32 +4458,27 @@ JSC_CCALL(cmd_render_pass, JSValue depthval = JS_GetPropertyStr(js, passObj, "depth_stencil"); if (!JS_IsUndefined(depthval)) { has_depth = 1; - // Fill out depthtar[0] fields from the JS descriptor JS_GETPROPSTR(js, depthval, depthtar, texture, SDL_GPUTexture) - JS_GETPROPSTR(js, depthval, depthtar, clear_depth, number) - JS_GETPROPSTR(js, depthval, depthtar, load_op, load_op) - JS_GETPROPSTR(js, depthval, depthtar, store_op, store_op) - JS_GETPROPSTR(js, depthval, depthtar, stencil_load_op, load_op) - JS_GETPROPSTR(js, depthval, depthtar, stencil_store_op, store_op) - JS_GETPROPSTR(js, depthval, depthtar, clear_stencil, number) - // If you support 'cycle' or other booleans, retrieve them here. + JS_GETPROP(js, depthtar.load_op, depthval, load, SDL_GPULoadOp) + JS_GETPROP(js, depthtar.store_op, depthval, store, SDL_GPUStoreOp) + JS_GETPROP(js, depthtar.stencil_load_op, depthval, stencil_load, SDL_GPULoadOp) + JS_GETPROP(js, depthtar.stencil_store_op, depthval, stencil_store, SDL_GPUStoreOp) + JS_GETPROP(js,depthtar.clear_depth, depthval, clear, number) + JS_GETPROP(js,depthtar.clear_stencil,depthval,clear_stencil,number) } JS_FreeValue(js, depthval); - // Begin the render pass with multiple color attachments + optional depth SDL_GPURenderPass *pass = SDL_BeginGPURenderPass( cmds, colortars, colorCount, has_depth ? &depthtar : NULL ); + + JS_FreeValue(js, colorTargetsVal); - if (!pass) { - JS_FreeValue(js, colorTargetsVal); - return JS_ThrowInternalError(js, "render_pass: Failed to begin render pass"); - } + if (!pass) return JS_ThrowInternalError(js, "render_pass: Failed to begin render pass"); - JS_FreeValue(js, colorTargetsVal); return SDL_GPURenderPass2js(js, pass); ) @@ -4859,9 +4682,59 @@ JSC_SCALL(cmd_debug_label, SDL_InsertGPUDebugLabel(cmd, str); ) +SDL_GPUBlitRegion js2SDL_GPUBlitRegion(JSContext *js, JSValue v) +{ + SDL_GPUBlitRegion info = {0}; + if (JS_GetClassID(v) == js_SDL_GPUTexture_id) { + // texture path + JSValue tex = v; + info.texture = js2SDL_GPUTexture(js,tex); + info.mip_level = 0, + info.layer_or_depth_plane = 0; + info.x = 0; + info.y = 0; + JS_GETPROP(js,info.w,tex,width,number) + JS_GETPROP(js,info.h,tex,height,number) + return info; + } + JSValue tex = JS_GetPropertyStr(js, v, "texture"); + info.texture = js2SDL_GPUTexture(js,tex); + JS_GETPROP(js,info.mip_level,v,mip_level, number) + JS_GETPROP(js,info.mip_level,v,layer,number) + JS_GETPROP(js,info.x,v,x,number) + JS_GETPROP(js,info.y,v,y,number) + JS_GETPROP(js,info.w,v,width,number) + JS_GETPROP(js,info.h,v,height,number) + + if (!info.w) JS_GETPROP(js,info.w,tex,width,number) + if (!info.h) JS_GETPROP(js,info.h,tex,height,number) + + JS_FreeValue(js,tex); + return info; +} + +JSC_CCALL(cmd_blit, + SDL_GPUCommandBuffer *cmd = js2SDL_GPUCommandBuffer(js,self); + SDL_GPUBlitInfo info = {0}; + JSValue v = argv[0]; + JS_GETPROP(js,info.source,v,src,SDL_GPUBlitRegion) + JS_GETPROP(js,info.destination,v,dst,SDL_GPUBlitRegion) + JS_GETPROP(js,info.load_op,v,load,SDL_GPULoadOp) + JS_GETPROP(js,info.flip_mode,v,flip,SDL_FlipMode) + JS_GETPROP(js,info.filter,v,filter,SDL_GPUFilter) + JS_GETPROP(js,info.clear_color,v,color,SDL_FColor) + SDL_BlitGPUTexture(cmd,&info); +) + +JSC_CCALL(cmd_cancel, + SDL_GPUCommandBuffer *cmd = js2SDL_GPUCommandBuffer(js,self); + SDL_CancelGPUCommandBuffer(cmd); +) + static const JSCFunctionListEntry js_SDL_GPUCommandBuffer_funcs[] = { - MIST_FUNC_DEF(cmd, render_pass, 2), + MIST_FUNC_DEF(cmd, render_pass, 1), MIST_FUNC_DEF(cmd, swapchain_pass, 1), + MIST_FUNC_DEF(cmd, acquire_swapchain,0), MIST_FUNC_DEF(cmd, bind_vertex_buffer, 2), MIST_FUNC_DEF(cmd, bind_index_buffer, 1), MIST_FUNC_DEF(cmd, bind_fragment_sampler, 3), @@ -4869,10 +4742,12 @@ static const JSCFunctionListEntry js_SDL_GPUCommandBuffer_funcs[] = { MIST_FUNC_DEF(cmd, push_fragment_uniform_data, 2), MIST_FUNC_DEF(cmd, push_compute_uniform_data, 2), MIST_FUNC_DEF(cmd, submit, 0), + MIST_FUNC_DEF(cmd, cancel, 0), MIST_FUNC_DEF(cmd, camera, 4), MIST_FUNC_DEF(cmd, push_debug_group, 1), MIST_FUNC_DEF(cmd, pop_debug_group, 0), MIST_FUNC_DEF(cmd, debug_label, 1), + MIST_FUNC_DEF(cmd, blit, 1), }; JSC_CCALL(surface_blit, @@ -5002,12 +4877,7 @@ static const JSCFunctionListEntry js_SDL_Texture_funcs[] = { MIST_FUNC_DEF(texture, mode, 1), }; -JSC_CCALL(gputexture_mode, - -) - static const JSCFunctionListEntry js_SDL_GPUTexture_funcs[] = { - MIST_FUNC_DEF(gputexture, mode, 1), }; JSC_CCALL(input_mouse_lock, SDL_CaptureMouse(JS_ToBool(js,argv[0])))