能否更新纹理并将其用于预录制的vkCmdDraw调用?
问题:文本图集渲染终端屏幕的方案可行性
我尝试使用文本图集渲染终端屏幕(本质是文本矩阵)。我的方案是遍历每个字符:若字符已在图集中,则传递其纹理坐标等参数并调用vkCmdDraw;若未在图集中,则传递该字符即将添加的字形位置坐标,并将该字符加入列表。我想在绘制结束后重新创建纹理并绑定,使本次绘制使用更新后的纹理,请问这是否可行?
// 伪代码,便于理解场景 start_drawing(); for (line : terminal_buffer){ for (char : line){ vec2 position = texture_contains(char) ? get_position(char) : get_last_position_and_add_to_list(char); push_data(position); draw(); } } if(regen_texture) regen_texture(); end drawing();
回答
这个方案不可行,核心原因在于Vulkan的渲染命令执行逻辑:
- 你在
start_drawing()到end drawing()之间记录的所有vkCmdDraw命令,会被存入命令缓冲;这些命令要等到后续提交到GPU队列时才会实际执行。而你在命令记录完成后才调用regen_texture()更新纹理,此时命令缓冲里的绘制指令已经绑定了旧的纹理资源——GPU执行这些命令时,访问的还是更新前的纹理数据,新字符对应的预留坐标区域根本没有有效像素,最终渲染出的新字符会是空白或错误内容。 - 如果你是直接销毁旧纹理再重建,还会导致命令缓冲里的指令引用无效资源,触发GPU错误甚至程序崩溃。
正确的实现思路
应该把纹理更新放在绘制命令记录之前,步骤调整为:
- 遍历整个终端缓冲区,收集所有需要渲染的字符,筛选出图集中没有的新字符。
- 更新纹理图集:将新字符的字形写入纹理,同步更新字符到纹理坐标的映射表。
- 开始记录绘制命令,遍历终端缓冲区,用更新后的映射表获取每个字符的纹理坐标,依次调用
vkCmdDraw完成所有绘制指令的记录。 - 提交命令缓冲到GPU队列执行渲染。
调整后的伪代码示例:
// 正确流程的伪代码 // 第一步:收集所有需要的字符 unordered_set<char> needed_chars; for (line : terminal_buffer) { for (char : line) { needed_chars.insert(char); } } // 第二步:更新纹理图集(如果有新字符) vector<char> new_chars = get_new_chars(needed_chars); if (!new_chars.empty()) { regen_texture(new_chars); update_char_position_map(new_chars); } // 第三步:记录绘制命令 start_drawing(); for (line : terminal_buffer) { for (char : line) { vec2 position = get_position(char); push_data(position); draw(); } } end drawing(); // 提交命令缓冲执行渲染 submit_command_buffer();
内容的提问来源于stack exchange,提问作者F00L.r
相关产品推荐
相关产品推荐

