This repository has been archived on 2023-02-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-benchmark-bundle/benchmark/space/draw.py
Sybren A. Stüvel 7b88d7704c Fix T56372: Properly show error messages when submission fails
This also introduces a word-wrapping function that takes variable character
widths into account.
2018-08-14 15:08:58 +02:00

285 lines
9.2 KiB
Python

import os.path
import blf
import bpy
from ..foundation import util
from ..submission.client import CommunicationError
from . import G
WELCOME_TEXT = "Run the Quick Benchmark on the selected device to " \
"get a fast measurement of your hardware's performance.\n" \
"Usually takes less than 30 minutes."
BLURB_TEXT = "Share your results with the world!\n" \
"Manage the uploaded benchmark data on your Blender ID."
################################################################################
# Draw Utilities.
font_id = 0
def viewport_size():
import bgl
viewport = bgl.Buffer(bgl.GL_INT, 4)
bgl.glGetIntegerv(bgl.GL_VIEWPORT, viewport)
return viewport[2], viewport[3]
def draw_text_center(text, x, y, shadow=False):
dim = blf.dimensions(font_id, text)
cx = x - int(dim[0] / 2)
cy = y - int(dim[1] / 2)
if shadow:
delta = 1
blf.color(font_id, 0.2, 0.2, 0.2, 1.0)
blf.position(font_id, cx + delta, cy - delta, 0)
blf.draw(font_id, text)
blf.color(font_id, 1.0, 1.0, 1.0, 1.0)
blf.position(font_id, cx, cy, 0)
blf.draw(font_id, text)
def draw_text_multiline(text, x, y, shadow=False):
ui_scale = bpy.context.user_preferences.system.ui_scale
height = int(blf.dimensions(font_id, "Dummy Text")[1])
space = int(8 * ui_scale)
for line in text.split('\n'):
if shadow:
delta = 1
blf.color(font_id, 0.2, 0.2, 0.2, 1.0)
blf.position(font_id, x + delta, y - height - delta, 0)
blf.draw(font_id, line)
blf.color(font_id, 1.0, 1.0, 1.0, 1.0)
blf.position(font_id, x, y - height, 0)
blf.draw(font_id, line)
y -= height + space
def draw_rect(x, y, w, h, color):
import gpu
gpu.draw.rect(x, y, x + w, y + h, color[0], color[1], color[2], color[3])
def draw_image(filepath, x, y, w, h):
if filepath not in G.images:
ima = bpy.data.images.load(filepath)
G.images[filepath] = ima
import gpu
gpu.draw.image(G.images[filepath], x, y, x + w, y + h)
################################################################################
# Draw.
def benchmark_draw_post_pixel(arg1, arg2):
with G.progress_lock:
progress_status = G.progress_status
result_platform = G.result_platform
result_stats = G.result_stats
result_dict = G.result_dict
ui_scale = bpy.context.user_preferences.system.ui_scale
blf.color(font_id, 1.0, 1.0, 1.0, 1.0)
window_width, window_height = viewport_size()
# Image
image_h = 370 * ui_scale
image_y = window_height - image_h
if G.background_image_path:
draw_image(G.background_image_path, 0, image_y, window_width, image_h)
else:
splash_dir = os.path.dirname(os.path.abspath(__file__))
splash_filepath = os.path.join(splash_dir, 'splash.png')
draw_image(splash_filepath, 0, image_y, window_width, image_h)
if result_dict:
_draw_benchmark_has_run(image_y, ui_scale, window_width, window_height)
elif result_stats or result_platform or progress_status:
_draw_benchmark_is_running(image_y, result_platform, result_stats, ui_scale, window_width)
else:
_draw_introduction(image_y, ui_scale, window_width, window_height)
# Bottom bar
bottom_x = 0
bottom_y = 0
bottom_w = window_width
bottom_h = 52 * ui_scale
bottom_color = [0.2, 0.2, 0.2, 1.0]
draw_rect(bottom_x, bottom_y, bottom_w, bottom_h, bottom_color)
# Logo
logo_width_unscaled = 326
logo_height_unscaled = 104
logo_dir = os.path.dirname(os.path.abspath(__file__))
logo_filepath = os.path.join(logo_dir, 'blender.png')
logo_scale_factor = 1.0
while logo_height_unscaled * logo_scale_factor > bottom_h:
logo_scale_factor *= 0.5
logo_width = logo_width_unscaled * logo_scale_factor
logo_height = logo_height_unscaled * logo_scale_factor
logo_padding = (bottom_h - logo_height) * 0.5
draw_image(logo_filepath,
logo_padding, logo_padding,
logo_width, logo_height)
def _draw_introduction(image_y, ui_scale, window_width, window_height):
"""Draw title and welcome text."""
x = 0.5 * window_width
y = 0.70 * window_height
blf.size(font_id, int(32 * ui_scale), 72)
draw_text_center("Blender Benchmark 1.0 Beta", x, y, shadow=True)
y -= 32 * ui_scale
blf.size(font_id, int(12 * ui_scale), 72)
draw_text_center("Free and Open Data for everyone.",
x, y, shadow=True)
x = 50.0 * ui_scale
y = image_y - (image_y - 52 * ui_scale - 18 * 3 * ui_scale) * 0.5
blf.size(font_id, int(12 * ui_scale), 72)
text = word_wrap(WELCOME_TEXT, window_width * 0.45)
draw_text_multiline(text, x, y)
def _draw_benchmark_is_running(image_y, result_platform, result_stats, ui_scale, window_width):
"""Draw while the benchmark is running."""
blf.size(font_id, int(12 * ui_scale), 72)
x = 50.0 * ui_scale
y = image_y - 20 * ui_scale
# Stats
if result_platform:
draw_text_multiline(result_platform, 0.5 * window_width + x, y)
if result_stats:
draw_text_multiline(result_stats, x, y)
# Progress
progress_x = 0.0
progress_y = image_y + 1
progress_w = window_width * G.current_progress
progress_h = 15.0 * ui_scale
progress_color = [0.8, 1.0, 1.0, 0.2]
draw_rect(progress_x, progress_y, progress_w, progress_h, progress_color)
# Current status
if G.progress_status:
blf.size(font_id, int(18 * ui_scale), 72)
draw_text_multiline(G.progress_status,
progress_x + 8.0 * ui_scale,
progress_y + progress_h + int(22 * ui_scale),
shadow=True)
def _draw_benchmark_has_run(image_y, ui_scale, window_width, window_height):
"""Draw submit button and other after-running stuff."""
x = 0.5 * window_width
y = 0.70 * window_height
score = 0
for name_stats in G.result_dict["scenes"]:
stat = name_stats['stats']
if stat["result"] == "OK":
score += stat["total_render_time"]
else:
score = -1
if score >= 0:
blf.size(font_id, int(32 * ui_scale), 72)
draw_text_center("Your Time: {}".format(
util.humanReadableTimeDifference(score)), x, y, shadow=True)
else:
blf.size(font_id, int(18 * ui_scale), 72)
draw_text_center("Unfortunately, crash happened :(", x, y, shadow=True)
blf.size(font_id, int(24 * ui_scale), 72)
draw_text_center("You can still share data of succeeded scenes!",
x, y - 26 * ui_scale, shadow=True)
x = 50.0 * ui_scale
y = image_y - (image_y - 52 * ui_scale - 18 * 3 * ui_scale) * 0.5
blf.size(font_id, int(12 * ui_scale), 72)
text = _after_submission_text()
text = word_wrap(text, window_width * 0.45)
draw_text_multiline(text, x, y)
def _after_submission_text() -> str:
ex = G.submission_exception
# Nothing wrong, just show the default text.
if not ex:
return BLURB_TEXT
# If not our own exception class, show generic message.
if not isinstance(ex, CommunicationError):
return f'Error submitting your results: {ex}'
# Return proper message based on the HTTP status code of the response.
if ex.status_code in {502, 503}:
# 502 Bad Gateway, happens when restarting uWSGI.
# 503 Service Unavailable, happens when OpenData is down.
text = f'There was a hickups with code {ex.status_code} ' \
f'in the Open Data platform, please try submitting again.'
elif ex.status_code == 422:
# 422 Unprocessable Entity, happens when the JSON doesn't pass schema validation.
text = f'We somehow submitted invalid data, see below for details.'
else:
text = f'Error {ex.status_code} submitting your results.'
if not ex.json:
return text
msg = ex.json.get('message')
if msg:
return f'{text}\nThe server said: {msg}'
return text
def word_wrap(string: str, width_in_px: int) -> str:
"""Word-wrapping with variable character width.
Newlines in the input string are kept in the output.
"""
if '\n' in string:
# If the string already consists of multiple lines, wrap each line individually.
return '\n'.join(word_wrap(line, width_in_px)
for line in string.splitlines(keepends=False))
# Do an estimate of the maximum number of characters to fit on a line.
char_width = blf.dimensions(font_id, "i")[0]
max_chars = int(width_in_px // char_width)
wrapped_lines = []
while string:
# The line won't be longer than max_chars, so start there.
candidate_line = string[:max_chars]
line_width = blf.dimensions(font_id, candidate_line)[0]
# Keep removing the last word until the line fits the width.
while line_width >= width_in_px:
marker = len(candidate_line) - 1
while not candidate_line[marker].isspace():
marker -= 1
candidate_line = candidate_line[:marker]
line_width = blf.dimensions(font_id, candidate_line)[0]
string = string[len(candidate_line):]
wrapped_lines.append(candidate_line.strip())
return '\n'.join(wrapped_lines)