function shader_data_create(raw: shader_data_t): shader_data_t { raw._ = {}; raw._.contexts = []; for (let i: i32 = 0; i < raw.contexts.length; ++i) { let c: shader_context_t = raw.contexts[i]; let con: shader_context_t = shader_context_create(c); array_push(raw._.contexts, con); } return raw; } function shader_data_ext(): string { ///if arm_vulkan return ".spirv"; ///elseif arm_metal return ".metal"; ///else return ".d3d11"; ///end } function shader_data_parse(file: string, name: string): shader_data_t { let format: scene_t = data_get_scene_raw(file); let raw: shader_data_t = shader_data_get_raw_by_name(format.shader_datas, name); if (raw == null) { iron_log("Shader data '" + name + "' not found!"); return null; } return shader_data_create(raw); } function shader_data_get_raw_by_name(datas: shader_data_t[], name: string): shader_data_t { if (name == "") { return datas[0]; } for (let i: i32 = 0; i < datas.length; ++i) { if (datas[i].name == name) { return datas[i]; } } return null; } function shader_data_delete(raw: shader_data_t) { for (let i: i32 = 0; i < raw._.contexts.length; ++i) { let c: shader_context_t = raw._.contexts[i]; shader_context_delete(c); } } function shader_data_get_context(raw: shader_data_t, name: string): shader_context_t { for (let i: i32 = 0; i < raw._.contexts.length; ++i) { let c: shader_context_t = raw._.contexts[i]; if (c.name == name) { return c; } } return null; } function shader_context_create(raw: shader_context_t): shader_context_t { raw._ = {}; shader_context_parse_vertex_struct(raw); return shader_context_compile(raw); } function shader_context_compile(raw: shader_context_t): shader_context_t { if (raw._.pipe_state != null) { gpu_delete_pipeline(raw._.pipe_state); } raw._.pipe_state = gpu_create_pipeline(); raw._.constants = []; raw._.tex_units = []; raw._.pipe_state.input_layout = raw._.structure; // Depth raw._.pipe_state.depth_write = raw.depth_write; raw._.pipe_state.depth_mode = shader_context_get_compare_mode(raw.compare_mode); // Cull raw._.pipe_state.cull_mode = shader_context_get_cull_mode(raw.cull_mode); // Blending if (raw.blend_source != null) { raw._.pipe_state.blend_source = shader_context_get_blend_fac(raw.blend_source); } if (raw.blend_destination != null) { raw._.pipe_state.blend_destination = shader_context_get_blend_fac(raw.blend_destination); } if (raw.alpha_blend_source != null) { raw._.pipe_state.alpha_blend_source = shader_context_get_blend_fac(raw.alpha_blend_source); } if (raw.alpha_blend_destination != null) { raw._.pipe_state.alpha_blend_destination = shader_context_get_blend_fac(raw.alpha_blend_destination); } // Per-target color write mask if (raw.color_writes_red != null) { for (let i: i32 = 0; i < raw.color_writes_red.length; ++i) { ARRAY_ACCESS(raw._.pipe_state.color_write_mask_red, i) = raw.color_writes_red[i]; } } if (raw.color_writes_green != null) { for (let i: i32 = 0; i < raw.color_writes_green.length; ++i) { ARRAY_ACCESS(raw._.pipe_state.color_write_mask_green, i) = raw.color_writes_green[i]; } } if (raw.color_writes_blue != null) { for (let i: i32 = 0; i < raw.color_writes_blue.length; ++i) { ARRAY_ACCESS(raw._.pipe_state.color_write_mask_blue, i) = raw.color_writes_blue[i]; } } if (raw.color_writes_alpha != null) { for (let i: i32 = 0; i < raw.color_writes_alpha.length; ++i) { ARRAY_ACCESS(raw._.pipe_state.color_write_mask_alpha, i) = raw.color_writes_alpha[i]; } } // Color attachment format if (raw.color_attachments != null) { raw._.pipe_state.color_attachment_count = raw.color_attachments.length; for (let i: i32 = 0; i < raw.color_attachments.length; ++i) { ARRAY_ACCESS(raw._.pipe_state.color_attachment, i) = shader_context_get_tex_format(raw.color_attachments[i]); } } // Depth attachment format if (raw.depth_attachment != null) { raw._.pipe_state.depth_attachment_bits = raw.depth_attachment == "NONE" ? 0 : 24; } // Shaders if (raw.shader_from_source) { raw._.pipe_state.vertex_shader = gpu_create_shader_from_source(raw.vertex_shader, shader_type_t.VERTEX); raw._.pipe_state.fragment_shader = gpu_create_shader_from_source(raw.fragment_shader, shader_type_t.FRAGMENT); // Shader compile error if (raw._.pipe_state.vertex_shader == null || raw._.pipe_state.fragment_shader == null) { return null; } } else { ///if arm_embed raw._.pipe_state.fragment_shader = sys_get_shader(raw.fragment_shader); raw._.pipe_state.vertex_shader = sys_get_shader(raw.vertex_shader); ///else // Load shaders manually let vs_buffer: buffer_t = data_get_blob(raw.vertex_shader + shader_data_ext()); raw._.pipe_state.vertex_shader = gpu_create_shader(vs_buffer, shader_type_t.VERTEX); let fs_buffer: buffer_t = data_get_blob(raw.fragment_shader + shader_data_ext()); raw._.pipe_state.fragment_shader = gpu_create_shader(fs_buffer, shader_type_t.FRAGMENT); ///end } return shader_context_finish_compile(raw); } function shader_context_type_size(t: string): i32 { if (t == "int") return 4; if (t == "float") return 4; if (t == "vec2") return 8; if (t == "vec3") return 12; if (t == "vec4") return 16; if (t == "mat3") return 48; if (t == "mat4") return 64; } function shader_context_type_pad(offset: i32, size: i32): i32 { let r: i32 = offset % 16; if (r == 0) { return 0; } if (size >= 16 || r + size > 16) { return 16 - r; } return 0; } function shader_context_finish_compile(raw: shader_context_t): shader_context_t { gpu_compile_pipeline(raw._.pipe_state); if (raw.constants != null) { let offset: i32 = 0; for (let i: i32 = 0; i < raw.constants.length; ++i) { let c: shader_const_t = raw.constants[i]; let size: i32 = shader_context_type_size(c.type); offset += shader_context_type_pad(offset, size); shader_context_add_const(raw, c, offset); offset += size; } } if (raw.texture_units != null) { for (let i: i32 = 0; i < raw.texture_units.length; ++i) { let tu: tex_unit_t = raw.texture_units[i]; shader_context_add_tex(raw, tu, i); } } return raw; } function shader_context_parse_data(data: string): vertex_data_t { if (data == "float1") { return vertex_data_t.F32_1X; } else if (data == "float2") { return vertex_data_t.F32_2X; } else if (data == "float3") { return vertex_data_t.F32_3X; } else if (data == "float4") { return vertex_data_t.F32_4X; } else if (data == "short2norm") { return vertex_data_t.I16_2X_NORM; } else if (data == "short4norm") { return vertex_data_t.I16_4X_NORM; } return vertex_data_t.F32_1X; } function shader_context_parse_vertex_struct(raw: shader_context_t) { raw._.structure = gpu_vertex_struct_create(); for (let i: i32 = 0; i < raw.vertex_elements.length; ++i) { let elem: vertex_element_t = raw.vertex_elements[i]; gpu_vertex_struct_add(raw._.structure, elem.name, shader_context_parse_data(elem.data)); } } function shader_context_delete(raw: shader_context_t) { if (raw._.pipe_state.fragment_shader != null) { iron_gpu_shader_destroy(raw._.pipe_state.fragment_shader); } if (raw._.pipe_state.vertex_shader != null) { iron_gpu_shader_destroy(raw._.pipe_state.vertex_shader); } gpu_delete_pipeline(raw._.pipe_state); } function shader_context_get_compare_mode(s: string): compare_mode_t { if (s == "always") { return compare_mode_t.ALWAYS; } if (s == "never") { return compare_mode_t.NEVER; } if (s == "less") { return compare_mode_t.LESS; } if (s == "less_equal") { return compare_mode_t.LESS_EQUAL; } if (s == "greater") { return compare_mode_t.GREATER; } if (s == "greater_equal") { return compare_mode_t.GREATER_EQUAL; } if (s == "equal") { return compare_mode_t.EQUAL; } if (s == "not_equal") { return compare_mode_t.NOT_EQUAL; } return compare_mode_t.LESS; } function shader_context_get_cull_mode(s: string): cull_mode_t { if (s == "none") { return cull_mode_t.NONE; } if (s == "clockwise") { return cull_mode_t.CLOCKWISE; } return cull_mode_t.COUNTER_CLOCKWISE; } function shader_context_get_blend_fac(s: string): blend_factor_t { if (s == "blend_one") { return blend_factor_t.BLEND_ONE; } if (s == "blend_zero") { return blend_factor_t.BLEND_ZERO; } if (s == "source_alpha") { return blend_factor_t.SOURCE_ALPHA; } if (s == "destination_alpha") { return blend_factor_t.DEST_ALPHA; } if (s == "inverse_source_alpha") { return blend_factor_t.INV_SOURCE_ALPHA; } if (s == "inverse_destination_alpha") { return blend_factor_t.INV_DEST_ALPHA; } if (s == "source_color") { return blend_factor_t.SOURCE_COLOR; } if (s == "destination_color") { return blend_factor_t.DEST_COLOR; } if (s == "inverse_source_color") { return blend_factor_t.INV_SOURCE_COLOR; } if (s == "inverse_destination_color") { return blend_factor_t.INV_DEST_COLOR; } return blend_factor_t.BLEND_ONE; } function shader_context_get_tex_addresing(s: string): tex_addressing_t { if (s == "repeat") { return tex_addressing_t.REPEAT; } if (s == "mirror") { return tex_addressing_t.MIRROR; } return tex_addressing_t.CLAMP; } function shader_context_get_tex_filter(s: string): tex_filter_t { if (s == "point") { return tex_filter_t.POINT; } if (s == "linear") { return tex_filter_t.LINEAR; } return tex_filter_t.ANISOTROPIC; } function shader_context_get_mipmap_filter(s: string): mip_map_filter_t { if (s == "no") { return mip_map_filter_t.NONE; } if (s == "point") { return mip_map_filter_t.POINT; } return mip_map_filter_t.LINEAR; } function shader_context_get_tex_format(s: string): tex_format_t { if (s == "RGBA32") { return tex_format_t.RGBA32; } if (s == "RGBA64") { return tex_format_t.RGBA64; } if (s == "RGBA128") { return tex_format_t.RGBA128; } if (s == "R32") { return tex_format_t.R32; } if (s == "R16") { return tex_format_t.R16; } if (s == "R8") { return tex_format_t.R8; } return tex_format_t.RGBA32; } function shader_context_add_const(raw: shader_context_t, c: shader_const_t, offset: i32) { let cl: iron_gpu_constant_location_t = gpu_get_constant_location(raw._.pipe_state, c.name); let ptr: gpu_constant_location_impl_t = ADDRESS(cl.impl); ptr.vertexOffset = offset; ptr.fragmentOffset = offset; array_push(raw._.constants, cl); } function shader_context_add_tex(raw: shader_context_t, tu: tex_unit_t, i: i32) { let unit: iron_gpu_texture_unit_t = gpu_get_texture_unit(raw._.pipe_state, tu.name); ARRAY_ACCESS(unit.stages, IRON_GPU_SHADER_TYPE_FRAGMENT) = i; array_push(raw._.tex_units, unit); } function shader_context_set_tex_params(raw: shader_context_t, unit_index: i32, tex: bind_tex_t) { // This function is called for samplers set using material context let unit: any = raw._.tex_units[unit_index]; gpu_set_texture_parameters(unit, tex.u_addressing == null ? tex_addressing_t.REPEAT : shader_context_get_tex_addresing(tex.u_addressing), tex.v_addressing == null ? tex_addressing_t.REPEAT : shader_context_get_tex_addresing(tex.v_addressing), tex.min_filter == null ? tex_filter_t.LINEAR : shader_context_get_tex_filter(tex.min_filter), tex.mag_filter == null ? tex_filter_t.LINEAR : shader_context_get_tex_filter(tex.mag_filter), tex.mipmap_filter == null ? mip_map_filter_t.NONE : shader_context_get_mipmap_filter(tex.mipmap_filter)); }