blob: 6b7f524e2236df25b5ea5ae14327b2e803c3b6ea [file]
//
// Copyright 2021 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.
//
// CLProgramVk.cpp: Implements the class methods for CLProgramVk.
//
#ifdef UNSAFE_BUFFERS_BUILD
# pragma allow_unsafe_buffers
#endif
#include "libANGLE/renderer/vulkan/CLProgramVk.h"
#include "libANGLE/renderer/vulkan/CLContextVk.h"
#include "libANGLE/renderer/vulkan/cl_types.h"
#include "libANGLE/renderer/vulkan/clspv_utils.h"
#include "libANGLE/CLBuffer.h"
#include "libANGLE/CLContext.h"
#include "libANGLE/CLKernel.h"
#include "libANGLE/CLProgram.h"
#include "libANGLE/cl_utils.h"
#include "clspv/Compiler.h"
namespace rx
{
namespace
{
#if defined(ANGLE_ENABLE_ASSERTS)
constexpr bool kAngleDebug = true;
#else
constexpr bool kAngleDebug = false;
#endif
std::string ProcessBuildOptions(const std::vector<std::string> &optionTokens,
CLProgramVk::BuildType buildType)
{
std::string processedOptions;
// Need to remove/replace options that are not 1-1 mapped to clspv
for (const std::string &optionToken : optionTokens)
{
if (optionToken == "-create-library" && buildType == CLProgramVk::BuildType::LINK)
{
processedOptions += " --output-format=bc";
continue;
}
else if (optionToken == "-cl-std=CL2.0")
{
processedOptions += " -cl-std=CL2.0 -inline-entry-points";
continue;
}
processedOptions += " " + optionToken;
}
switch (buildType)
{
case CLProgramVk::BuildType::COMPILE:
processedOptions += " --output-format=bc";
break;
case CLProgramVk::BuildType::LINK:
processedOptions += " -x ir";
break;
default:
break;
}
return processedOptions;
}
} // namespace
void CLAsyncBuildTask::operator()()
{
ANGLE_TRACE_EVENT0("gpu.angle", "CLProgramVk::buildInternal (async)");
CLProgramVk::ScopedProgramCallback spc(mNotify);
if (!mProgramVk->buildInternal(mDevices, mOptions, mInternalOptions, mBuildType,
mLinkProgramsList))
{
ERR() << "Async build failed for program (" << mProgramVk
<< ")! Check the build status or build log for details.";
}
}
CLProgramVk::CLProgramVk(const cl::Program &program)
: CLProgramImpl(program),
mContext(&program.getContext().getImpl<CLContextVk>()),
mAsyncBuildEvent(std::make_shared<angle::WaitableEventDone>()),
mModuleConstantDataBuffer(nullptr)
{}
angle::Result CLProgramVk::init()
{
cl::DevicePtrs devices;
ANGLE_TRY(mContext->getDevices(&devices));
// The devices associated with the program object are the devices associated with context
for (const cl::DevicePtr &device : devices)
{
DeviceProgramData deviceProgramData{};
mAssociatedDevicePrograms[device->getNative()] = std::move(deviceProgramData);
}
return angle::Result::Continue;
}
angle::Result CLProgramVk::init(const size_t *lengths,
const unsigned char **binaries,
cl_int *binaryStatus)
{
// The devices associated with program come from device_list param from
// clCreateProgramWithBinary
for (const cl::DevicePtr &device : mProgram.getDevices())
{
const unsigned char *binaryHandle = *binaries++;
size_t binarySize = *lengths++;
// Check for header
if (binarySize < sizeof(ProgramBinaryOutputHeader))
{
if (binaryStatus)
{
*binaryStatus++ = CL_INVALID_BINARY;
}
ANGLE_CL_RETURN_ERROR(CL_INVALID_BINARY);
}
binarySize -= sizeof(ProgramBinaryOutputHeader);
// Check for valid binary version from header
const ProgramBinaryOutputHeader *binaryHeader =
reinterpret_cast<const ProgramBinaryOutputHeader *>(binaryHandle);
if (binaryHeader == nullptr)
{
ERR() << "NULL binary header!";
if (binaryStatus)
{
*binaryStatus++ = CL_INVALID_BINARY;
}
ANGLE_CL_RETURN_ERROR(CL_INVALID_BINARY);
}
else if (binaryHeader->headerVersion < kBinaryVersion)
{
ERR() << "Binary version not compatible with runtime!";
if (binaryStatus)
{
*binaryStatus++ = CL_INVALID_BINARY;
}
ANGLE_CL_RETURN_ERROR(CL_INVALID_BINARY);
}
binaryHandle += sizeof(ProgramBinaryOutputHeader);
// See what kind of binary we have (i.e. SPIR-V or LLVM Bitcode)
// https://llvm.org/docs/BitCodeFormat.html#llvm-ir-magic-number
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_magic_number
constexpr uint32_t LLVM_BC_MAGIC = 0xDEC04342;
constexpr uint32_t SPIRV_MAGIC = 0x07230203;
const uint32_t &firstWord = reinterpret_cast<const uint32_t *>(binaryHandle)[0];
bool isBC = firstWord == LLVM_BC_MAGIC;
bool isSPV = firstWord == SPIRV_MAGIC;
if (!isBC && !isSPV)
{
ERR() << "Binary is neither SPIR-V nor LLVM Bitcode!";
if (binaryStatus)
{
*binaryStatus++ = CL_INVALID_BINARY;
}
ANGLE_CL_RETURN_ERROR(CL_INVALID_BINARY);
}
// Add device binary to program
DeviceProgramData deviceBinary;
deviceBinary.spirvVersion = device->getImpl<CLDeviceVk>().getSpirvVersion();
deviceBinary.binaryType = binaryHeader->binaryType;
deviceBinary.buildStatus = binaryHeader->buildStatus;
switch (deviceBinary.binaryType)
{
case CL_PROGRAM_BINARY_TYPE_EXECUTABLE:
deviceBinary.binary.assign(binarySize / sizeof(uint32_t), 0);
std::memcpy(deviceBinary.binary.data(), binaryHandle, binarySize);
break;
case CL_PROGRAM_BINARY_TYPE_LIBRARY:
case CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT:
deviceBinary.IR.assign(binarySize, 0);
std::memcpy(deviceBinary.IR.data(), binaryHandle, binarySize);
break;
default:
UNREACHABLE();
ERR() << "Invalid binary type!";
if (binaryStatus)
{
*binaryStatus++ = CL_INVALID_BINARY;
}
ANGLE_CL_RETURN_ERROR(CL_INVALID_BINARY);
}
mAssociatedDevicePrograms[device->getNative()] = std::move(deviceBinary);
if (binaryStatus)
{
*binaryStatus++ = CL_SUCCESS;
}
}
return angle::Result::Continue;
}
CLProgramVk::~CLProgramVk() {}
angle::Result CLProgramVk::build(const cl::DevicePtrs &devices,
const char *options,
cl::Program *notify)
{
BuildType buildType = !mProgram.getSource().empty() ? BuildType::BUILD : BuildType::BINARY;
const cl::DevicePtrs &devicePtrs = !devices.empty() ? devices : mProgram.getDevices();
setBuildStatus(devicePtrs, CL_BUILD_IN_PROGRESS);
if (notify)
{
mAsyncBuildEvent =
getPlatform()->postMultiThreadWorkerTask(std::make_shared<CLAsyncBuildTask>(
this, devicePtrs, std::string(options ? options : ""), "", buildType,
LinkProgramsList{}, notify));
ASSERT(mAsyncBuildEvent != nullptr);
}
else
{
if (!buildInternal(devicePtrs, std::string(options ? options : ""), "", buildType,
LinkProgramsList{}))
{
ANGLE_CL_RETURN_ERROR(CL_BUILD_PROGRAM_FAILURE);
}
}
return angle::Result::Continue;
}
angle::Result CLProgramVk::compile(const cl::DevicePtrs &devices,
const char *options,
const cl::ProgramPtrs &inputHeaders,
const char **headerIncludeNames,
cl::Program *notify)
{
const cl::DevicePtrs &devicePtrs = !devices.empty() ? devices : mProgram.getDevices();
// Ensure OS temp dir is available
std::string internalCompileOpts;
Optional<std::string> tmpDir = angle::GetTempDirectory();
if (!tmpDir.valid())
{
ERR() << "Failed to open OS temp dir";
ANGLE_CL_RETURN_ERROR(CL_INVALID_OPERATION);
}
internalCompileOpts += inputHeaders.empty() ? "" : " -I" + tmpDir.value();
// Dump input headers to OS temp directory
for (size_t i = 0; i < inputHeaders.size(); ++i)
{
const std::string &inputHeaderSrc =
inputHeaders.at(i)->getImpl<CLProgramVk>().mProgram.getSource();
std::string headerFilePath(angle::ConcatenatePath(tmpDir.value(), headerIncludeNames[i]));
// Sanitize path so we can use "/" as universal path separator
angle::MakeForwardSlashThePathSeparator(headerFilePath);
size_t baseDirPos = headerFilePath.find_last_of("/");
// Ensure parent dir(s) exists
if (!angle::CreateDirectories(headerFilePath.substr(0, baseDirPos)))
{
ERR() << "Failed to create output path(s) for header(s)!";
ANGLE_CL_RETURN_ERROR(CL_INVALID_OPERATION);
}
writeFile(headerFilePath.c_str(), inputHeaderSrc);
}
setBuildStatus(devicePtrs, CL_BUILD_IN_PROGRESS);
// Perform compile
if (notify)
{
mAsyncBuildEvent = mProgram.getContext().getPlatform().getMultiThreadPool()->postWorkerTask(
std::make_shared<CLAsyncBuildTask>(
this, devicePtrs, std::string(options ? options : ""), internalCompileOpts,
BuildType::COMPILE, LinkProgramsList{}, notify));
ASSERT(mAsyncBuildEvent != nullptr);
}
else
{
mAsyncBuildEvent = std::make_shared<angle::WaitableEventDone>();
if (!buildInternal(devicePtrs, std::string(options ? options : ""), internalCompileOpts,
BuildType::COMPILE, LinkProgramsList{}))
{
ANGLE_CL_RETURN_ERROR(CL_COMPILE_PROGRAM_FAILURE);
}
}
return angle::Result::Continue;
}
angle::Result CLProgramVk::getInfo(cl::ProgramInfo name,
size_t valueSize,
void *value,
size_t *valueSizeRet) const
{
cl_uint valUInt = 0u;
cl_bool valBool = CL_FALSE;
void *valPointer = nullptr;
const void *copyValue = nullptr;
size_t copySize = 0u;
unsigned char **outputBins = reinterpret_cast<unsigned char **>(value);
std::string kernelNamesList;
std::vector<size_t> vBinarySizes;
switch (name)
{
case cl::ProgramInfo::NumKernels:
for (const auto &deviceProgram : mAssociatedDevicePrograms)
{
valUInt += static_cast<decltype(valUInt)>(deviceProgram.second.numKernels());
}
copyValue = &valUInt;
copySize = sizeof(valUInt);
break;
case cl::ProgramInfo::BinarySizes:
{
for (const auto &deviceProgram : mAssociatedDevicePrograms)
{
vBinarySizes.push_back(
sizeof(ProgramBinaryOutputHeader) +
(deviceProgram.second.binaryType == CL_PROGRAM_BINARY_TYPE_EXECUTABLE
? deviceProgram.second.binary.size() * sizeof(uint32_t)
: deviceProgram.second.IR.size()));
}
valPointer = vBinarySizes.data();
copyValue = valPointer;
copySize = vBinarySizes.size() * sizeof(size_t);
break;
}
case cl::ProgramInfo::Binaries:
for (const auto &deviceProgram : mAssociatedDevicePrograms)
{
const void *bin =
deviceProgram.second.binaryType == CL_PROGRAM_BINARY_TYPE_EXECUTABLE
? reinterpret_cast<const void *>(deviceProgram.second.binary.data())
: reinterpret_cast<const void *>(deviceProgram.second.IR.data());
size_t binSize =
deviceProgram.second.binaryType == CL_PROGRAM_BINARY_TYPE_EXECUTABLE
? deviceProgram.second.binary.size() * sizeof(uint32_t)
: deviceProgram.second.IR.size();
ProgramBinaryOutputHeader header{.headerVersion = kBinaryVersion,
.binaryType = deviceProgram.second.binaryType,
.buildStatus = deviceProgram.second.buildStatus};
if (outputBins != nullptr)
{
if (*outputBins != nullptr)
{
std::memcpy(*outputBins, &header, sizeof(ProgramBinaryOutputHeader));
std::memcpy((*outputBins) + sizeof(ProgramBinaryOutputHeader), bin,
binSize);
}
outputBins++;
}
// Spec just wants pointer size here
copySize += sizeof(unsigned char *);
}
// We already copied the (headers + binaries) over - nothing else left to copy
copyValue = nullptr;
break;
case cl::ProgramInfo::KernelNames:
for (const auto &deviceProgram : mAssociatedDevicePrograms)
{
kernelNamesList = deviceProgram.second.getKernelNames();
}
valPointer = kernelNamesList.data();
copyValue = valPointer;
copySize = kernelNamesList.size() + 1;
break;
case cl::ProgramInfo::ScopeGlobalCtorsPresent:
case cl::ProgramInfo::ScopeGlobalDtorsPresent:
// These are deprecated by version 3.0 and are currently not supported
copyValue = &valBool;
copySize = sizeof(cl_bool);
break;
default:
UNREACHABLE();
}
if ((value != nullptr) && (copyValue != nullptr))
{
std::memcpy(value, copyValue, copySize);
}
if (valueSizeRet != nullptr)
{
*valueSizeRet = copySize;
}
return angle::Result::Continue;
}
angle::Result CLProgramVk::getBuildInfo(const cl::Device &device,
cl::ProgramBuildInfo name,
size_t valueSize,
void *value,
size_t *valueSizeRet) const
{
cl_uint valUInt = 0;
cl_build_status valStatus = 0;
const void *copyValue = nullptr;
size_t copySize = 0;
const DeviceProgramData *deviceProgramData = getDeviceProgramData(device.getNative());
switch (name)
{
case cl::ProgramBuildInfo::Status:
valStatus = deviceProgramData->buildStatus;
copyValue = &valStatus;
copySize = sizeof(valStatus);
break;
case cl::ProgramBuildInfo::Log:
copyValue = deviceProgramData->buildLog.c_str();
copySize = deviceProgramData->buildLog.size() + 1;
break;
case cl::ProgramBuildInfo::Options:
copyValue = mProgramOpts.c_str();
copySize = mProgramOpts.size() + 1;
break;
case cl::ProgramBuildInfo::BinaryType:
valUInt = deviceProgramData->binaryType;
copyValue = &valUInt;
copySize = sizeof(valUInt);
break;
case cl::ProgramBuildInfo::GlobalVariableTotalSize:
// Returns 0 if device does not support program scope global variables.
valUInt = 0;
copyValue = &valUInt;
copySize = sizeof(valUInt);
break;
default:
UNREACHABLE();
}
if ((value != nullptr) && (copyValue != nullptr))
{
memcpy(value, copyValue, std::min(valueSize, copySize));
}
if (valueSizeRet != nullptr)
{
*valueSizeRet = copySize;
}
return angle::Result::Continue;
}
angle::Result CLProgramVk::createKernel(const cl::Kernel &kernel,
const char *name,
CLKernelImpl::Ptr *kernelOut)
{
// Wait for the compile to finish
mAsyncBuildEvent->wait();
std::scoped_lock<angle::SimpleMutex> sl(mProgramMutex);
const auto devProgram = getDeviceProgramData(name);
ASSERT(devProgram != nullptr);
// Create kernel
std::string kernelAttributes = devProgram->getKernelAttributes(name);
std::string kernelName = std::string(name ? name : "");
CLKernelVk::Ptr kernelImpl =
CLKernelVk::Ptr(new (std::nothrow) CLKernelVk(kernel, kernelName, kernelAttributes));
if (kernelImpl == nullptr)
{
ERR() << "Could not create kernel obj!";
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
ANGLE_TRY(kernelImpl->init());
*kernelOut = std::move(kernelImpl);
return angle::Result::Continue;
}
angle::Result CLProgramVk::createKernels(cl_uint numKernels,
CLKernelImpl::CreateFuncs &createFuncs,
cl_uint *numKernelsRet)
{
size_t numDevKernels = 0;
for (const auto &dev : mAssociatedDevicePrograms)
{
numDevKernels += dev.second.numKernels();
}
if (numKernelsRet != nullptr)
{
*numKernelsRet = static_cast<cl_uint>(numDevKernels);
}
if (numKernels != 0)
{
for (const auto &dev : mAssociatedDevicePrograms)
{
for (const auto &kernArgMap : dev.second.getKernelArgsMap())
{
createFuncs.emplace_back([this, &kernArgMap](const cl::Kernel &kern) {
CLKernelImpl::Ptr implPtr = nullptr;
ANGLE_CL_IMPL_TRY(this->createKernel(kern, kernArgMap.first.c_str(), &implPtr));
return CLKernelImpl::Ptr(std::move(implPtr));
});
}
}
}
return angle::Result::Continue;
}
const CLProgramVk::DeviceProgramData *CLProgramVk::getDeviceProgramData(
const _cl_device_id *device) const
{
if (!mAssociatedDevicePrograms.contains(device))
{
WARN() << "Device (" << device << ") is not associated with program (" << this << ") !";
return nullptr;
}
return &mAssociatedDevicePrograms.at(device);
}
const CLProgramVk::DeviceProgramData *CLProgramVk::getDeviceProgramData(
const char *kernelName) const
{
for (const auto &deviceProgram : mAssociatedDevicePrograms)
{
if (deviceProgram.second.containsKernel(kernelName))
{
return &deviceProgram.second;
}
}
WARN() << "Kernel name (" << kernelName << ") is not associated with program (" << this
<< ") !";
return nullptr;
}
cl::BufferPtr CLProgramVk::getOrCreateModuleConstantDataBuffer(const std::string &kernelName)
{
const DeviceProgramData *devProgram = getDeviceProgramData(kernelName.c_str());
ASSERT(devProgram);
const std::vector<uint8_t> &initData =
devProgram->reflectionData.constantDataBufferInfo.bufferData;
void *initDataPtr = reinterpret_cast<void *>(const_cast<uint8_t *>(initData.data()));
if (!mModuleConstantDataBuffer)
{
mModuleConstantDataBuffer = cl::BufferPtr::Create(
const_cast<cl::Context &>(mProgram.getContext()), cl::Memory::PropArray{},
cl::MemFlags(CL_MEM_USE_HOST_PTR), initData.size(), initDataPtr);
}
else
{
// reading that this buffer is already present and is sufficient to hold initData
ASSERT(mModuleConstantDataBuffer->getSize() == initData.size());
}
return mModuleConstantDataBuffer;
}
bool CLProgramVk::buildInternal(const cl::DevicePtrs &devices,
std::string options,
std::string internalOptions,
BuildType buildType,
const LinkProgramsList &LinkProgramsList)
{
std::scoped_lock<angle::SimpleMutex> sl(mProgramMutex);
// Cache original options string
mProgramOpts = options;
// Build for each associated device
for (size_t i = 0; i < devices.size(); ++i)
{
const cl::RefPointer<cl::Device> &device = devices.at(i);
DeviceProgramData &deviceProgramData = mAssociatedDevicePrograms[device->getNative()];
deviceProgramData.spirvVersion = device->getImpl<CLDeviceVk>().getSpirvVersion();
if (buildType != BuildType::BINARY)
{
// Process options and append any other internal (required) options for clspv
std::vector<std::string> optionTokens;
angle::SplitStringAlongWhitespace(options + " " + internalOptions, &optionTokens);
const bool createLibrary = std::find(optionTokens.begin(), optionTokens.end(),
"-create-library") != optionTokens.end();
std::string processedOptions = ProcessBuildOptions(optionTokens, buildType);
// add clspv compiler options based on device features
processedOptions += ClspvGetCompilerOptions(&device->getImpl<CLDeviceVk>());
switch (buildType)
{
case BuildType::BUILD:
case BuildType::COMPILE:
{
ScopedClspvContext clspvCtx;
const char *clSrc = mProgram.getSource().c_str();
ClspvError clspvRet = ClspvCompileSource(
1, NULL, static_cast<const char **>(&clSrc), processedOptions.c_str(),
&clspvCtx.mOutputBin, &clspvCtx.mOutputBinSize, &clspvCtx.mOutputBuildLog);
deviceProgramData.buildLog =
clspvCtx.mOutputBuildLog != nullptr ? clspvCtx.mOutputBuildLog : "";
if (clspvRet != CLSPV_SUCCESS)
{
ERR() << "OpenCL build failed with: ClspvError(" << clspvRet << ")!";
ERR() << "Clspv option: " << processedOptions;
ERR() << "Build log: " << std::endl << deviceProgramData.buildLog;
deviceProgramData.buildStatus = CL_BUILD_ERROR;
return false;
}
if (buildType == BuildType::COMPILE)
{
deviceProgramData.IR.assign(clspvCtx.mOutputBinSize, 0);
std::memcpy(deviceProgramData.IR.data(), clspvCtx.mOutputBin,
clspvCtx.mOutputBinSize);
deviceProgramData.binaryType = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT;
}
else
{
deviceProgramData.binary.assign(clspvCtx.mOutputBinSize / sizeof(uint32_t),
0);
std::memcpy(deviceProgramData.binary.data(), clspvCtx.mOutputBin,
clspvCtx.mOutputBinSize);
deviceProgramData.binaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
}
break;
}
case BuildType::LINK:
{
ScopedClspvContext clspvCtx;
std::vector<size_t> vSizes;
std::vector<const char *> vBins;
const LinkPrograms &linkPrograms = LinkProgramsList.at(i);
for (const CLProgramVk::DeviceProgramData *linkProgramData : linkPrograms)
{
vSizes.push_back(linkProgramData->IR.size());
vBins.push_back(linkProgramData->IR.data());
}
ClspvError clspvRet = ClspvCompileSource(
linkPrograms.size(), vSizes.data(), vBins.data(), processedOptions.c_str(),
&clspvCtx.mOutputBin, &clspvCtx.mOutputBinSize, &clspvCtx.mOutputBuildLog);
deviceProgramData.buildLog =
clspvCtx.mOutputBuildLog != nullptr ? clspvCtx.mOutputBuildLog : "";
if (clspvRet != CLSPV_SUCCESS)
{
ERR() << "OpenCL build failed with: ClspvError(" << clspvRet << ")!";
ERR() << "Clspv option: " << processedOptions;
ERR() << "Build log: " << std::endl << deviceProgramData.buildLog;
deviceProgramData.buildStatus = CL_BUILD_ERROR;
return false;
}
if (createLibrary)
{
deviceProgramData.IR.assign(clspvCtx.mOutputBinSize, 0);
std::memcpy(deviceProgramData.IR.data(), clspvCtx.mOutputBin,
clspvCtx.mOutputBinSize);
deviceProgramData.binaryType = CL_PROGRAM_BINARY_TYPE_LIBRARY;
}
else
{
deviceProgramData.binary.assign(clspvCtx.mOutputBinSize / sizeof(uint32_t),
0);
std::memcpy(deviceProgramData.binary.data(),
reinterpret_cast<char *>(clspvCtx.mOutputBin),
clspvCtx.mOutputBinSize);
deviceProgramData.binaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
}
break;
}
default:
UNREACHABLE();
return false;
}
}
// Extract reflection info from spv binary and populate reflection data, as well as create
// the shader module
if (deviceProgramData.binaryType == CL_PROGRAM_BINARY_TYPE_EXECUTABLE)
{
// Report SPIR-V validation failure as a build failure
if (!ClspvValidate(mContext->getRenderer(), deviceProgramData.binary))
{
ERR() << "Failed to validate SPIR-V binary!";
deviceProgramData.buildStatus = CL_BUILD_ERROR;
return false;
}
if (!ClspvParseReflection(mContext->getRenderer(), deviceProgramData.binary,
deviceProgramData.reflectionData))
{
ERR() << "Failed to parse reflection info from SPIR-V!";
deviceProgramData.buildStatus = CL_BUILD_ERROR;
return false;
}
angle::spirv::Blob strippedSpvBlob;
angle::spirv::Blob *spvBlobPtr = &deviceProgramData.binary;
if (!mContext->getFeatures().supportsShaderNonSemanticInfo.enabled)
{
// If VK driver does not support non-semantic instructions, attempt to use a
// "stripped" version of the spir-v.
if (ClspvStripReflection(mContext->getRenderer(), deviceProgramData.binary,
strippedSpvBlob))
{
spvBlobPtr = &strippedSpvBlob;
}
}
if (mShader)
{
// Reset shader module if we built program prior to this current build
mShader.reset();
}
if (IsError(vk::InitShaderModule(mContext, &mShader, spvBlobPtr->data(),
spvBlobPtr->size() * sizeof(uint32_t))))
{
ERR() << "Failed to init Vulkan Shader Module!";
deviceProgramData.buildStatus = CL_BUILD_ERROR;
return false;
}
// Setup inital push constant range
uint32_t pushConstantMinOffet = UINT32_MAX, pushConstantMaxOffset = 0,
pushConstantMaxSize = 0;
for (const auto &pushConstant : deviceProgramData.reflectionData.pushConstants)
{
pushConstantMinOffet = pushConstant.second.offset < pushConstantMinOffet
? pushConstant.second.offset
: pushConstantMinOffet;
if (pushConstant.second.offset >= pushConstantMaxOffset)
{
pushConstantMaxOffset = pushConstant.second.offset;
pushConstantMaxSize = pushConstant.second.size;
}
}
for (const auto &pushConstant : deviceProgramData.reflectionData.imagePushConstants)
{
for (const auto imageConstant : pushConstant.second)
{
pushConstantMinOffet = imageConstant.pcRange.offset < pushConstantMinOffet
? imageConstant.pcRange.offset
: pushConstantMinOffet;
if (imageConstant.pcRange.offset >= pushConstantMaxOffset)
{
pushConstantMaxOffset = imageConstant.pcRange.offset;
pushConstantMaxSize = imageConstant.pcRange.size;
}
}
}
deviceProgramData.pushConstRange.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
deviceProgramData.pushConstRange.offset =
pushConstantMinOffet == UINT32_MAX ? 0 : pushConstantMinOffet;
deviceProgramData.pushConstRange.size = pushConstantMaxOffset + pushConstantMaxSize;
if (kAngleDebug)
{
if (mContext->getFeatures().clDumpVkSpirv.enabled)
{
angle::spirv::Print(deviceProgramData.binary);
}
}
}
deviceProgramData.buildStatus = CL_BUILD_SUCCESS;
}
return true;
}
void CLProgramVk::setBuildStatus(const cl::DevicePtrs &devices, cl_build_status status)
{
std::scoped_lock<angle::SimpleMutex> sl(mProgramMutex);
for (const auto &device : devices)
{
ASSERT(mAssociatedDevicePrograms.contains(device->getNative()));
DeviceProgramData &deviceProgram = mAssociatedDevicePrograms.at(device->getNative());
deviceProgram.buildStatus = status;
}
}
const angle::HashMap<uint32_t, ClspvPrintfInfo> *CLProgramVk::getPrintfDescriptors(
const std::string &kernelName) const
{
const DeviceProgramData *deviceProgram = getDeviceProgramData(kernelName.c_str());
if (deviceProgram)
{
return &deviceProgram->reflectionData.printfInfoMap;
}
return nullptr;
}
} // namespace rx