Skip to content

Commit 6d7c9b4

Browse files
[vulkan] Device API blending (#4815)
* Add actual blending control in device API and disable blending for set_image * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5265d4e commit 6d7c9b4

File tree

11 files changed

+144
-31
lines changed

11 files changed

+144
-31
lines changed

taichi/backends/device.h

+28
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@ enum class DeviceCapability : uint32_t {
4848
wide_lines
4949
};
5050

51+
enum class BlendOp : uint32_t { add, subtract, reverse_subtract, min, max };
52+
53+
enum class BlendFactor : uint32_t {
54+
zero,
55+
one,
56+
src_color,
57+
one_minus_src_color,
58+
dst_color,
59+
one_minus_dst_color,
60+
src_alpha,
61+
one_minus_src_alpha,
62+
dst_alpha,
63+
one_minus_dst_alpha
64+
};
65+
5166
class Device;
5267
struct DeviceAllocation;
5368
struct DevicePtr;
@@ -529,13 +544,26 @@ struct ImageParams {
529544
bool export_sharing{false};
530545
};
531546

547+
struct BlendFunc {
548+
BlendOp op{BlendOp::add};
549+
BlendFactor src_factor{BlendFactor::src_alpha};
550+
BlendFactor dst_factor{BlendFactor::one_minus_src_alpha};
551+
};
552+
553+
struct BlendingParams {
554+
bool enable{true};
555+
BlendFunc color;
556+
BlendFunc alpha;
557+
};
558+
532559
struct RasterParams {
533560
TopologyType prim_topology{TopologyType::Triangles};
534561
PolygonMode polygon_mode{PolygonMode::Fill};
535562
bool front_face_cull{false};
536563
bool back_face_cull{false};
537564
bool depth_test{false};
538565
bool depth_write{false};
566+
std::vector<BlendingParams> blending{};
539567
};
540568

541569
class GraphicsDevice : public Device {

taichi/backends/vulkan/vulkan_device.cpp

+104-31
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,40 @@ VkImageLayout image_layout_ti_to_vk(ImageLayout layout) {
105105
return image_layout_ti_2_vk.at(layout);
106106
}
107107

108+
const std::unordered_map<BlendOp, VkBlendOp> blend_op_ti_2_vk = {
109+
{BlendOp::add, VK_BLEND_OP_ADD},
110+
{BlendOp::subtract, VK_BLEND_OP_SUBTRACT},
111+
{BlendOp::reverse_subtract, VK_BLEND_OP_REVERSE_SUBTRACT},
112+
{BlendOp::min, VK_BLEND_OP_MIN},
113+
{BlendOp::max, VK_BLEND_OP_MAX}};
114+
115+
VkBlendOp blend_op_ti_to_vk(BlendOp op) {
116+
if (blend_op_ti_2_vk.find(op) == blend_op_ti_2_vk.end()) {
117+
TI_ERROR("BlendOp cannot be mapped to vk");
118+
}
119+
return blend_op_ti_2_vk.at(op);
120+
}
121+
122+
const std::unordered_map<BlendFactor, VkBlendFactor> blend_factor_ti_2_vk = {
123+
{BlendFactor::zero, VK_BLEND_FACTOR_ZERO},
124+
{BlendFactor::one, VK_BLEND_FACTOR_ONE},
125+
{BlendFactor::src_color, VK_BLEND_FACTOR_SRC_COLOR},
126+
{BlendFactor::one_minus_src_color, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR},
127+
{BlendFactor::dst_color, VK_BLEND_FACTOR_DST_COLOR},
128+
{BlendFactor::one_minus_dst_color, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR},
129+
{BlendFactor::src_alpha, VK_BLEND_FACTOR_SRC_ALPHA},
130+
{BlendFactor::one_minus_src_alpha, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA},
131+
{BlendFactor::dst_alpha, VK_BLEND_FACTOR_DST_ALPHA},
132+
{BlendFactor::one_minus_dst_alpha, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA},
133+
};
134+
135+
VkBlendFactor blend_factor_ti_to_vk(BlendFactor factor) {
136+
if (blend_factor_ti_2_vk.find(factor) == blend_factor_ti_2_vk.end()) {
137+
TI_ERROR("BlendFactor cannot be mapped to vk");
138+
}
139+
return blend_factor_ti_2_vk.at(factor);
140+
}
141+
108142
VulkanPipeline::VulkanPipeline(const Params &params)
109143
: device_(params.device->vk_device()), name_(params.name) {
110144
create_descriptor_set_layout(params);
@@ -124,6 +158,9 @@ VulkanPipeline::VulkanPipeline(
124158
const std::vector<VertexInputBinding> &vertex_inputs,
125159
const std::vector<VertexInputAttribute> &vertex_attrs)
126160
: device_(params.device->vk_device()), name_(params.name) {
161+
this->graphics_pipeline_template_ =
162+
std::make_unique<GraphicsPipelineTemplate>();
163+
127164
create_descriptor_set_layout(params);
128165
create_shader_stages(params);
129166
create_pipeline_layout();
@@ -159,38 +196,12 @@ vkapi::IVkPipeline VulkanPipeline::graphics_pipeline(
159196
return graphics_pipeline_.at(renderpass);
160197
}
161198

162-
std::vector<VkPipelineColorBlendAttachmentState> blend_attachments(
163-
renderpass_desc.color_attachments.size());
164-
for (int i = 0; i < renderpass_desc.color_attachments.size(); i++) {
165-
blend_attachments[i].colorWriteMask =
166-
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
167-
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
168-
blend_attachments[i].blendEnable = VK_TRUE;
169-
blend_attachments[i].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
170-
blend_attachments[i].dstColorBlendFactor =
171-
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
172-
blend_attachments[i].colorBlendOp = VK_BLEND_OP_ADD;
173-
blend_attachments[i].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
174-
blend_attachments[i].dstAlphaBlendFactor =
175-
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
176-
blend_attachments[i].alphaBlendOp = VK_BLEND_OP_ADD;
177-
}
178-
179-
graphics_pipeline_template_->color_blending.attachmentCount =
180-
renderpass_desc.color_attachments.size();
181-
graphics_pipeline_template_->color_blending.pAttachments =
182-
blend_attachments.data();
183-
184199
vkapi::IVkPipeline pipeline = vkapi::create_graphics_pipeline(
185200
device_, &graphics_pipeline_template_->pipeline_info, renderpass,
186201
pipeline_layout_);
187202

188203
graphics_pipeline_[renderpass] = pipeline;
189204

190-
graphics_pipeline_template_->color_blending.attachmentCount = 0;
191-
graphics_pipeline_template_->color_blending.pAttachments = nullptr;
192-
graphics_pipeline_template_->pipeline_info.renderPass = VK_NULL_HANDLE;
193-
194205
return pipeline;
195206
}
196207

@@ -252,6 +263,39 @@ void VulkanPipeline::create_descriptor_set_layout(const Params &params) {
252263
// TI_WARN("attrib {}:{}", location, type->type_name);
253264
// }
254265
// }
266+
267+
if (code_view.stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
268+
uint32_t render_target_count = 0;
269+
result = spvReflectEnumerateOutputVariables(&module, &render_target_count,
270+
nullptr);
271+
TI_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
272+
273+
std::vector<SpvReflectInterfaceVariable *> variables(render_target_count);
274+
result = spvReflectEnumerateOutputVariables(&module, &render_target_count,
275+
variables.data());
276+
277+
render_target_count = 0;
278+
279+
for (auto var : variables) {
280+
// We want to remove auxiliary outputs such as frag depth
281+
if (var->built_in == -1) {
282+
render_target_count++;
283+
}
284+
}
285+
286+
graphics_pipeline_template_->blend_attachments.resize(
287+
render_target_count);
288+
289+
VkPipelineColorBlendAttachmentState default_state{};
290+
default_state.colorWriteMask =
291+
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
292+
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
293+
default_state.blendEnable = VK_FALSE;
294+
295+
std::fill(graphics_pipeline_template_->blend_attachments.begin(),
296+
graphics_pipeline_template_->blend_attachments.end(),
297+
default_state);
298+
}
255299
}
256300

257301
for (uint32_t set : sets_used) {
@@ -295,9 +339,6 @@ void VulkanPipeline::create_graphics_pipeline(
295339
const RasterParams &raster_params,
296340
const std::vector<VertexInputBinding> &vertex_inputs,
297341
const std::vector<VertexInputAttribute> &vertex_attrs) {
298-
this->graphics_pipeline_template_ =
299-
std::make_unique<GraphicsPipelineTemplate>();
300-
301342
// Use dynamic viewport state. These two are just dummies
302343
VkViewport viewport;
303344
viewport.width = 1;
@@ -411,13 +452,45 @@ void VulkanPipeline::create_graphics_pipeline(
411452
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
412453
color_blending.logicOpEnable = VK_FALSE;
413454
color_blending.logicOp = VK_LOGIC_OP_COPY;
414-
color_blending.attachmentCount = 0;
415-
color_blending.pAttachments = nullptr; // Filled in later
455+
color_blending.attachmentCount =
456+
graphics_pipeline_template_->blend_attachments.size();
457+
color_blending.pAttachments =
458+
graphics_pipeline_template_->blend_attachments.data();
416459
color_blending.blendConstants[0] = 0.0f;
417460
color_blending.blendConstants[1] = 0.0f;
418461
color_blending.blendConstants[2] = 0.0f;
419462
color_blending.blendConstants[3] = 0.0f;
420463

464+
if (raster_params.blending.size()) {
465+
TI_ASSERT_INFO(raster_params.blending.size() ==
466+
graphics_pipeline_template_->blend_attachments.size(),
467+
"RasterParams::blending (size={}) must either be zero sized "
468+
"or match the number of fragment shader outputs (size={}).",
469+
raster_params.blending.size(),
470+
graphics_pipeline_template_->blend_attachments.size());
471+
472+
for (int i = 0; i < raster_params.blending.size(); i++) {
473+
auto &state = graphics_pipeline_template_->blend_attachments[i];
474+
auto &ti_param = raster_params.blending[i];
475+
state.blendEnable = ti_param.enable;
476+
if (ti_param.enable) {
477+
state.colorBlendOp = blend_op_ti_to_vk(ti_param.color.op);
478+
state.srcColorBlendFactor =
479+
blend_factor_ti_to_vk(ti_param.color.src_factor);
480+
state.dstColorBlendFactor =
481+
blend_factor_ti_to_vk(ti_param.color.dst_factor);
482+
state.alphaBlendOp = blend_op_ti_to_vk(ti_param.alpha.op);
483+
state.srcAlphaBlendFactor =
484+
blend_factor_ti_to_vk(ti_param.alpha.src_factor);
485+
state.dstAlphaBlendFactor =
486+
blend_factor_ti_to_vk(ti_param.alpha.dst_factor);
487+
state.colorWriteMask =
488+
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
489+
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
490+
}
491+
}
492+
}
493+
421494
VkPipelineDynamicStateCreateInfo &dynamic_state =
422495
graphics_pipeline_template_->dynamic_state;
423496
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;

taichi/backends/vulkan/vulkan_device.h

+1
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class VulkanPipeline : public Pipeline {
313313
VkPipelineMultisampleStateCreateInfo multisampling{};
314314
VkPipelineDepthStencilStateCreateInfo depth_stencil{};
315315
VkPipelineColorBlendStateCreateInfo color_blending{};
316+
std::vector<VkPipelineColorBlendAttachmentState> blend_attachments{};
316317
std::vector<VkDynamicState> dynamic_state_enables = {
317318
VK_DYNAMIC_STATE_LINE_WIDTH, VK_DYNAMIC_STATE_VIEWPORT,
318319
VK_DYNAMIC_STATE_SCISSOR};

taichi/ui/backends/vulkan/renderable.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ void Renderable::create_graphics_pipeline() {
145145
raster_params.depth_test = true;
146146
raster_params.depth_write = true;
147147

148+
if (config_.blending) {
149+
raster_params.blending.push_back(BlendingParams());
150+
}
151+
148152
std::vector<VertexInputBinding> vertex_inputs = {
149153
{/*binding=*/0, config_.vbo_size(), /*instance=*/false}};
150154
// TODO: consider using uint8 for colors and normals

taichi/ui/backends/vulkan/renderable.h

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct RenderableConfig {
3131
int indices_count{0};
3232
size_t ubo_size{0};
3333
size_t ssbo_size{0};
34+
bool blending{false};
3435
std::string vertex_shader_path;
3536
std::string fragment_shader_path;
3637
taichi::lang::TopologyType topology_type{

taichi/ui/backends/vulkan/renderables/circles.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void Circles::init_circles(AppContext *app_context,
2626
1,
2727
sizeof(UniformBufferObject),
2828
0,
29+
true,
2930
app_context->config.package_path + "/shaders/Circles_vk_vert.spv",
3031
app_context->config.package_path + "/shaders/Circles_vk_frag.spv",
3132
TopologyType::Points,

taichi/ui/backends/vulkan/renderables/lines.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void Lines::init_lines(AppContext *app_context,
2929
indices_count,
3030
sizeof(UniformBufferObject),
3131
0,
32+
true,
3233
app_context->config.package_path + "/shaders/Lines_vk_vert.spv",
3334
app_context->config.package_path + "/shaders/Lines_vk_frag.spv",
3435
TopologyType::Lines,

taichi/ui/backends/vulkan/renderables/mesh.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ void Mesh::init_mesh(AppContext *app_context,
5353
indices_count,
5454
sizeof(UniformBufferObject),
5555
1,
56+
true,
5657
app_context->config.package_path + "/shaders/Mesh_vk_vert.spv",
5758
app_context->config.package_path + "/shaders/Mesh_vk_frag.spv",
5859
TopologyType::Triangles,

taichi/ui/backends/vulkan/renderables/particles.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ void Particles::init_particles(AppContext *app_context,
5858
1,
5959
sizeof(UniformBufferObject),
6060
1,
61+
true,
6162
app_context->config.package_path + "/shaders/Particles_vk_vert.spv",
6263
app_context->config.package_path + "/shaders/Particles_vk_frag.spv",
6364
TopologyType::Points,

taichi/ui/backends/vulkan/renderables/set_image.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ void SetImage::init_set_image(AppContext *app_context,
113113
6,
114114
sizeof(UniformBufferObject),
115115
0,
116+
false,
116117
app_context->config.package_path + "/shaders/SetImage_vk_vert.spv",
117118
app_context->config.package_path + "/shaders/SetImage_vk_frag.spv",
118119
TopologyType::Triangles,

taichi/ui/backends/vulkan/renderables/triangles.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void Triangles::init_triangles(AppContext *app_context,
2525
indices_count,
2626
sizeof(UniformBufferObject),
2727
0,
28+
true,
2829
app_context->config.package_path + "/shaders/Triangles_vk_vert.spv",
2930
app_context->config.package_path + "/shaders/Triangles_vk_frag.spv",
3031
TopologyType::Triangles,

0 commit comments

Comments
 (0)