2024-04-13 23:51:38 +02:00
|
|
|
#include "PipelineCache.h"
|
|
|
|
|
#include "Descriptor.h"
|
2024-04-14 11:35:37 +02:00
|
|
|
#include "Enums.h"
|
|
|
|
|
#include "Foundation/NSError.hpp"
|
2024-04-17 14:33:06 +02:00
|
|
|
#include "Foundation/NSString.hpp"
|
2024-04-13 23:51:38 +02:00
|
|
|
#include "Graphics.h"
|
|
|
|
|
#include "Graphics/Descriptor.h"
|
|
|
|
|
#include "Graphics/Enums.h"
|
2024-04-14 11:35:37 +02:00
|
|
|
#include "Graphics/Metal/Pipeline.h"
|
|
|
|
|
#include "Metal/MTLComputePipeline.hpp"
|
|
|
|
|
#include "Metal/MTLDevice.hpp"
|
|
|
|
|
#include "Metal/MTLRenderCommandEncoder.hpp"
|
2024-04-13 23:51:38 +02:00
|
|
|
#include "Metal/MTLRenderPipeline.hpp"
|
|
|
|
|
#include "Metal/MTLVertexDescriptor.hpp"
|
2024-04-14 11:35:37 +02:00
|
|
|
#include "Shader.h"
|
|
|
|
|
#include "Texture.h"
|
2024-04-17 14:33:06 +02:00
|
|
|
#include <iostream>
|
2024-04-13 23:51:38 +02:00
|
|
|
|
|
|
|
|
using namespace Seele;
|
|
|
|
|
using namespace Seele::Metal;
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
PipelineCache::PipelineCache(PGraphics graphics, const std::string &name)
|
|
|
|
|
: graphics(graphics), cacheFile(name) {}
|
2024-04-13 23:51:38 +02:00
|
|
|
|
|
|
|
|
PipelineCache::~PipelineCache() {}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
PGraphicsPipeline
|
|
|
|
|
PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo createInfo) {
|
|
|
|
|
PPipelineLayout layout =
|
|
|
|
|
Gfx::PPipelineLayout(createInfo.pipelineLayout).cast<PipelineLayout>();
|
2024-04-14 11:35:37 +02:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
MTL::RenderPipelineDescriptor *pipelineDescriptor =
|
|
|
|
|
MTL::RenderPipelineDescriptor::alloc()->init();
|
2024-04-13 23:51:38 +02:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
MTL::VertexDescriptor *vertexDescriptor =
|
|
|
|
|
pipelineDescriptor->vertexDescriptor()->init();
|
|
|
|
|
MTL::VertexAttributeDescriptorArray *attributes =
|
|
|
|
|
vertexDescriptor->attributes()->init();
|
2024-04-17 14:33:06 +02:00
|
|
|
if (createInfo.vertexInput != nullptr) {
|
2024-06-09 12:20:04 +02:00
|
|
|
const auto &vertexInfo = createInfo.vertexInput->getInfo();
|
2024-04-15 13:48:34 +02:00
|
|
|
for (size_t attr = 0; attr < vertexInfo.attributes.size(); ++attr) {
|
2024-06-09 12:20:04 +02:00
|
|
|
MTL::VertexAttributeDescriptor *attribute =
|
|
|
|
|
attributes->object(attr + METAL_VERTEXATTRIBUTE_OFFSET)->init();
|
|
|
|
|
attribute->setBufferIndex(vertexInfo.attributes[attr].binding +
|
|
|
|
|
METAL_VERTEXBUFFER_OFFSET);
|
2024-04-15 13:48:34 +02:00
|
|
|
switch (vertexInfo.attributes[attr].format) {
|
|
|
|
|
case Gfx::SE_FORMAT_R32G32B32_SFLOAT:
|
|
|
|
|
attribute->setFormat(MTL::VertexFormatFloat3);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw std::logic_error("TODO");
|
|
|
|
|
}
|
|
|
|
|
attribute->setOffset(vertexInfo.attributes[attr].offset);
|
2024-04-13 23:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
MTL::VertexBufferLayoutDescriptorArray *bufferLayout =
|
|
|
|
|
vertexDescriptor->layouts()->init();
|
2024-04-15 13:48:34 +02:00
|
|
|
for (size_t binding = 0; binding < vertexInfo.bindings.size(); ++binding) {
|
2024-06-09 12:20:04 +02:00
|
|
|
MTL::VertexBufferLayoutDescriptor *buffer =
|
|
|
|
|
bufferLayout->object(binding + METAL_VERTEXBUFFER_OFFSET)->init();
|
2024-04-15 13:48:34 +02:00
|
|
|
buffer->setStride(vertexInfo.bindings[binding].stride);
|
|
|
|
|
buffer->setStepRate(1);
|
|
|
|
|
switch (vertexInfo.bindings[binding].inputRate) {
|
|
|
|
|
case Gfx::SE_VERTEX_INPUT_RATE_VERTEX:
|
|
|
|
|
buffer->setStepFunction(MTL::VertexStepFunctionPerVertex);
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_VERTEX_INPUT_RATE_INSTANCE:
|
|
|
|
|
buffer->setStepFunction(MTL::VertexStepFunctionPerInstance);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-04-13 23:51:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pipelineDescriptor->setVertexDescriptor(vertexDescriptor);
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setVertexFunction(
|
|
|
|
|
createInfo.vertexShader.cast<VertexShader>()->getFunction());
|
2024-04-14 11:35:37 +02:00
|
|
|
if (createInfo.fragmentShader != nullptr) {
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setFragmentFunction(
|
|
|
|
|
createInfo.fragmentShader.cast<FragmentShader>()->getFunction());
|
2024-04-14 11:35:37 +02:00
|
|
|
}
|
|
|
|
|
pipelineDescriptor->setInputPrimitiveTopology(cast(createInfo.topology));
|
2024-06-09 12:20:04 +02:00
|
|
|
if (createInfo.renderPass->getLayout().depthAttachment.getTexture() !=
|
|
|
|
|
nullptr) {
|
2024-04-14 11:35:37 +02:00
|
|
|
pipelineDescriptor->setDepthAttachmentPixelFormat(
|
2024-06-09 12:20:04 +02:00
|
|
|
cast(createInfo.renderPass->getLayout()
|
|
|
|
|
.depthAttachment.getTexture()
|
|
|
|
|
.cast<Texture2D>()
|
|
|
|
|
->getFormat()));
|
2024-04-14 11:35:37 +02:00
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setAlphaToCoverageEnabled(
|
|
|
|
|
createInfo.multisampleState.alphaCoverageEnable);
|
|
|
|
|
pipelineDescriptor->setAlphaToOneEnabled(
|
|
|
|
|
createInfo.multisampleState.alphaToOneEnable);
|
2024-04-14 11:35:37 +02:00
|
|
|
pipelineDescriptor->setRasterSampleCount(createInfo.multisampleState.samples);
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setRasterizationEnabled(
|
|
|
|
|
!createInfo.rasterizationState.rasterizerDiscardEnable);
|
2024-04-14 11:35:37 +02:00
|
|
|
|
|
|
|
|
uint32 hash = pipelineDescriptor->hash();
|
|
|
|
|
|
|
|
|
|
if (graphicsPipelines.contains(hash)) {
|
|
|
|
|
return graphicsPipelines[hash];
|
|
|
|
|
}
|
|
|
|
|
MTL::PrimitiveType type = MTL::PrimitiveTypeTriangle;
|
|
|
|
|
switch (createInfo.topology) {
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_POINT_LIST:
|
|
|
|
|
type = MTL::PrimitiveTypePoint;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST:
|
|
|
|
|
type = MTL::PrimitiveTypeLine;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_STRIP:
|
|
|
|
|
type = MTL::PrimitiveTypeLineStrip;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
|
|
|
|
|
type = MTL::PrimitiveTypeTriangle;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
|
|
|
|
|
type = MTL::PrimitiveTypeTriangleStrip;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
|
|
|
|
|
type = MTL::PrimitiveTypeTriangle;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
|
|
|
|
|
type = MTL::PrimitiveTypeLine;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
|
|
|
|
|
type = MTL::PrimitiveTypeLineStrip;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
|
|
|
|
|
type = MTL::PrimitiveTypeTriangle;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
|
|
|
|
|
type = MTL::PrimitiveTypeTriangleStrip;
|
|
|
|
|
break;
|
|
|
|
|
case Gfx::SE_PRIMITIVE_TOPOLOGY_PATCH_LIST:
|
|
|
|
|
type = MTL::PrimitiveTypeTriangle;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
NS::Error *error;
|
|
|
|
|
graphicsPipelines[hash] = new GraphicsPipeline(
|
|
|
|
|
graphics, type,
|
|
|
|
|
graphics->getDevice()->newRenderPipelineState(pipelineDescriptor, &error),
|
|
|
|
|
std::move(createInfo.pipelineLayout));
|
2024-04-17 14:33:06 +02:00
|
|
|
if (error) {
|
2024-06-09 12:20:04 +02:00
|
|
|
std::cout << error->localizedDescription()->cString(NS::ASCIIStringEncoding)
|
|
|
|
|
<< std::endl;
|
2024-04-17 14:33:06 +02:00
|
|
|
assert(false);
|
|
|
|
|
}
|
2024-04-13 23:51:38 +02:00
|
|
|
|
|
|
|
|
pipelineDescriptor->release();
|
2024-04-14 11:35:37 +02:00
|
|
|
return graphicsPipelines[hash];
|
2024-04-13 23:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
PGraphicsPipeline
|
|
|
|
|
PipelineCache::createPipeline(Gfx::MeshPipelineCreateInfo createInfo) {
|
|
|
|
|
MTL::MeshRenderPipelineDescriptor *pipelineDescriptor =
|
|
|
|
|
MTL::MeshRenderPipelineDescriptor::alloc()->init();
|
2024-04-13 23:51:38 +02:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setMeshFunction(
|
|
|
|
|
createInfo.meshShader.cast<MeshShader>()->getFunction());
|
2024-04-14 11:35:37 +02:00
|
|
|
if (createInfo.taskShader != nullptr) {
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setObjectFunction(
|
|
|
|
|
createInfo.taskShader.cast<TaskShader>()->getFunction());
|
2024-04-14 11:35:37 +02:00
|
|
|
}
|
|
|
|
|
if (createInfo.fragmentShader != nullptr) {
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setFragmentFunction(
|
|
|
|
|
createInfo.fragmentShader.cast<FragmentShader>()->getFunction());
|
2024-04-14 11:35:37 +02:00
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if (createInfo.renderPass->getLayout().depthAttachment.getTexture() !=
|
|
|
|
|
nullptr) {
|
2024-04-14 11:35:37 +02:00
|
|
|
pipelineDescriptor->setDepthAttachmentPixelFormat(
|
2024-06-09 12:20:04 +02:00
|
|
|
cast(createInfo.renderPass->getLayout()
|
|
|
|
|
.depthAttachment.getTexture()
|
|
|
|
|
.cast<Texture2D>()
|
|
|
|
|
->getFormat()));
|
2024-04-14 11:35:37 +02:00
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setAlphaToCoverageEnabled(
|
|
|
|
|
createInfo.multisampleState.alphaCoverageEnable);
|
|
|
|
|
pipelineDescriptor->setAlphaToOneEnabled(
|
|
|
|
|
createInfo.multisampleState.alphaToOneEnable);
|
2024-04-14 11:35:37 +02:00
|
|
|
pipelineDescriptor->setRasterSampleCount(createInfo.multisampleState.samples);
|
2024-06-09 12:20:04 +02:00
|
|
|
pipelineDescriptor->setRasterizationEnabled(
|
|
|
|
|
!createInfo.rasterizationState.rasterizerDiscardEnable);
|
2024-04-14 11:35:37 +02:00
|
|
|
|
|
|
|
|
uint32 hash = pipelineDescriptor->hash();
|
|
|
|
|
|
|
|
|
|
if (graphicsPipelines.contains(hash)) {
|
|
|
|
|
return graphicsPipelines[hash];
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
NS::Error *error = nullptr;
|
2024-04-17 14:33:06 +02:00
|
|
|
MTL::AutoreleasedRenderPipelineReflection reflection;
|
|
|
|
|
graphicsPipelines[hash] = new GraphicsPipeline(
|
|
|
|
|
graphics, MTL::PrimitiveTypeTriangle,
|
2024-06-09 12:20:04 +02:00
|
|
|
graphics->getDevice()->newRenderPipelineState(
|
|
|
|
|
pipelineDescriptor, MTL::PipelineOptionNone, &reflection, &error),
|
2024-04-17 14:33:06 +02:00
|
|
|
std::move(createInfo.pipelineLayout));
|
2024-04-14 11:35:37 +02:00
|
|
|
|
|
|
|
|
pipelineDescriptor->release();
|
|
|
|
|
return graphicsPipelines[hash];
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
PComputePipeline
|
|
|
|
|
PipelineCache::createPipeline(Gfx::ComputePipelineCreateInfo createInfo) {
|
2024-04-14 11:35:37 +02:00
|
|
|
PComputeShader shader = createInfo.computeShader.cast<ComputeShader>();
|
|
|
|
|
uint32 hash = shader->getShaderHash();
|
|
|
|
|
if (computePipelines.contains(hash)) {
|
|
|
|
|
return computePipelines[hash];
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
NS::Error *error;
|
2024-04-14 11:35:37 +02:00
|
|
|
computePipelines[hash] =
|
2024-06-09 12:20:04 +02:00
|
|
|
new ComputePipeline(graphics,
|
|
|
|
|
graphics->getDevice()->newComputePipelineState(
|
|
|
|
|
shader->getFunction(), &error),
|
2024-04-14 11:35:37 +02:00
|
|
|
std::move(createInfo.pipelineLayout));
|
|
|
|
|
assert(!error);
|
|
|
|
|
return computePipelines[hash];
|
|
|
|
|
}
|