blob: 3baa37fa54c755fd134ebc232457f7d2247449db [file] [log] [blame]
/*
* Copyright (C) 2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WHLSLEntryPointScaffolding.h"
#if ENABLE(WEBGPU)
#include "WHLSLBuiltInSemantic.h"
#include "WHLSLFunctionDefinition.h"
#include "WHLSLGatherEntryPointItems.h"
#include "WHLSLPipelineDescriptor.h"
#include "WHLSLReferenceType.h"
#include "WHLSLResourceSemantic.h"
#include "WHLSLStageInOutSemantic.h"
#include "WHLSLStructureDefinition.h"
#include "WHLSLTypeNamer.h"
#include <wtf/Optional.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/StringConcatenateNumbers.h>
namespace WebCore {
namespace WHLSL {
namespace Metal {
static String attributeForSemantic(AST::BuiltInSemantic& builtInSemantic)
{
switch (builtInSemantic.variable()) {
case AST::BuiltInSemantic::Variable::SVInstanceID:
return "[[instance_id]]"_str;
case AST::BuiltInSemantic::Variable::SVVertexID:
return "[[vertex_id]]"_str;
case AST::BuiltInSemantic::Variable::PSize:
return "[[point_size]]"_str;
case AST::BuiltInSemantic::Variable::SVPosition:
return "[[position]]"_str;
case AST::BuiltInSemantic::Variable::SVIsFrontFace:
return "[[front_facing]]"_str;
case AST::BuiltInSemantic::Variable::SVSampleIndex:
return "[[sample_id]]"_str;
case AST::BuiltInSemantic::Variable::SVInnerCoverage:
return "[[sample_mask]]"_str;
case AST::BuiltInSemantic::Variable::SVTarget:
return makeString("[[color(", *builtInSemantic.targetIndex(), ")]]");
case AST::BuiltInSemantic::Variable::SVDepth:
return "[[depth(any)]]"_str;
case AST::BuiltInSemantic::Variable::SVCoverage:
return "[[sample_mask]]"_str;
case AST::BuiltInSemantic::Variable::SVDispatchThreadID:
return "[[thread_position_in_grid]]"_str;
case AST::BuiltInSemantic::Variable::SVGroupID:
return "[[threadgroup_position_in_grid]]"_str;
case AST::BuiltInSemantic::Variable::SVGroupIndex:
return "[[thread_index_in_threadgroup]]"_str;
default:
ASSERT(builtInSemantic.variable() == AST::BuiltInSemantic::Variable::SVGroupThreadID);
return "[[thread_position_in_threadgroup]]"_str;
}
}
static String attributeForSemantic(AST::Semantic& semantic)
{
if (WTF::holds_alternative<AST::BuiltInSemantic>(semantic))
return attributeForSemantic(WTF::get<AST::BuiltInSemantic>(semantic));
auto& stageInOutSemantic = WTF::get<AST::StageInOutSemantic>(semantic);
return makeString("[[user(user", stageInOutSemantic.index(), ")]]");
}
EntryPointScaffolding::EntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<String()>&& generateNextVariableName)
: m_functionDefinition(functionDefinition)
, m_intrinsics(intrinsics)
, m_typeNamer(typeNamer)
, m_entryPointItems(entryPointItems)
, m_resourceMap(resourceMap)
, m_layout(layout)
, m_generateNextVariableName(generateNextVariableName)
{
m_namedBindGroups.reserveInitialCapacity(m_layout.size());
for (size_t i = 0; i < m_layout.size(); ++i) {
NamedBindGroup namedBindGroup;
namedBindGroup.structName = m_typeNamer.generateNextTypeName();
namedBindGroup.variableName = m_generateNextVariableName();
namedBindGroup.argumentBufferIndex = m_layout[i].name; // convertLayout() in GPURenderPipelineMetal.mm makes sure these don't collide.
namedBindGroup.namedBindings.reserveInitialCapacity(m_layout[i].bindings.size());
for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) {
NamedBinding namedBinding;
namedBinding.elementName = m_typeNamer.generateNextStructureElementName();
namedBinding.index = m_layout[i].bindings[j].internalName;
WTF::visit(WTF::makeVisitor([&](UniformBufferBinding& uniformBufferBinding) {
LengthInformation lengthInformation { m_typeNamer.generateNextStructureElementName(), m_generateNextVariableName(), uniformBufferBinding.lengthName };
namedBinding.lengthInformation = lengthInformation;
}, [&](SamplerBinding&) {
}, [&](TextureBinding&) {
}, [&](StorageBufferBinding& storageBufferBinding) {
LengthInformation lengthInformation { m_typeNamer.generateNextStructureElementName(), m_generateNextVariableName(), storageBufferBinding.lengthName };
namedBinding.lengthInformation = lengthInformation;
}), m_layout[i].bindings[j].binding);
namedBindGroup.namedBindings.uncheckedAppend(WTFMove(namedBinding));
}
m_namedBindGroups.uncheckedAppend(WTFMove(namedBindGroup));
}
for (size_t i = 0; i < m_entryPointItems.inputs.size(); ++i) {
if (!WTF::holds_alternative<AST::BuiltInSemantic>(*m_entryPointItems.inputs[i].semantic))
continue;
NamedBuiltIn namedBuiltIn;
namedBuiltIn.indexInEntryPointItems = i;
namedBuiltIn.variableName = m_generateNextVariableName();
m_namedBuiltIns.append(WTFMove(namedBuiltIn));
}
m_parameterVariables.reserveInitialCapacity(m_functionDefinition.parameters().size());
for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i)
m_parameterVariables.uncheckedAppend(m_generateNextVariableName());
}
String EntryPointScaffolding::resourceHelperTypes()
{
StringBuilder stringBuilder;
for (size_t i = 0; i < m_layout.size(); ++i) {
stringBuilder.append(makeString("struct ", m_namedBindGroups[i].structName, " {\n"));
for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) {
auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]);
if (iterator == m_resourceMap.end())
continue;
auto& unnamedType = *m_entryPointItems.inputs[iterator->value].unnamedType;
ASSERT(is<AST::ReferenceType>(unnamedType));
auto& referenceType = downcast<AST::ReferenceType>(unnamedType);
auto mangledTypeName = m_typeNamer.mangledNameForType(referenceType.elementType());
auto addressSpace = toString(referenceType.addressSpace());
auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
auto index = m_namedBindGroups[i].namedBindings[j].index;
stringBuilder.append(makeString(" ", addressSpace, " ", mangledTypeName, "* ", elementName, " [[id(", index, ")]];\n"));
if (auto lengthInformation = m_namedBindGroups[i].namedBindings[j].lengthInformation)
stringBuilder.append(makeString(" uint2 ", lengthInformation->elementName, " [[id(", lengthInformation->index, ")]];\n"));
}
stringBuilder.append("};\n\n");
}
return stringBuilder.toString();
}
Optional<String> EntryPointScaffolding::resourceSignature()
{
if (!m_layout.size())
return WTF::nullopt;
StringBuilder stringBuilder;
for (size_t i = 0; i < m_layout.size(); ++i) {
if (i)
stringBuilder.append(", ");
auto& namedBindGroup = m_namedBindGroups[i];
stringBuilder.append(makeString("device ", namedBindGroup.structName, "& ", namedBindGroup.variableName, " [[buffer(", namedBindGroup.argumentBufferIndex, ")]]"));
}
return stringBuilder.toString();
}
static String internalTypeForSemantic(const AST::BuiltInSemantic& builtInSemantic)
{
switch (builtInSemantic.variable()) {
case AST::BuiltInSemantic::Variable::SVInstanceID:
return "uint"_str;
case AST::BuiltInSemantic::Variable::SVVertexID:
return "uint"_str;
case AST::BuiltInSemantic::Variable::PSize:
return "float"_str;
case AST::BuiltInSemantic::Variable::SVPosition:
return "float4"_str;
case AST::BuiltInSemantic::Variable::SVIsFrontFace:
return "bool"_str;
case AST::BuiltInSemantic::Variable::SVSampleIndex:
return "uint"_str;
case AST::BuiltInSemantic::Variable::SVInnerCoverage:
return "uint"_str;
case AST::BuiltInSemantic::Variable::SVTarget:
return String();
case AST::BuiltInSemantic::Variable::SVDepth:
return "float"_str;
case AST::BuiltInSemantic::Variable::SVCoverage:
return "uint"_str;
case AST::BuiltInSemantic::Variable::SVDispatchThreadID:
return "uint3"_str;
case AST::BuiltInSemantic::Variable::SVGroupID:
return "uint3"_str;
case AST::BuiltInSemantic::Variable::SVGroupIndex:
return "uint"_str;
default:
ASSERT(builtInSemantic.variable() == AST::BuiltInSemantic::Variable::SVGroupThreadID);
return "uint3"_str;
}
}
Optional<String> EntryPointScaffolding::builtInsSignature()
{
if (!m_namedBuiltIns.size())
return WTF::nullopt;
StringBuilder stringBuilder;
for (size_t i = 0; i < m_namedBuiltIns.size(); ++i) {
if (i)
stringBuilder.append(", ");
auto& namedBuiltIn = m_namedBuiltIns[i];
auto& item = m_entryPointItems.inputs[namedBuiltIn.indexInEntryPointItems];
auto& builtInSemantic = WTF::get<AST::BuiltInSemantic>(*item.semantic);
auto internalType = internalTypeForSemantic(builtInSemantic);
if (internalType.isNull())
internalType = m_typeNamer.mangledNameForType(*item.unnamedType);
auto variableName = namedBuiltIn.variableName;
stringBuilder.append(makeString(internalType, ' ', variableName, ' ', attributeForSemantic(builtInSemantic)));
}
return stringBuilder.toString();
}
String EntryPointScaffolding::mangledInputPath(Vector<String>& path)
{
ASSERT(!path.isEmpty());
StringBuilder stringBuilder;
bool found = false;
AST::StructureDefinition* structureDefinition = nullptr;
for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i) {
if (m_functionDefinition.parameters()[i]->name() == path[0]) {
stringBuilder.append(m_parameterVariables[i]);
auto& unifyNode = m_functionDefinition.parameters()[i]->type()->unifyNode();
if (is<AST::NamedType>(unifyNode)) {
auto& namedType = downcast<AST::NamedType>(unifyNode);
if (is<AST::StructureDefinition>(namedType))
structureDefinition = &downcast<AST::StructureDefinition>(namedType);
}
found = true;
break;
}
}
ASSERT(found);
for (size_t i = 1; i < path.size(); ++i) {
ASSERT(structureDefinition);
auto* next = structureDefinition->find(path[i]);
ASSERT(next);
stringBuilder.append(makeString('.', m_typeNamer.mangledNameForStructureElement(*next)));
structureDefinition = nullptr;
auto& unifyNode = next->type().unifyNode();
if (is<AST::NamedType>(unifyNode)) {
auto& namedType = downcast<AST::NamedType>(unifyNode);
if (is<AST::StructureDefinition>(namedType))
structureDefinition = &downcast<AST::StructureDefinition>(namedType);
}
}
return stringBuilder.toString();
}
String EntryPointScaffolding::mangledOutputPath(Vector<String>& path)
{
StringBuilder stringBuilder;
AST::StructureDefinition* structureDefinition = nullptr;
auto& unifyNode = m_functionDefinition.type().unifyNode();
ASSERT(is<AST::NamedType>(unifyNode));
auto& namedType = downcast<AST::NamedType>(unifyNode);
ASSERT(is<AST::StructureDefinition>(namedType));
structureDefinition = &downcast<AST::StructureDefinition>(namedType);
for (auto& component : path) {
ASSERT(structureDefinition);
auto* next = structureDefinition->find(component);
ASSERT(next);
stringBuilder.append(makeString('.', m_typeNamer.mangledNameForStructureElement(*next)));
structureDefinition = nullptr;
auto& unifyNode = next->type().unifyNode();
if (is<AST::NamedType>(unifyNode)) {
auto& namedType = downcast<AST::NamedType>(unifyNode);
if (is<AST::StructureDefinition>(namedType))
structureDefinition = &downcast<AST::StructureDefinition>(namedType);
}
}
return stringBuilder.toString();
}
String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
{
StringBuilder stringBuilder;
for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i)
stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*m_functionDefinition.parameters()[i]->type()), ' ', m_parameterVariables[i], ";\n"));
for (size_t i = 0; i < m_layout.size(); ++i) {
auto variableName = m_namedBindGroups[i].variableName;
for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) {
auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]);
if (iterator == m_resourceMap.end())
continue;
if (m_namedBindGroups[i].namedBindings[j].lengthInformation) {
auto& path = m_entryPointItems.inputs[iterator->value].path;
auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
auto lengthElementName = m_namedBindGroups[i].namedBindings[j].lengthInformation->elementName;
auto lengthTemporaryName = m_namedBindGroups[i].namedBindings[j].lengthInformation->temporaryName;
auto& unnamedType = *m_entryPointItems.inputs[iterator->value].unnamedType;
ASSERT(is<AST::ReferenceType>(unnamedType));
auto& referenceType = downcast<AST::ReferenceType>(unnamedType);
auto mangledTypeName = m_typeNamer.mangledNameForType(referenceType.elementType());
stringBuilder.append(makeString("size_t ", lengthTemporaryName, " = ", variableName, '.', lengthElementName, ".x;\n"));
stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " << 32;\n"));
stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " | ", variableName, '.', lengthElementName, ".y;\n"));
stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " / sizeof(", mangledTypeName, ");\n"));
stringBuilder.append(makeString("if (", lengthTemporaryName, " > 0xFFFFFFFF) ", lengthTemporaryName, " = 0xFFFFFFFF;\n"));
stringBuilder.append(makeString(mangledInputPath(path), " = { ", variableName, '.', elementName, ", static_cast<uint32_t>(", lengthTemporaryName, ") };\n"));
} else {
auto& path = m_entryPointItems.inputs[iterator->value].path;
auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
stringBuilder.append(makeString(mangledInputPath(path), " = ", variableName, '.', elementName, ";\n"));
}
}
}
for (auto& namedBuiltIn : m_namedBuiltIns) {
auto& item = m_entryPointItems.inputs[namedBuiltIn.indexInEntryPointItems];
auto& path = item.path;
auto& variableName = namedBuiltIn.variableName;
auto mangledTypeName = m_typeNamer.mangledNameForType(*item.unnamedType);
stringBuilder.append(makeString(mangledInputPath(path), " = ", mangledTypeName, '(', variableName, ");\n"));
}
return stringBuilder.toString();
}
VertexEntryPointScaffolding::VertexEntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<String()>&& generateNextVariableName, HashMap<VertexAttribute*, size_t>& matchedVertexAttributes)
: EntryPointScaffolding(functionDefinition, intrinsics, typeNamer, entryPointItems, resourceMap, layout, WTFMove(generateNextVariableName))
, m_matchedVertexAttributes(matchedVertexAttributes)
, m_stageInStructName(typeNamer.generateNextTypeName())
, m_returnStructName(typeNamer.generateNextTypeName())
, m_stageInParameterName(m_generateNextVariableName())
{
m_namedStageIns.reserveInitialCapacity(m_matchedVertexAttributes.size());
for (auto& keyValuePair : m_matchedVertexAttributes) {
NamedStageIn namedStageIn;
namedStageIn.indexInEntryPointItems = keyValuePair.value;
namedStageIn.elementName = m_typeNamer.generateNextStructureElementName();
namedStageIn.attributeIndex = keyValuePair.key->metalLocation;
m_namedStageIns.uncheckedAppend(WTFMove(namedStageIn));
}
m_namedOutputs.reserveInitialCapacity(m_entryPointItems.outputs.size());
for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
auto& outputItem = m_entryPointItems.outputs[i];
NamedOutput namedOutput;
namedOutput.elementName = m_typeNamer.generateNextStructureElementName();
if (WTF::holds_alternative<AST::BuiltInSemantic>(*outputItem.semantic))
namedOutput.internalTypeName = internalTypeForSemantic(WTF::get<AST::BuiltInSemantic>(*outputItem.semantic));
if (namedOutput.internalTypeName.isNull())
namedOutput.internalTypeName = m_typeNamer.mangledNameForType(*outputItem.unnamedType);
m_namedOutputs.uncheckedAppend(WTFMove(namedOutput));
}
}
String VertexEntryPointScaffolding::helperTypes()
{
StringBuilder stringBuilder;
stringBuilder.append(makeString("struct ", m_stageInStructName, " {\n"));
for (auto& namedStageIn : m_namedStageIns) {
auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
auto elementName = namedStageIn.elementName;
auto attributeIndex = namedStageIn.attributeIndex;
stringBuilder.append(makeString(" ", mangledTypeName, ' ', elementName, " [[attribute(", attributeIndex, ")]];\n"));
}
stringBuilder.append("};\n\n");
stringBuilder.append(makeString("struct ", m_returnStructName, " {\n"));
for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
auto& outputItem = m_entryPointItems.outputs[i];
auto& internalTypeName = m_namedOutputs[i].internalTypeName;
auto elementName = m_namedOutputs[i].elementName;
auto attribute = attributeForSemantic(*outputItem.semantic);
stringBuilder.append(makeString(" ", internalTypeName, ' ', elementName, ' ', attribute, ";\n"));
}
stringBuilder.append("};\n\n");
stringBuilder.append(resourceHelperTypes());
return stringBuilder.toString();
}
String VertexEntryPointScaffolding::signature(String& functionName)
{
StringBuilder stringBuilder;
stringBuilder.append(makeString("vertex ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]"));
if (auto resourceSignature = this->resourceSignature())
stringBuilder.append(makeString(", ", *resourceSignature));
if (auto builtInsSignature = this->builtInsSignature())
stringBuilder.append(makeString(", ", *builtInsSignature));
stringBuilder.append(")");
return stringBuilder.toString();
}
String VertexEntryPointScaffolding::unpack()
{
StringBuilder stringBuilder;
stringBuilder.append(unpackResourcesAndNamedBuiltIns());
for (auto& namedStageIn : m_namedStageIns) {
auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
auto& elementName = namedStageIn.elementName;
stringBuilder.append(makeString(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n"));
}
return stringBuilder.toString();
}
String VertexEntryPointScaffolding::pack(const String& inputVariableName, const String& outputVariableName)
{
StringBuilder stringBuilder;
stringBuilder.append(makeString(m_returnStructName, ' ', outputVariableName, ";\n"));
if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
auto& elementName = m_namedOutputs[0].elementName;
stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n"));
return stringBuilder.toString();
}
for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
auto& elementName = m_namedOutputs[i].elementName;
auto& internalTypeName = m_namedOutputs[i].internalTypeName;
auto& path = m_entryPointItems.outputs[i].path;
stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n"));
}
return stringBuilder.toString();
}
FragmentEntryPointScaffolding::FragmentEntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<String()>&& generateNextVariableName, HashMap<AttachmentDescriptor*, size_t>&)
: EntryPointScaffolding(functionDefinition, intrinsics, typeNamer, entryPointItems, resourceMap, layout, WTFMove(generateNextVariableName))
, m_stageInStructName(typeNamer.generateNextTypeName())
, m_returnStructName(typeNamer.generateNextTypeName())
, m_stageInParameterName(m_generateNextVariableName())
{
for (size_t i = 0; i < m_entryPointItems.inputs.size(); ++i) {
auto& inputItem = m_entryPointItems.inputs[i];
if (!WTF::holds_alternative<AST::StageInOutSemantic>(*inputItem.semantic))
continue;
auto& stageInOutSemantic = WTF::get<AST::StageInOutSemantic>(*inputItem.semantic);
NamedStageIn namedStageIn;
namedStageIn.indexInEntryPointItems = i;
namedStageIn.elementName = m_typeNamer.generateNextStructureElementName();
namedStageIn.attributeIndex = stageInOutSemantic.index();
m_namedStageIns.append(WTFMove(namedStageIn));
}
m_namedOutputs.reserveInitialCapacity(m_entryPointItems.outputs.size());
for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
auto& outputItem = m_entryPointItems.outputs[i];
NamedOutput namedOutput;
namedOutput.elementName = m_typeNamer.generateNextStructureElementName();
if (WTF::holds_alternative<AST::BuiltInSemantic>(*outputItem.semantic))
namedOutput.internalTypeName = internalTypeForSemantic(WTF::get<AST::BuiltInSemantic>(*outputItem.semantic));
if (namedOutput.internalTypeName.isNull())
namedOutput.internalTypeName = m_typeNamer.mangledNameForType(*outputItem.unnamedType);
m_namedOutputs.uncheckedAppend(WTFMove(namedOutput));
}
}
String FragmentEntryPointScaffolding::helperTypes()
{
StringBuilder stringBuilder;
stringBuilder.append(makeString("struct ", m_stageInStructName, " {\n"));
for (auto& namedStageIn : m_namedStageIns) {
auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
auto elementName = namedStageIn.elementName;
auto attributeIndex = namedStageIn.attributeIndex;
stringBuilder.append(makeString(" ", mangledTypeName, ' ', elementName, " [[user(user", attributeIndex, ")]];\n"));
}
stringBuilder.append("};\n\n");
stringBuilder.append(makeString("struct ", m_returnStructName, " {\n"));
for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
auto& outputItem = m_entryPointItems.outputs[i];
auto& internalTypeName = m_namedOutputs[i].internalTypeName;
auto elementName = m_namedOutputs[i].elementName;
auto attribute = attributeForSemantic(*outputItem.semantic);
stringBuilder.append(makeString(" ", internalTypeName, ' ', elementName, ' ', attribute, ";\n"));
}
stringBuilder.append("};\n\n");
stringBuilder.append(resourceHelperTypes());
return stringBuilder.toString();
}
String FragmentEntryPointScaffolding::signature(String& functionName)
{
StringBuilder stringBuilder;
stringBuilder.append(makeString("fragment ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]"));
if (auto resourceSignature = this->resourceSignature())
stringBuilder.append(makeString(", ", *resourceSignature));
if (auto builtInsSignature = this->builtInsSignature())
stringBuilder.append(makeString(", ", *builtInsSignature));
stringBuilder.append(")");
return stringBuilder.toString();
}
String FragmentEntryPointScaffolding::unpack()
{
StringBuilder stringBuilder;
stringBuilder.append(unpackResourcesAndNamedBuiltIns());
for (auto& namedStageIn : m_namedStageIns) {
auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
auto& elementName = namedStageIn.elementName;
stringBuilder.append(makeString(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n"));
}
return stringBuilder.toString();
}
String FragmentEntryPointScaffolding::pack(const String& inputVariableName, const String& outputVariableName)
{
StringBuilder stringBuilder;
stringBuilder.append(makeString(m_returnStructName, ' ', outputVariableName, ";\n"));
if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
auto& elementName = m_namedOutputs[0].elementName;
stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n"));
return stringBuilder.toString();
}
for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
auto& elementName = m_namedOutputs[i].elementName;
auto& internalTypeName = m_namedOutputs[i].internalTypeName;
auto& path = m_entryPointItems.outputs[i].path;
stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n"));
}
return stringBuilder.toString();
}
ComputeEntryPointScaffolding::ComputeEntryPointScaffolding(AST::FunctionDefinition& functionDefinition, Intrinsics& intrinsics, TypeNamer& typeNamer, EntryPointItems& entryPointItems, HashMap<Binding*, size_t>& resourceMap, Layout& layout, std::function<String()>&& generateNextVariableName)
: EntryPointScaffolding(functionDefinition, intrinsics, typeNamer, entryPointItems, resourceMap, layout, WTFMove(generateNextVariableName))
{
}
String ComputeEntryPointScaffolding::helperTypes()
{
return resourceHelperTypes();
}
String ComputeEntryPointScaffolding::signature(String& functionName)
{
StringBuilder stringBuilder;
stringBuilder.append(makeString("kernel void ", functionName, '('));
bool empty = true;
if (auto resourceSignature = this->resourceSignature()) {
empty = false;
stringBuilder.append(makeString(*resourceSignature));
}
if (auto builtInsSignature = this->builtInsSignature()) {
if (!empty)
stringBuilder.append(", ");
stringBuilder.append(*builtInsSignature);
}
stringBuilder.append(")");
return stringBuilder.toString();
}
String ComputeEntryPointScaffolding::unpack()
{
return unpackResourcesAndNamedBuiltIns();
}
String ComputeEntryPointScaffolding::pack(const String&, const String&)
{
ASSERT_NOT_REACHED();
return String();
}
}
}
}
#endif