213 lines
9.2 KiB
C++
Raw Normal View History

Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
/*
* SPIRVReflection.cpp
*
* Copyright (c) 2019 Chip Davis for Codeweavers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SPIRVReflection.h"
#include <SPIRV-Cross/spirv_parser.hpp>
#include <SPIRV-Cross/spirv_reflect.hpp>
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
namespace mvk {
static const char missingPatchInputErr[] = "Neither tessellation shader specifies a patch input mode (Triangles, Quads, or Isolines).";
static const char missingWindingErr[] = "Neither tessellation shader specifies a winding order mode (VertexOrderCw or VertexOrderCcw).";
static const char missingPartitionErr[] = "Neither tessellation shader specifies a partition mode (SpacingEqual, SpacingFractionalOdd, or SpacingFractionalEven).";
static const char missingOutputVerticesErr[] = "Neither tessellation shader specifies the number of output control points.";
/** Given a tessellation control shader and a tessellation evaluation shader, both in SPIR-V format, returns tessellation reflection data. */
bool getTessReflectionData(const std::vector<uint32_t>& tesc, const std::string& tescEntryName, const std::vector<uint32_t>& tese, const std::string& teseEntryName, SPIRVTessReflectionData& reflectData, std::string& errorLog) {
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
try {
#endif
SPIRV_CROSS_NAMESPACE::CompilerReflection tescReflect(tesc);
SPIRV_CROSS_NAMESPACE::CompilerReflection teseReflect(tese);
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
if (!tescEntryName.empty()) {
tescReflect.set_entry_point(tescEntryName, spv::ExecutionModelTessellationControl);
}
if (!teseEntryName.empty()) {
teseReflect.set_entry_point(teseEntryName, spv::ExecutionModelTessellationEvaluation);
}
tescReflect.compile();
teseReflect.compile();
const SPIRV_CROSS_NAMESPACE::Bitset& tescModes = tescReflect.get_execution_mode_bitset();
const SPIRV_CROSS_NAMESPACE::Bitset& teseModes = teseReflect.get_execution_mode_bitset();
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
// Extract the parameters from the shaders.
if (tescModes.get(spv::ExecutionModeTriangles)) {
reflectData.patchKind = spv::ExecutionModeTriangles;
} else if (tescModes.get(spv::ExecutionModeQuads)) {
reflectData.patchKind = spv::ExecutionModeQuads;
} else if (tescModes.get(spv::ExecutionModeIsolines)) {
reflectData.patchKind = spv::ExecutionModeIsolines;
} else if (teseModes.get(spv::ExecutionModeTriangles)) {
reflectData.patchKind = spv::ExecutionModeTriangles;
} else if (teseModes.get(spv::ExecutionModeQuads)) {
reflectData.patchKind = spv::ExecutionModeQuads;
} else if (teseModes.get(spv::ExecutionModeIsolines)) {
reflectData.patchKind = spv::ExecutionModeIsolines;
} else {
errorLog = missingPatchInputErr;
return false;
}
if (tescModes.get(spv::ExecutionModeVertexOrderCw)) {
reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
} else if (tescModes.get(spv::ExecutionModeVertexOrderCcw)) {
reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
} else if (teseModes.get(spv::ExecutionModeVertexOrderCw)) {
reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
} else if (teseModes.get(spv::ExecutionModeVertexOrderCcw)) {
reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
} else {
errorLog = missingWindingErr;
return false;
}
reflectData.pointMode = tescModes.get(spv::ExecutionModePointMode) || teseModes.get(spv::ExecutionModePointMode);
if (tescModes.get(spv::ExecutionModeSpacingEqual)) {
reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
} else if (tescModes.get(spv::ExecutionModeSpacingFractionalEven)) {
reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
} else if (tescModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
} else if (teseModes.get(spv::ExecutionModeSpacingEqual)) {
reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
} else if (teseModes.get(spv::ExecutionModeSpacingFractionalEven)) {
reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
} else if (teseModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
} else {
errorLog = missingPartitionErr;
return false;
}
if (tescModes.get(spv::ExecutionModeOutputVertices)) {
reflectData.numControlPoints = tescReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
} else if (teseModes.get(spv::ExecutionModeOutputVertices)) {
reflectData.numControlPoints = teseReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
} else {
errorLog = missingOutputVerticesErr;
return false;
}
return true;
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
} catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
errorLog = ex.what();
return false;
}
#endif
}
/** Given a shader in SPIR-V format, returns output reflection data. */
bool getShaderOutputs(const std::vector<uint32_t>& spirv, spv::ExecutionModel model, const std::string& entryName, std::vector<SPIRVShaderOutput>& outputs, std::string& errorLog) {
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
try {
#endif
SPIRV_CROSS_NAMESPACE::Parser parser(spirv);
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
parser.parse();
SPIRV_CROSS_NAMESPACE::CompilerReflection reflect(parser.get_parsed_ir());
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
if (!entryName.empty()) {
reflect.set_entry_point(entryName, model);
}
reflect.compile();
reflect.update_active_builtins();
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
outputs.clear();
auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
parser.get_parsed_ir().for_each_typed_id<SPIRV_CROSS_NAMESPACE::SPIRVariable>([&reflect, &outputs, model, addSat](uint32_t varID, const SPIRV_CROSS_NAMESPACE::SPIRVariable& var) {
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
if (var.storage != spv::StorageClassOutput) { return; }
bool isUsed = true;
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
bool patch = reflect.has_decoration(varID, spv::DecorationPatch);
auto biType = spv::BuiltInMax;
if (reflect.has_decoration(varID, spv::DecorationBuiltIn)) {
biType = (spv::BuiltIn)reflect.get_decoration(varID, spv::DecorationBuiltIn);
isUsed = reflect.has_active_builtin(biType, var.storage);
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
uint32_t loc = -1;
if (reflect.has_decoration(varID, spv::DecorationLocation)) {
loc = reflect.get_decoration(varID, spv::DecorationLocation);
}
if (model == spv::ExecutionModelTessellationControl && !patch)
type = &reflect.get_type(type->parent_type);
if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
for (uint32_t i = 0; i < type->member_types.size(); i++) {
// Each member may have a location decoration. If not, each member
// gets an incrementing location.
uint32_t memberLoc = addSat(loc, i);
if (reflect.has_member_decoration(type->self, i, spv::DecorationLocation)) {
memberLoc = reflect.get_member_decoration(type->self, i, spv::DecorationLocation);
}
patch = reflect.has_member_decoration(type->self, i, spv::DecorationPatch);
if (reflect.has_member_decoration(type->self, i, spv::DecorationBuiltIn)) {
biType = (spv::BuiltIn)reflect.get_member_decoration(type->self, i, spv::DecorationBuiltIn);
isUsed = reflect.has_active_builtin(biType, var.storage);
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
const SPIRV_CROSS_NAMESPACE::SPIRType& memberType = reflect.get_type(type->member_types[i]);
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
if (memberType.columns > 1) {
for (uint32_t i = 0; i < memberType.columns; i++) {
outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
} else if (!memberType.array.empty()) {
for (uint32_t i = 0; i < memberType.array[0]; i++) {
outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
} else {
outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, biType, patch, isUsed});
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
}
} else if (type->columns > 1) {
for (uint32_t i = 0; i < type->columns; i++) {
outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
} else if (!type->array.empty()) {
for (uint32_t i = 0; i < type->array[0]; i++) {
outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
} else {
outputs.push_back({type->basetype, type->vecsize, loc, biType, patch, isUsed});
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
}
});
// Sort outputs by ascending location.
std::stable_sort(outputs.begin(), outputs.end(), [](const SPIRVShaderOutput& a, const SPIRVShaderOutput& b) {
return a.location < b.location;
});
// Assign locations to outputs that don't have one.
uint32_t loc = -1;
for (SPIRVShaderOutput& out : outputs) {
if (out.location == uint32_t(-1)) { out.location = loc + 1; }
loc = out.location;
}
return true;
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
} catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
Add support for tessellation. At long last, tessellation comes to MoltenVK! With this change, clients will now be able to specify tessellation shaders when creating pipelines, and then draw tessellated patches with them. Unfortunately, there seem to be a few gotchas with tessellation in Metal. For one thing, tessellation pipelines in Metal are structured very differently from Vulkan. There is no tessellation control or even vertex stage. Instead, the tessellation evaluation shader takes the place of the vertex function as a "post-tessellation vertex function." The tessellation levels are supplied in a buffer to the tessellator, which you are expected to populate. The most common way to do this is by running a compute shader. MoltenVK thus runs the vertex shader and tessellation control shader by themselves; a single `VkPipeline` object then requires at least *three* `MTLPipelineState` objects. But wait, there's more! The tessellation-control-as-compute stage uses Metal's support for vertex-style stage input to a compute shader. But, this support requires one to declare indexing *ahead of time*, when the pipeline state is created. So a single `VkPipeline` object could have as many as *five* `MTLPipelineState` objects. Further, if there are more output than input control points for the tessellation control stage, then later invocations may end up fetching the wrong attributes! To get around this, this change uses index buffers to ensure that all tessellation control shaders see the correct input. Unfortunately, in the indexed draw case, this means that the incoming index buffer needs to be munged. Instancing is another pain point here. In Vulkan, as in OpenGL and Direct3D, instancing is done in the vertex shader; but in Metal, it is done at the tessellation evaluation stage. For this reason, only the vertex stage of a tessellated draw supports instancing. Additional memory is required to hold data for the extra vertices generated by instancing. This also requires still more munging of index buffers for indexed draws. Indirect draws are even more painful. Because the number of vertices and instances is unknown, storage for the maximum possible number of vertices must be allocated. This change imposes a totally arbitrary limit of 131072 vertices from a single draw, including all vertices generated by instancing. On a Mac, this requires about 194-256 MB of VRAM for all the temporary buffers. There are some possible optimizations here. If we could prove that the vertex shader's output doesn't depend on the instance ID, either directly or through a per-instance attribute, then we could avoid running the vertex and tess. control stages per instance, and take advantage of Metal's support for tess. eval instancing. If we could also prove that the vertex shader simply passes instance attributes through (similarly with the tess. control shader), we could do this for many more instanced draws as well. It should also be possible to cache the output from the tess. control stage; if the draw comes up again, we can then skip the vertex and tess. control stages entirely! Fixes #56 and #501.
2019-02-18 20:56:42 -06:00
errorLog = ex.what();
return false;
}
#endif
}
}