blob: 9e177c4109508487d14d6df9441bb5ec5a6c1594 [file]
//
// Copyright 2024 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
//
// clspv_utils:
// Utilities to map clspv interface variables to OpenCL and Vulkan mappings.
//
#ifndef LIBANGLE_RENDERER_VULKAN_CLSPV_UTILS_H_
#define LIBANGLE_RENDERER_VULKAN_CLSPV_UTILS_H_
#include <libANGLE/renderer/vulkan/CLDeviceVk.h>
#include "clspv/Compiler.h"
#include "clspv/Sampler.h"
#include "spirv-tools/libspirv.h"
#include <vulkan/vulkan_core.h>
#include <string>
#include <vector>
namespace rx
{
struct ClspvPrintfBufferStorage
{
uint32_t descriptorSet = 0;
uint32_t binding = 0;
uint32_t pcOffset = 0;
uint32_t size = 0;
};
struct ClspvPrintfInfo
{
uint32_t id = 0;
std::string formatSpecifier;
std::vector<uint32_t> argSizes;
};
struct ClspvLiteralSampler
{
uint32_t descriptorSet;
uint32_t binding;
cl_bool normalizedCoords;
cl::AddressingMode addressingMode;
cl::FilterMode filterMode;
};
struct ClspvConstantDataBufferInfo
{
uint32_t set;
uint32_t binding;
uint32_t pcOffset;
std::vector<uint8_t> bufferData;
};
struct ClspvWorkgroupVariableSize
{
uint32_t size = 0;
};
// TODO: Look into moving this information in CLKernelArgument
// https://anglebug.com/378514267
struct ClspvImagePushConstant
{
VkPushConstantRange pcRange;
uint32_t ordinal;
};
// Information as encoded by the clspv ArgumentInfo reflection instruction
// https://github.khronos.org/SPIRV-Registry/nonsemantic/NonSemantic.ClspvReflection.html#ArgumentInfo
struct ClspvArgumentInfo
{
std::string name;
std::string typeName;
cl_kernel_arg_address_qualifier addressQualifier = 0u;
cl_kernel_arg_access_qualifier accessQualifier = 0u;
cl_kernel_arg_type_qualifier typeQualifier = 0u;
};
// This captures all in information that is available from the clspv compiled binary related to a
// kernel argument
// - ClspvArgumentInfo
// - Reflection type
// - Descriptor set/push constant offset
// - Descriptor binding/push constant size
// - pod buffer offset
// - pod buffer size
struct ClspvKernelArgument
{
ClspvArgumentInfo info{};
uint32_t type = 0;
uint32_t ordinal = 0;
size_t handleSize = 0;
void *handle = nullptr;
bool used = false;
// Shared operand words/regions for "OpExtInst" type spv instructions
// (starts from spv word index/offset 7 and onward)
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExtInst
// https://github.com/google/clspv/blob/main/docs/OpenCLCOnVulkan.md#kernels
union
{
uint32_t op3;
uint32_t descriptorSet;
uint32_t pushConstOffset;
uint32_t workgroupBufferSpecId;
};
union
{
uint32_t op4;
uint32_t descriptorBinding;
uint32_t pushConstantSize;
uint32_t workgroupBufferElemSize;
};
union
{
uint32_t op5;
uint32_t podStorageBufferOffset;
uint32_t podUniformOffset;
uint32_t pointerUniformOffset;
};
union
{
uint32_t op6;
uint32_t podStorageBufferSize;
uint32_t podUniformSize;
uint32_t pointerUniformSize;
};
};
using ClspvKernelArguments = std::vector<ClspvKernelArgument>;
using ClspvKernelArgsMap = angle::HashMap<std::string, ClspvKernelArguments>;
struct ClspvReflectionData
{
angle::HashMap<uint32_t, uint32_t> spvIntLookup;
angle::HashMap<uint32_t, std::string> spvStrLookup;
// The ArgumentInfo is setup as a separate reflection instruction
// %a = OpExtInst %b %c ArgumentInfo %d [ %e %f %g %h ]
// The instruction itself doesn't encode the variable information
// instead this is attached as a tag to the appropriate resource
// Here we store the map of <a, ClspvArgumentInfo> for later processing
angle::HashMap<uint32_t, ClspvArgumentInfo> kernelArgInfos;
// A map of kernel name to kernel arguments
ClspvKernelArgsMap kernelArgsMap;
// Temporary store for any out of order processing on the kernel arguments
// map of kernel name to single kernel argument
angle::HashMap<std::string, ClspvKernelArgument> kernelArgMap;
angle::HashMap<std::string, uint32_t> kernelFlags;
angle::HashMap<std::string, std::string> kernelAttributes;
angle::HashMap<std::string, std::array<uint32_t, 3>> kernelCompileWorkgroupSize;
angle::HashMap<uint32_t, VkPushConstantRange> pushConstants;
angle::PackedEnumMap<SpecConstantType, uint32_t> specConstantIDs;
angle::PackedEnumBitSet<SpecConstantType, uint32_t> specConstantsUsed;
angle::HashMap<uint32_t, std::vector<ClspvImagePushConstant>> imagePushConstants;
angle::HashSet<uint32_t> kernelIDs;
// Printf buffer related info
ClspvPrintfBufferStorage printfBufferStorage;
angle::HashMap<uint32_t, ClspvPrintfInfo> printfInfoMap;
std::vector<ClspvLiteralSampler> literalSamplers;
ClspvConstantDataBufferInfo constantDataBufferInfo;
ClspvWorkgroupVariableSize workgroupVariableSize;
};
namespace clspv_cl
{
cl::AddressingMode GetAddressingMode(uint32_t mask);
cl::FilterMode GetFilterMode(uint32_t mask);
inline bool IsNormalizedCoords(uint32_t mask)
{
return (mask & clspv::kSamplerNormalizedCoordsMask) == clspv::CLK_NORMALIZED_COORDS_TRUE;
}
} // namespace clspv_cl
angle::Result ClspvProcessPrintfBuffer(unsigned char *buffer,
const size_t bufferSize,
const angle::HashMap<uint32_t, ClspvPrintfInfo> *infoMap);
// Populate a list of options that can be supported by clspv based on the features supported by the
// vulkan renderer.
std::string ClspvGetCompilerOptions(const CLDeviceVk *device);
ClspvError ClspvCompileSource(const size_t programCount,
const size_t *programSizes,
const char **programs,
const char *options,
char **outputBinary,
size_t *outputBinarySize,
char **outputLog);
spv_target_env ClspvGetSpirvVersion(const vk::Renderer *renderer);
bool ClspvValidate(vk::Renderer *rendererVk, const angle::spirv::Blob &blob);
bool ClspvParseReflection(vk::Renderer *rendererVk,
const angle::spirv::Blob &blob,
ClspvReflectionData &reflectionDataOut);
bool ClspvStripReflection(vk::Renderer *rendererVk,
const angle::spirv::Blob &inBlob,
angle::spirv::Blob &outBlob);
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_CLSPV_UTILS_H_