VK: Add extra safety checks around font texture creation. Motivated by some Play crashes.

This commit is contained in:
Henrik Rydgård 2018-11-21 17:33:30 +01:00
parent c73b13781c
commit 7af93d08cf
4 changed files with 41 additions and 18 deletions

View file

@ -56,10 +56,15 @@ public class TextRenderer {
total.y = (int) (p.descent() - p.ascent()) * lines.length + 2; total.y = (int) (p.descent() - p.ascent()) * lines.length + 2;
// Returning a 0 size can create problems when the caller // Returning a 0 size can create problems when the caller
// uses the measurement to create a texture. // uses the measurement to create a texture.
// Also, clamp to a reasonable maximum size.
if (total.x < 1) if (total.x < 1)
total.x = 1; total.x = 1;
if (total.y < 1) if (total.y < 1)
total.y = 1; total.y = 1;
if (total.x > 2048)
total.x = 2048;
if (total.y > 2048)
total.y = 2048;
return total; return total;
} }

View file

@ -172,7 +172,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
if (iter != cache_.end()) { if (iter != cache_.end()) {
entry = iter->second.get(); entry = iter->second.get();
entry->lastUsedFrame = frameCount_; entry->lastUsedFrame = frameCount_;
draw_->BindTexture(0, entry->texture); if (entry->texture)
draw_->BindTexture(0, entry->texture);
} else { } else {
double size = 0.0; double size = 0.0;
auto iter = fontMap_.find(fontHash_); auto iter = fontMap_.find(fontHash_);
@ -195,8 +196,10 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
env_->DeleteLocalRef(jstr); env_->DeleteLocalRef(jstr);
entry = new TextStringEntry(); entry = new TextStringEntry();
entry->bmWidth = entry->width = imageWidth; entry->bmWidth = imageWidth;
entry->bmHeight = entry->height = imageHeight; entry->width = imageWidth;
entry->bmHeight = imageHeight;
entry->height = imageHeight;
entry->lastUsedFrame = frameCount_; entry->lastUsedFrame = frameCount_;
TextureDesc desc{}; TextureDesc desc{};
@ -206,6 +209,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
desc.height = entry->bmHeight; desc.height = entry->bmHeight;
desc.depth = 1; desc.depth = 1;
desc.mipLevels = 1; desc.mipLevels = 1;
desc.generateMips = false;
desc.tag = "TextDrawer"; desc.tag = "TextDrawer";
uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight];
@ -224,13 +228,17 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
entry->texture = draw_->CreateTexture(desc); entry->texture = draw_->CreateTexture(desc);
delete[] bitmapData; delete[] bitmapData;
cache_[key] = std::unique_ptr<TextStringEntry>(entry); cache_[key] = std::unique_ptr<TextStringEntry>(entry);
draw_->BindTexture(0, entry->texture); if (entry->texture) {
draw_->BindTexture(0, entry->texture);
}
} }
float w = entry->bmWidth * fontScaleX_ * dpiScale_; float w = entry->bmWidth * fontScaleX_ * dpiScale_;
float h = entry->bmHeight * fontScaleY_ * dpiScale_; float h = entry->bmHeight * fontScaleY_ * dpiScale_;
DrawBuffer::DoAlign(align, &x, &y, &w, &h); DrawBuffer::DoAlign(align, &x, &y, &w, &h);
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); if (entry->texture) {
target.Flush(true); target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
target.Flush(true);
}
} }
void TextDrawerAndroid::ClearCache() { void TextDrawerAndroid::ClearCache() {

View file

@ -380,7 +380,9 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() {
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
}; };
VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin); VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin);
_assert_(res == VK_SUCCESS); if (res != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
frameData.hasInitCommands = true; frameData.hasInitCommands = true;
} }
return frameData_[curFrame].initCmd; return frameData_[curFrame].initCmd;

View file

@ -301,11 +301,9 @@ struct DescriptorSetKey {
class VKTexture : public Texture { class VKTexture : public Texture {
public: public:
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc) VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc)
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) { : vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {}
bool result = Create(cmd, pushBuffer, desc, alloc); bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
_assert_(result);
}
~VKTexture() { ~VKTexture() {
Destroy(); Destroy();
@ -322,8 +320,6 @@ public:
} }
private: private:
bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
void Destroy() { void Destroy() {
if (vkTex_) { if (vkTex_) {
vkTex_->Destroy(); vkTex_->Destroy();
@ -335,9 +331,9 @@ private:
VulkanContext *vulkan_; VulkanContext *vulkan_;
VulkanTexture *vkTex_ = nullptr; VulkanTexture *vkTex_ = nullptr;
int mipLevels_; int mipLevels_ = 0;
DataFormat format_; DataFormat format_ = DataFormat::UNDEFINED;
}; };
class VKFramebuffer; class VKFramebuffer;
@ -698,6 +694,10 @@ enum class TextureState {
bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) { bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) {
// Zero-sized textures not allowed. // Zero-sized textures not allowed.
_assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1! _assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1!
if (desc.width * desc.height * desc.depth <= 0) {
ELOG("Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth);
return false;
}
_assert_(push); _assert_(push);
format_ = desc.format; format_ = desc.format;
mipLevels_ = desc.mipLevels; mipLevels_ = desc.mipLevels;
@ -1079,12 +1079,20 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
} }
Texture *VKContext::CreateTexture(const TextureDesc &desc) { Texture *VKContext::CreateTexture(const TextureDesc &desc) {
if (!push_ || !renderManager_.GetInitCmd()) { VkCommandBuffer initCmd = renderManager_.GetInitCmd();
if (!push_ || !initCmd) {
// Too early! Fail. // Too early! Fail.
ELOG("Can't create textures before the first frame has started."); ELOG("Can't create textures before the first frame has started.");
return nullptr; return nullptr;
} }
return new VKTexture(vulkan_, renderManager_.GetInitCmd(), push_, desc, allocator_); VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc);
if (tex->Create(initCmd, push_, desc, allocator_)) {
return tex;
} else {
ELOG("Failed to create texture");
delete tex;
return nullptr;
}
} }
static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) { static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {