X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fglsl%2Fspirv.cpp;h=c6f15614f5c8a56a36c7e7236a1c785f081e0a19;hp=7b3e104e372c65a7d845bfd0a77c93358762aee3;hb=HEAD;hpb=0859998b4d394cb31f92c1031339bf6404561a8a diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 7b3e104e..4dceb971 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -111,9 +111,14 @@ const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] = { "textureSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "textureQueryLod", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "textureQueryLevels", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "textureSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, - { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texel_fetch }, + { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageLoad", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageStore", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_store }, { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 }, { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 }, { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 }, @@ -182,6 +187,14 @@ SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const strin return BUILTIN_INVOCATION_ID; else if(name=="gl_Layer") return BUILTIN_LAYER; + else if(name=="gl_TessLevelOuter") + return BUILTIN_TESS_LEVEL_OUTER; + else if(name=="gl_TessLevelInner") + return BUILTIN_TESS_LEVEL_INNER; + else if(name=="gl_TessCoord") + return BUILTIN_TESS_COORD; + else if(name=="gl_PatchVerticesIn") + return BUILTIN_PATCH_VERTICES; else if(name=="gl_FragCoord") return BUILTIN_FRAG_COORD; else if(name=="gl_PointCoord") @@ -194,10 +207,66 @@ SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const strin return BUILTIN_SAMPLE_POSITION; else if(name=="gl_FragDepth") return BUILTIN_FRAG_DEPTH; + else if(name=="gl_NumWorkGroups") + return BUILTIN_NUM_WORKGROUPS; + else if(name=="gl_WorkGroupSize") + return BUILTIN_WORKGROUP_SIZE; + else if(name=="gl_WorkGroupID") + return BUILTIN_WORKGROUP_ID; + else if(name=="gl_LocalInvocationID") + return BUILTIN_LOCAL_INVOCATION_ID; + else if(name=="gl_GlobalInvocationID") + return BUILTIN_GLOBAL_INVOCATION_ID; + else if(name=="gl_LocalInvocationIndex") + return BUILTIN_LOCAL_INVOCATION_INDEX; else throw invalid_argument("SpirVGenerator::get_builtin_semantic"); } +SpirVFormat SpirVGenerator::get_format(const std::string &name) +{ + if(name.empty()) + return FORMAT_UNKNOWN; + else if(name=="rgba32f") + return FORMAT_RGBA32F; + else if(name=="rgba16f") + return FORMAT_RGBA16F; + else if(name=="r32f") + return FORMAT_R32F; + else if(name=="rgba8") + return FORMAT_RGBA8; + else if(name=="rgba8_snorm") + return FORMAT_RGBA8_SNORM; + else if(name=="rg32f") + return FORMAT_RG32F; + else if(name=="rg16f") + return FORMAT_RG16F; + else if(name=="r16f") + return FORMAT_R16F; + else if(name=="rgba16") + return FORMAT_RGBA16; + else if(name=="rg16") + return FORMAT_RG16; + else if(name=="rg8") + return FORMAT_RG8; + else if(name=="r16") + return FORMAT_RG16; + else if(name=="r8") + return FORMAT_RG8; + else if(name=="rgba16_snorm") + return FORMAT_RGBA16_SNORM; + else if(name=="rg16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="rg8_snorm") + return FORMAT_RG8_SNORM; + else if(name=="r16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="r8_snorm") + return FORMAT_RG8_SNORM; + else + throw invalid_argument("SpirVGenerator::get_format"); +} + void SpirVGenerator::use_capability(Capability cap) { if(used_capabilities.count(cap)) @@ -518,7 +587,9 @@ void SpirVGenerator::visit(VariableReference &var) if(composite_access) { r_expression_result_id = 0; - if(!assignment_source_id) + if(assignment_source_id) + variable_load_ids.erase(var.declaration); + else { auto i = variable_load_ids.find(var.declaration); if(i!=variable_load_ids.end()) @@ -846,9 +917,10 @@ void SpirVGenerator::visit(BinaryExpression &binary) compare_id = write_construct(bool_vec_type_id, column_ids, n_elems); } + else + throw internal_error("unsupported types for non-scalar equality comparison"); - if(compare_id) - r_expression_result_id = write_expression(combine_op, result_type_id, compare_id); + r_expression_result_id = write_expression(combine_op, result_type_id, compare_id); return; } } @@ -1021,18 +1093,22 @@ void SpirVGenerator::visit(TernaryExpression &ternary) writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none) writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, condition_id, true_label_id, false_label_id); + std::map saved_load_ids = variable_load_ids; + writer.write_op_label(true_label_id); ternary.true_expr->visit(*this); Id true_result_id = r_expression_result_id; true_label_id = writer.get_current_block(); writer.write_op(content.function_body, OP_BRANCH, merge_block_id); + swap(saved_load_ids, variable_load_ids); writer.write_op_label(false_label_id); ternary.false_expr->visit(*this); Id false_result_id = r_expression_result_id; false_label_id = writer.get_current_block(); writer.write_op_label(merge_block_id); + prune_loads(true_label_id); r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4); writer.write(true_result_id); writer.write(true_label_id); @@ -1287,17 +1363,21 @@ void SpirVGenerator::visit_builtin_texture_query(FunctionCall &call, const vecto Opcode opcode; if(call.name=="textureSize") opcode = OP_IMAGE_QUERY_SIZE_LOD; + else if(call.name=="imageSize") + opcode = OP_IMAGE_QUERY_SIZE; else if(call.name=="textureQueryLod") opcode = OP_IMAGE_QUERY_LOD; else if(call.name=="textureQueryLevels") opcode = OP_IMAGE_QUERY_LEVELS; + else if(call.name=="textureSamples" || call.name=="imageSamples") + opcode = OP_IMAGE_QUERY_SAMPLES; else throw internal_error("invalid texture query call"); ImageTypeDeclaration &image_arg0 = dynamic_cast(*call.arguments[0]->type); Id image_id; - if(image_arg0.sampled) + if(image_arg0.sampled && opcode!=OP_IMAGE_QUERY_LOD) { Id image_type_id = get_item(image_type_ids, get_id(image_arg0)); image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]); @@ -1362,17 +1442,63 @@ void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector end_expression(opcode); } -void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector &argument_ids) +void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector &argument_ids) +{ + ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); + + Opcode opcode; + if(call.name=="texelFetch") + opcode = OP_IMAGE_FETCH; + else if(call.name=="imageLoad") + opcode = OP_IMAGE_READ; + else + throw internal_error("invalid texture fetch call"); + + bool need_sample = image.multisample; + bool need_lod = (opcode==OP_IMAGE_FETCH && !need_sample); + + if(argument_ids.size()!=2U+need_sample+need_lod) + throw internal_error("invalid texture fetch call"); + + Id image_id; + if(image.sampled) + { + Id image_type_id = get_item(image_type_ids, get_id(image)); + image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]); + } + else + image_id = argument_ids[0]; + + r_expression_result_id = begin_expression(opcode, get_id(*call.type), 2+(need_lod|need_sample)+need_lod+need_sample); + writer.write(image_id); + writer.write(argument_ids[1]); + if(need_lod || need_sample) + { + writer.write(need_lod*0x02 | need_sample*0x40); + writer.write(argument_ids.back()); + } + end_expression(opcode); +} + +void SpirVGenerator::visit_builtin_texture_store(FunctionCall &call, const vector &argument_ids) { if(argument_ids.size()!=3) - throw internal_error("invalid texelFetch call"); + throw internal_error("invalid texture store call"); + + const ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); - r_expression_result_id = begin_expression(OP_IMAGE_FETCH, get_id(*call.type), 4); + begin_expression(OP_IMAGE_WRITE, get_id(*call.type), 3+image.multisample*2); for(unsigned i=0; i<2; ++i) writer.write(argument_ids[i]); - writer.write(2); // Lod writer.write(argument_ids.back()); - end_expression(OP_IMAGE_FETCH); + if(image.multisample) + { + writer.write(0x40); // Sample + writer.write(argument_ids[2]); + } + end_expression(OP_IMAGE_WRITE); + + r_expression_result_id = 0; } void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector &argument_ids) @@ -1480,6 +1606,7 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) return; Id type_id = allocate_id(image, 0); + SpirVFormat format = get_format(image.format); Id image_id = (image.sampled ? next_id++ : type_id); writer.begin_op(content.globals, OP_TYPE_IMAGE, 9); @@ -1488,9 +1615,9 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) writer.write(image.dimensions-1); writer.write(image.shadow); writer.write(image.array); - writer.write(false); // Multisample + writer.write(image.multisample); writer.write(image.sampled ? 1 : 2); - writer.write(0); // Format (unknown) + writer.write(format); writer.end_op(OP_TYPE_IMAGE); if(image.sampled) @@ -1504,6 +1631,12 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D); else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array) use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY); + + if(image.multisample && !image.sampled) + use_capability(CAP_STORAGE_IMAGE_MULTISAMPLE); + + if(format>=FORMAT_RG32F && format<=FORMAT_R8_SNORM) + use_capability(CAP_STORAGE_IMAGE_EXTENDED_FORMATS); } void SpirVGenerator::visit(StructDeclaration &strct) @@ -1662,6 +1795,12 @@ void SpirVGenerator::visit(VariableDeclaration &var) BuiltinSemantic semantic = get_builtin_semantic(var.name); writer.write_op_decorate(var_id, DECO_BUILTIN, semantic); } + if(var.interpolation=="flat") + writer.write_op_decorate(var_id, DECO_FLAT); + if(var.sampling=="centroid") + writer.write_op_decorate(var_id, DECO_CENTROID); + if(var.sampling=="patch") + writer.write_op_decorate(var_id, DECO_PATCH); if(init_id && current_function) { @@ -1680,8 +1819,11 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) switch(stage->type) { case Stage::VERTEX: writer.write(0); break; + case Stage::TESS_CONTROL: writer.write(1); break; + case Stage::TESS_EVAL: writer.write(2); break; case Stage::GEOMETRY: writer.write(3); break; case Stage::FRAGMENT: writer.write(4); break; + case Stage::COMPUTE: writer.write(5); break; default: throw internal_error("unknown stage"); } writer.write(func_id); @@ -1691,7 +1833,7 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) for(Node *n: dependencies) if(const VariableDeclaration *var = dynamic_cast(n)) if(!var->interface.empty()) - writer.write(get_id(*n)); + writer.write(allocate_forward_id(*n)); writer.end_op(OP_ENTRY_POINT); @@ -1705,6 +1847,12 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) use_capability(CAP_GEOMETRY); writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INVOCATIONS, 1); } + else if(stage->type==Stage::TESS_CONTROL || stage->type==Stage::TESS_EVAL) + { + use_capability(CAP_TESSELLATION); + } + + unsigned local_size[3] = { 0, 1, 1 }; for(const InterfaceLayout *i: interface_layouts) { @@ -1721,14 +1869,44 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_TRIANGLES); else if(q.name=="triangles_adjacency") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_TRIANGLES_ADJACENCY); + else if(q.name=="quads") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_QUADS); + else if(q.name=="isolines") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ISOLINES); else if(q.name=="line_strip") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_LINE_STRIP); else if(q.name=="triangle_strip") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP); - else if(q.name=="max_vertices") + else if(q.name=="max_vertices" || q.name=="vertices") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, q.value); + else if(q.name=="cw") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_VERTEX_ORDER_CW); + else if(q.name=="ccw") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_VERTEX_ORDER_CCW); + else if(q.name=="equal_spacing") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_EQUAL); + else if(q.name=="fractional_even_spacing") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_FRACTIONAL_EVEN); + else if(q.name=="fractional_odd_spacing") + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_FRACTIONAL_ODD); + else if(q.name=="local_size_x") + local_size[0] = q.value; + else if(q.name=="local_size_y") + local_size[1] = q.value; + else if(q.name=="local_size_z") + local_size[2] = q.value; } } + + if(stage->type==Stage::COMPUTE && local_size[0]) + { + writer.begin_op(content.exec_modes, OP_EXECUTION_MODE); + writer.write(func_id); + writer.write(EXEC_LOCAL_SIZE); + for(unsigned j=0; j<3; ++j) + writer.write(local_size[j]); + writer.end_op(OP_EXECUTION_MODE); + } } void SpirVGenerator::visit(FunctionDeclaration &func)