aclnnRasterizer
Applicable Products
| Product | Supported |
|---|---|
| ร | |
| โ | |
| โ | |
| ร | |
| ร | |
| ร |
Function
Description: Implements rasterization computation. Based on given points and faces in 3D space, obtains the minimum depth of each pixel on the screen and its corresponding face index, and computes the perspective-corrected interpolation of barycentric coordinates for that face.
Formula: records the face index corresponding to the minimum depth of each pixel, and records the perspective-corrected interpolation of barycentric coordinates of each vertex relative to the face recorded in . The Z-Buffer used in the computation records the minimum depth of each pixel and the triangle face index corresponding to that depth.
The computation process is as follows: For each triangle face in space:
Convert the three vertex coordinates , , of to screen coordinates , ,
Compute the bounding rectangle of based on , ,
For each pixel within the rectangle, perform the following operations:
a. Compute the pixel center coordinate b. Compute the barycentric coordinates of relative to triangle c. Determine whether lies inside the triangle based on . If is not inside the triangle, proceed to the next pixel within the rectangle; otherwise, perform the following steps d. Use and , , to obtain the depth value depth of the current pixel e. If depth prior is enabled; otherwise, directly proceed to the next step "Z-Buffer Update"
- Compute the depth threshold depth_thres using the depth prior map
- If depth < depth_thres, process the next pixel in the rectangle; otherwise, perform the following steps.
f. Z-Buffer update:
- If :
- If :
After processing all triangular faces in space according to the above steps, for each pixel on the screen of size :
- Retrieve the face index corresponding to in the Z-Buffer,
- Convert the three vertex coordinates , , of to screen coordinates , ,
- Compute the center coordinates of
- Compute the barycentric coordinates of relative to triangle
- Use to compute the perspective-corrected interpolation
The specific computation methods involved are as follows:
Convert vertex to screen coordinates
The barycentric coordinates of point relative to triangle
- Compute the signed areas , , and of triangles , , and , respectively
- If is 0, then ; otherwise
The signed area of the triangle formed by vertices , , and
Compute the depth of pixel by combining the barycentric coordinates and the triangle screen coordinates , , and
Compute the depth threshold for point by combining the depth map and the occlusion truncation
Determine whether the vertex lies inside the triangle based on the barycentric coordinates If , , and , the point is inside the triangle (including on the triangle edges); otherwise, the point is outside the triangle.
Compute the perspective-corrected interpolation using the barycentric coordinates and the three vertex coordinates of the triangle: , , and
Function Prototype
Each operator is divided into a two-phase API. You must first call the "aclnnRasterizerGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnRasterizer" API to execute the computation.
aclnnStatus aclnnRasterizerGetWorkspaceSize(
const aclTensor *v,
const aclTensor *f,
const aclTensor *dOptional,
int64_t width,
int64_t height,
double occlusionTruncation,
int64_t useDepthPrior,
const aclTensor *findicesOut,
const aclTensor *barycentricOut,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnRasterizer(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)aclnnRasterizerGetWorkspaceSize
Parameters
Parameter Name Input/Output Description Usage Description Data Type Data Format Dimension (shape) Non-contiguous Tensor v (aclTensor*) Input Input tensor representing vertex coordinates in space. - Empty tensors are not supported.
- Shape: (numVertices, 4), where numVertices is a positive integer indicating the number of vertices. Each vertex coordinate is represented as (x, y, z, w).
FLOAT32 ND 2 ร f (aclTensor*) Input Input tensor representing faces in space. - Empty tensors are not supported.
- The shape is (numFaces, 3), where numFaces represents the number of faces in space and is a positive integer. Each face is a triangle, and each vertex of the triangle is represented as an index of the vertex in v. Therefore, the element values in f should be valid indices into v, i.e., the value range is [0, numVertices-1]. The caller is responsible for ensuring that the elements in f are valid.
INT32 ND 2 ร dOptional (aclTensor*) Input Represents the input tensor of the depth map, used to compute the depth threshold. - Optional input. An empty Tensor is supported.
- This parameter does not take effect.
FLOAT32 ND 2 ร width (int64_t) Input Screen width. Value range: [1, 4096]. - - - - height (int64_t) Input Screen height. Value range: [1, 4096]. - - - - occlusionTruncation (double) Input Occlusion truncation, used to calculate the depth threshold. This parameter does not take effect. - - - - useDepthPrior (int64_t) Input Indicates whether to apply depth prior. - The value is 0 or 1. 1 indicates that depth prior is applied, and 0 indicates that depth prior is not applied.
- This operator does not support applying depth prior, so the value is fixed at 0.
- - - - findicesOut (aclTensor*) Output Indicates the index of the face corresponding to the minimum depth of each pixel on the screen. - Empty tensors are not supported.
- Shape: (height, width), where height is the screen height and width is the screen width.
INT32 ND 2 ร barycentricOut (aclTensor*) Output The output tensor representing the perspective-corrected interpolation of barycentric coordinates for each pixel on the screen relative to the face corresponding to the minimum depth. - Empty tensors are not supported.
- The shape is (height, width, 3), where height is the screen height and width is the screen width.
FLOAT32 ND 3 ร workspaceSize (uint64_t*) Output Returns the workspace size to be allocated on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the op executor, which contains the operator compute flow. - - - - - Return Value
aclnnStatus: return code. For details, see aclnn Return Codes.
The first-phase API performs input parameter validation and reports an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The input v, f, findicesOut, or barycentricOut is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of v, f, findicesOut, or barycentricOut is not within the supported range. ACLNN_ERR_INNER_TILING_ERROR 561002 The shape of v, f, findicesOut, or barycentricOut is not within the supported range. The value of useDepthPrior, height, or width is not within the supported range.
aclnnRasterizer
Parameters
Parameter Name Input/Output Description workspace Input The workspace memory address allocated on the Device side. workspaceSize Input Size of the workspace requested on the Device side, obtained through the first-phase API aclnnRasterizerGetWorkspaceSize. executor Input Operator executor, which encapsulates the operator computation flow. stream Input Specifies the stream on which the task is executed. Return Value
aclnnStatus: return code. For details, see aclnn Return Codes.
Constraints
Only the scenario where useDepthPrior is 0 is supported. The parameters dOptional, occlusionTruncation, and useDepthPrior do not take effect in actual computation.
Deterministic computation:
- aclnnRasterizer uses deterministic implementation by default.
Example
The following sample code is for reference only. For details about compilation and execution, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_rasterizer.h"
#define CHECK_RET(cond, return_expr) \
do { \
if (!(cond)) { \
return_expr; \
} \
} while (0)
#define LOG_PRINT(message, ...) \
do { \
printf(message, ##__VA_ARGS__); \
} while (0)
int64_t GetShapeSize(const std::vector<int64_t> &shape)
{
int64_t shapeSize = 1;
for (auto i : shape) {
shapeSize *= i;
}
return shapeSize;
}
int Init(int32_t deviceId, aclrtStream *stream)
{
// Boilerplate: resource initialization.
auto ret = aclInit(nullptr);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
ret = aclrtSetDevice(deviceId);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
ret = aclrtCreateStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
return 0;
}
template <typename T>
int CreateAclTensor(const std::vector<T> &hostData, const std::vector<int64_t> &shape, void **deviceAddr,
aclDataType dataType, aclTensor **tensor)
{
auto size = GetShapeSize(shape) * sizeof(T);
// Call aclrtMalloc to allocate device-side memory.
auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
// Call aclrtMemcpy to copy host-side data to the device-side memory.
ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
// Compute the strides of a contiguous tensor.
std::vector<int64_t> strides(shape.size(), 1);
for (int64_t i = shape.size() - 2; i >= 0; i--) {
strides[i] = shape[i + 1] * strides[i + 1];
}
// Call the aclCreateTensor API to create an aclTensor.
*tensor = aclCreateTensor(shape.data(),
shape.size(),
dataType,
strides.data(),
0,
aclFormat::ACL_FORMAT_ND,
shape.data(),
shape.size(),
*deviceAddr);
return 0;
}
int main()
{
// 1. (Boilerplate) Initialize the device/stream. See the acl API manual.
// Fill in the deviceId based on your actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
std::vector<int64_t> vShape = {3, 4};
std::vector<int64_t> fShape = {1, 3};
std::vector<int64_t> dShape = {10, 10};
std::vector<int64_t> findicesShape = {10, 10};
std::vector<int64_t> baryShape = {10, 10, 3};
int64_t height = 10;
int64_t width = 10;
float occlusionTruncation = 0.0f;
int64_t useDepthPrior = 0;
std::vector<float> vData = {6.0f, 4.0f, 1.0f, 6.9f, 7.0928106f, 0.3491799f, 3.0046327f, 6.6574745f,
7.308903f, 7.6934705f, 0.1315008f, 3.9899914f};
std::vector<int32_t> fData = {2, 1, 0};
std::vector<float> dData(100, 0.0f);
std::vector<int32_t> findicesData(100, 0);
std::vector<float> baryData(10 * 10 * 3, 0.0f);
void *vDeviceAddr = nullptr;
void *fDeviceAddr = nullptr;
void *dDeviceAddr = nullptr;
void *findicesDeviceAddr = nullptr;
void *baryDeviceAddr = nullptr;
aclTensor *v = nullptr;
aclTensor *f = nullptr;
aclTensor *d = nullptr;
aclTensor *findices = nullptr;
aclTensor *barycentric = nullptr;
ret = CreateAclTensor(vData, vShape, &vDeviceAddr, aclDataType::ACL_FLOAT, &v);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(fData, fShape, &fDeviceAddr, aclDataType::ACL_INT32, &f);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(dData, dShape, &dDeviceAddr, aclDataType::ACL_FLOAT, &d);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(findicesData, findicesShape, &findicesDeviceAddr, aclDataType::ACL_INT32, &findices);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(baryData, baryShape, &baryDeviceAddr, aclDataType::ACL_FLOAT, &barycentric);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API. Replace it with the specific API name.
uint64_t workspaceSize = 0;
aclOpExecutor *executor;
// Call the first-phase API of aclnnRasterizer.
ret = aclnnRasterizerGetWorkspaceSize(v, f, d, width, height, occlusionTruncation, useDepthPrior, findices,
barycentric, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRasterizerGetWorkspaceSize failed. ERROR: %d\n", ret);
return ret);
// Allocate device memory based on the workspaceSize calculated by the first-phase API.
void *workspaceAddr = nullptr;
if (workspaceSize > 0) {
ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
}
// Call the second-phase API of aclnnRasterizer.
ret = aclnnRasterizer(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRasterizer failed. ERROR: %d\n", ret); return ret);
// 4. (Standard practice) Synchronize and wait for task execution to complete.
ret = aclrtSynchronizeStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
// 5. Obtain the output values and copy the results from device memory to host memory. Modify this based on the specific API definition.
auto findicesSize = GetShapeSize(findicesShape);
std::vector<int32_t> findicesOutData(findicesSize, 0);
ret = aclrtMemcpy(findicesOutData.data(),
findicesSize * sizeof(findicesOutData[0]),
findicesDeviceAddr,
findicesSize * sizeof(findicesOutData[0]),
ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
auto barycentricSize = GetShapeSize(baryShape);
std::vector<float> baryOutData(barycentricSize, 0);
ret = aclrtMemcpy(baryOutData.data(),
barycentricSize * sizeof(baryOutData[0]),
baryDeviceAddr,
barycentricSize * sizeof(baryOutData[0]),
ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
for (int64_t i = 0; i < findicesSize; i++) {
LOG_PRINT("findices[%ld] is: %d\n", i, findicesOutData[i]);
}
for (int64_t i = 0; i < barycentricSize; i++) {
LOG_PRINT("barycentric[%ld] is: %f\n", i, baryOutData[i]);
}
// 6. Release the aclTensor. Modify based on the specific API definition.
aclDestroyTensor(v);
aclDestroyTensor(f);
aclDestroyTensor(d);
aclDestroyTensor(findices);
aclDestroyTensor(barycentric);
// 7. Release the device resources. Modify based on the specific API definition.
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}