mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-28 22:52:06 +00:00
355 lines
12 KiB
C++
355 lines
12 KiB
C++
//
|
|
// Copyright(C) 2021 Advanced Micro Devices, 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:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 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.
|
|
//
|
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE
|
|
// COPYRIGHT HOLDERS OR 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.
|
|
//
|
|
|
|
#ifndef GLSLANG_WEB
|
|
|
|
//
|
|
// GL_EXT_spirv_intrinsics
|
|
//
|
|
#include "../Include/intermediate.h"
|
|
#include "../Include/SpirvIntrinsics.h"
|
|
#include "../Include/Types.h"
|
|
#include "ParseHelper.h"
|
|
|
|
namespace glslang {
|
|
|
|
//
|
|
// Handle SPIR-V requirements
|
|
//
|
|
TSpirvRequirement* TParseContext::makeSpirvRequirement(const TSourceLoc& loc, const TString& name,
|
|
const TIntermAggregate* extensions,
|
|
const TIntermAggregate* capabilities)
|
|
{
|
|
TSpirvRequirement* spirvReq = new TSpirvRequirement;
|
|
|
|
if (name == "extensions") {
|
|
assert(extensions);
|
|
for (auto extension : extensions->getSequence()) {
|
|
assert(extension->getAsConstantUnion());
|
|
spirvReq->extensions.insert(*extension->getAsConstantUnion()->getConstArray()[0].getSConst());
|
|
}
|
|
} else if (name == "capabilities") {
|
|
assert(capabilities);
|
|
for (auto capability : capabilities->getSequence()) {
|
|
assert(capability->getAsConstantUnion());
|
|
spirvReq->capabilities.insert(capability->getAsConstantUnion()->getConstArray()[0].getIConst());
|
|
}
|
|
} else
|
|
error(loc, "unknow SPIR-V requirement", name.c_str(), "");
|
|
|
|
return spirvReq;
|
|
}
|
|
|
|
TSpirvRequirement* TParseContext::mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1,
|
|
TSpirvRequirement* spirvReq2)
|
|
{
|
|
// Merge the second SPIR-V requirement to the first one
|
|
if (!spirvReq2->extensions.empty()) {
|
|
if (spirvReq1->extensions.empty())
|
|
spirvReq1->extensions = spirvReq2->extensions;
|
|
else
|
|
error(loc, "too many SPIR-V requirements", "extensions", "");
|
|
}
|
|
|
|
if (!spirvReq2->capabilities.empty()) {
|
|
if (spirvReq1->capabilities.empty())
|
|
spirvReq1->capabilities = spirvReq2->capabilities;
|
|
else
|
|
error(loc, "too many SPIR-V requirements", "capabilities", "");
|
|
}
|
|
|
|
return spirvReq1;
|
|
}
|
|
|
|
void TIntermediate::insertSpirvRequirement(const TSpirvRequirement* spirvReq)
|
|
{
|
|
if (!spirvRequirement)
|
|
spirvRequirement = new TSpirvRequirement;
|
|
|
|
for (auto extension : spirvReq->extensions)
|
|
spirvRequirement->extensions.insert(extension);
|
|
|
|
for (auto capability : spirvReq->capabilities)
|
|
spirvRequirement->capabilities.insert(capability);
|
|
}
|
|
|
|
//
|
|
// Handle SPIR-V execution modes
|
|
//
|
|
void TIntermediate::insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args)
|
|
{
|
|
if (!spirvExecutionMode)
|
|
spirvExecutionMode = new TSpirvExecutionMode;
|
|
|
|
TVector<const TIntermConstantUnion*> extraOperands;
|
|
if (args) {
|
|
for (auto arg : args->getSequence()) {
|
|
auto extraOperand = arg->getAsConstantUnion();
|
|
assert(extraOperand != nullptr);
|
|
extraOperands.push_back(extraOperand);
|
|
}
|
|
}
|
|
spirvExecutionMode->modes[executionMode] = extraOperands;
|
|
}
|
|
|
|
void TIntermediate::insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args)
|
|
{
|
|
if (!spirvExecutionMode)
|
|
spirvExecutionMode = new TSpirvExecutionMode;
|
|
|
|
assert(args);
|
|
TVector<const TIntermConstantUnion*> extraOperands;
|
|
|
|
for (auto arg : args->getSequence()) {
|
|
auto extraOperand = arg->getAsConstantUnion();
|
|
assert(extraOperand != nullptr);
|
|
extraOperands.push_back(extraOperand);
|
|
}
|
|
spirvExecutionMode->modeIds[executionMode] = extraOperands;
|
|
}
|
|
|
|
//
|
|
// Handle SPIR-V decorate qualifiers
|
|
//
|
|
void TQualifier::setSpirvDecorate(int decoration, const TIntermAggregate* args)
|
|
{
|
|
if (!spirvDecorate)
|
|
spirvDecorate = new TSpirvDecorate;
|
|
|
|
TVector<const TIntermConstantUnion*> extraOperands;
|
|
if (args) {
|
|
for (auto arg : args->getSequence()) {
|
|
auto extraOperand = arg->getAsConstantUnion();
|
|
assert(extraOperand != nullptr);
|
|
extraOperands.push_back(extraOperand);
|
|
}
|
|
}
|
|
spirvDecorate->decorates[decoration] = extraOperands;
|
|
}
|
|
|
|
void TQualifier::setSpirvDecorateId(int decoration, const TIntermAggregate* args)
|
|
{
|
|
if (!spirvDecorate)
|
|
spirvDecorate = new TSpirvDecorate;
|
|
|
|
assert(args);
|
|
TVector<const TIntermConstantUnion*> extraOperands;
|
|
for (auto arg : args->getSequence()) {
|
|
auto extraOperand = arg->getAsConstantUnion();
|
|
assert(extraOperand != nullptr);
|
|
extraOperands.push_back(extraOperand);
|
|
}
|
|
spirvDecorate->decorateIds[decoration] = extraOperands;
|
|
}
|
|
|
|
void TQualifier::setSpirvDecorateString(int decoration, const TIntermAggregate* args)
|
|
{
|
|
if (!spirvDecorate)
|
|
spirvDecorate = new TSpirvDecorate;
|
|
|
|
assert(args);
|
|
TVector<const TIntermConstantUnion*> extraOperands;
|
|
for (auto arg : args->getSequence()) {
|
|
auto extraOperand = arg->getAsConstantUnion();
|
|
assert(extraOperand != nullptr);
|
|
extraOperands.push_back(extraOperand);
|
|
}
|
|
spirvDecorate->decorateStrings[decoration] = extraOperands;
|
|
}
|
|
|
|
TString TQualifier::getSpirvDecorateQualifierString() const
|
|
{
|
|
assert(spirvDecorate);
|
|
|
|
TString qualifierString;
|
|
|
|
const auto appendFloat = [&](float f) { qualifierString.append(std::to_string(f).c_str()); };
|
|
const auto appendInt = [&](int i) { qualifierString.append(std::to_string(i).c_str()); };
|
|
const auto appendUint = [&](unsigned int u) { qualifierString.append(std::to_string(u).c_str()); };
|
|
const auto appendBool = [&](bool b) { qualifierString.append(std::to_string(b).c_str()); };
|
|
const auto appendStr = [&](const char* s) { qualifierString.append(s); };
|
|
|
|
const auto appendDecorate = [&](const TIntermConstantUnion* constant) {
|
|
if (constant->getBasicType() == EbtFloat) {
|
|
float value = static_cast<float>(constant->getConstArray()[0].getDConst());
|
|
appendFloat(value);
|
|
}
|
|
else if (constant->getBasicType() == EbtInt) {
|
|
int value = constant->getConstArray()[0].getIConst();
|
|
appendInt(value);
|
|
}
|
|
else if (constant->getBasicType() == EbtUint) {
|
|
unsigned value = constant->getConstArray()[0].getUConst();
|
|
appendUint(value);
|
|
}
|
|
else if (constant->getBasicType() == EbtBool) {
|
|
bool value = constant->getConstArray()[0].getBConst();
|
|
appendBool(value);
|
|
}
|
|
else if (constant->getBasicType() == EbtString) {
|
|
const TString* value = constant->getConstArray()[0].getSConst();
|
|
appendStr(value->c_str());
|
|
}
|
|
else
|
|
assert(0);
|
|
};
|
|
|
|
for (auto& decorate : spirvDecorate->decorates) {
|
|
appendStr("spirv_decorate(");
|
|
appendInt(decorate.first);
|
|
for (auto extraOperand : decorate.second) {
|
|
appendStr(", ");
|
|
appendDecorate(extraOperand);
|
|
}
|
|
appendStr(") ");
|
|
}
|
|
|
|
for (auto& decorateId : spirvDecorate->decorateIds) {
|
|
appendStr("spirv_decorate_id(");
|
|
appendInt(decorateId.first);
|
|
for (auto extraOperand : decorateId.second) {
|
|
appendStr(", ");
|
|
appendDecorate(extraOperand);
|
|
}
|
|
appendStr(") ");
|
|
}
|
|
|
|
for (auto& decorateString : spirvDecorate->decorateStrings) {
|
|
appendStr("spirv_decorate_string(");
|
|
appendInt(decorateString.first);
|
|
for (auto extraOperand : decorateString.second) {
|
|
appendStr(", ");
|
|
appendDecorate(extraOperand);
|
|
}
|
|
appendStr(") ");
|
|
}
|
|
|
|
return qualifierString;
|
|
}
|
|
|
|
//
|
|
// Handle SPIR-V type specifiers
|
|
//
|
|
void TPublicType::setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams)
|
|
{
|
|
if (!spirvType)
|
|
spirvType = new TSpirvType;
|
|
|
|
basicType = EbtSpirvType;
|
|
spirvType->spirvInst = spirvInst;
|
|
if (typeParams)
|
|
spirvType->typeParams = *typeParams;
|
|
}
|
|
|
|
TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant)
|
|
{
|
|
TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters;
|
|
if (constant->getBasicType() != EbtFloat &&
|
|
constant->getBasicType() != EbtInt &&
|
|
constant->getBasicType() != EbtUint &&
|
|
constant->getBasicType() != EbtBool &&
|
|
constant->getBasicType() != EbtString)
|
|
error(loc, "this type not allowed", constant->getType().getBasicString(), "");
|
|
else {
|
|
assert(constant);
|
|
spirvTypeParams->push_back(TSpirvTypeParameter(constant));
|
|
}
|
|
|
|
return spirvTypeParams;
|
|
}
|
|
|
|
TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TPublicType& type)
|
|
{
|
|
TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters;
|
|
spirvTypeParams->push_back(TSpirvTypeParameter(new TType(type)));
|
|
return spirvTypeParams;
|
|
}
|
|
|
|
TSpirvTypeParameters* TParseContext::mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2)
|
|
{
|
|
// Merge SPIR-V type parameters of the second one to the first one
|
|
for (const auto& spirvTypeParam : *spirvTypeParams2)
|
|
spirvTypeParams1->push_back(spirvTypeParam);
|
|
return spirvTypeParams1;
|
|
}
|
|
|
|
//
|
|
// Handle SPIR-V instruction qualifiers
|
|
//
|
|
TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value)
|
|
{
|
|
TSpirvInstruction* spirvInst = new TSpirvInstruction;
|
|
if (name == "set")
|
|
spirvInst->set = value;
|
|
else
|
|
error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), "");
|
|
|
|
return spirvInst;
|
|
}
|
|
|
|
TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value)
|
|
{
|
|
TSpirvInstruction* spirvInstuction = new TSpirvInstruction;
|
|
if (name == "id")
|
|
spirvInstuction->id = value;
|
|
else
|
|
error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), "");
|
|
|
|
return spirvInstuction;
|
|
}
|
|
|
|
TSpirvInstruction* TParseContext::mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, TSpirvInstruction* spirvInst2)
|
|
{
|
|
// Merge qualifiers of the second SPIR-V instruction to those of the first one
|
|
if (!spirvInst2->set.empty()) {
|
|
if (spirvInst1->set.empty())
|
|
spirvInst1->set = spirvInst2->set;
|
|
else
|
|
error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(set)");
|
|
}
|
|
|
|
if (spirvInst2->id != -1) {
|
|
if (spirvInst1->id == -1)
|
|
spirvInst1->id = spirvInst2->id;
|
|
else
|
|
error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(id)");
|
|
}
|
|
|
|
return spirvInst1;
|
|
}
|
|
|
|
} // end namespace glslang
|
|
|
|
#endif // GLSLANG_WEB
|