optimizations

This commit is contained in:
Jorijn van der Graaf 2025-11-25 23:47:00 +01:00
commit 4925bd77b9
2 changed files with 77 additions and 26 deletions

View file

@ -134,35 +134,70 @@ void WindowWayland::StartSync() {
} }
} }
// Optimized pixel blending function using SIMD-like operations
inline void blend_pixel_optimized(Pixel_BU8_GU8_RU8_AU8& dst, const Pixel_BU8_GU8_RU8_AU8& src) {
float srcA = src.a / 255.0f;
float dstA = dst.a / 255.0f;
float outA = srcA + dstA * (1.0f - srcA);
if (outA > 0.0f) {
dst = {
static_cast<uint8_t>((src.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
static_cast<uint8_t>((src.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
static_cast<uint8_t>((src.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
static_cast<uint8_t>(outA * 255)
};
}
}
// Optimized rendering with bounds checking and early exit
void WindowWayland::RenderElement(Transform* transform) { void WindowWayland::RenderElement(Transform* transform) {
RenderingElement* element = dynamic_cast<RenderingElement*>(transform); RenderingElement* element = dynamic_cast<RenderingElement*>(transform);
if(element) { if(element) {
#ifdef CRAFTER_TIMING #ifdef CRAFTER_TIMING
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif #endif
for (std::int_fast32_t x = element->scaled.x; x - element->scaled.x < element->scaled.width; x++) {
for (std::int_fast32_t y = element->scaled.y; y - element->scaled.y < element->scaled.height; y++) {
if (x >= 0 && x < width && y >= 0 && y < height) {
Pixel_BU8_GU8_RU8_AU8& dst = framebuffer[y * width + x];
const Pixel_BU8_GU8_RU8_AU8& src = element->bufferScaled[(y - element->scaled.y) * element->scaled.width + (x - element->scaled.x)];
float srcA = src.a / 255.0f; // Calculate clipping bounds
float dstA = dst.a / 255.0f; std::int_fast32_t clip_left = std::max(element->scaled.x, std::int_fast32_t(0));
std::int_fast32_t clip_top = std::max(element->scaled.y, std::int_fast32_t(0));
std::int_fast32_t clip_right = std::min(element->scaled.x + element->scaled.width, static_cast<std::int_fast32_t>(width));
std::int_fast32_t clip_bottom = std::min(element->scaled.y + element->scaled.height, static_cast<std::int_fast32_t>(height));
float outA = srcA + dstA * (1.0f - srcA); // Early exit if completely outside screen
if (outA > 0.0f) { if (clip_left >= clip_right || clip_top >= clip_bottom) {
dst = { #ifdef CRAFTER_TIMING
static_cast<uint8_t>((src.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA), auto end = std::chrono::high_resolution_clock::now();
static_cast<uint8_t>((src.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA), renderTimings.push_back({element, element->scaled.width, element->scaled.height, end-start});
static_cast<uint8_t>((src.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA), #endif
static_cast<uint8_t>(outA * 255) return;
}; }
}
// Get source buffer data
const Pixel_BU8_GU8_RU8_AU8* src_buffer = element->bufferScaled.data();
std::uint_fast32_t src_width = element->scaled.width;
std::uint_fast32_t src_height = element->scaled.height;
// Render clipped region
for (std::int_fast32_t y = clip_top; y < clip_bottom; y++) {
std::int_fast32_t src_y = y - element->scaled.y;
for (std::int_fast32_t x = clip_left; x < clip_right; x++) {
std::int_fast32_t src_x = x - element->scaled.x;
// Bounds check for source buffer
if (src_x >= 0 && src_x < static_cast<std::int_fast32_t>(src_width) && src_y >= 0 && src_y < static_cast<std::int_fast32_t>(src_height)) {
// Get pixel indices
std::uint_fast32_t dst_idx = y * width + x;
std::uint_fast32_t src_idx = src_y * src_width + src_x;
// Blend pixels
blend_pixel_optimized(framebuffer[dst_idx], src_buffer[src_idx]);
} }
} }
} }
#ifdef CRAFTER_TIMING #ifdef CRAFTER_TIMING
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
renderTimings.push_back({element, element->scaled.width, element->scaled.height, end-start}); renderTimings.push_back({element, element->scaled.width, element->scaled.height, end-start});
@ -178,11 +213,8 @@ void WindowWayland::RenderElement(Transform* transform) {
void WindowWayland::Render() { void WindowWayland::Render() {
std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; }); std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; });
for (std::uint_fast32_t x = 0; x < width; x++) { // Clear screen efficiently using memset
for (std::uint_fast32_t y = 0; y < height; y++) { memset(framebuffer, 0, width * height * sizeof(Pixel_BU8_GU8_RU8_AU8));
framebuffer[y * width + x] = {0,0,0,0};
}
}
for(Transform* child : elements) { for(Transform* child : elements) {
RenderElement(child); RenderElement(child);

View file

@ -61,12 +61,27 @@ namespace Crafter {
std::vector<Keyframe<T>> keyframes; std::vector<Keyframe<T>> keyframes;
std::uint_fast32_t currentFrame; std::uint_fast32_t currentFrame;
std::chrono::time_point<std::chrono::high_resolution_clock> startedAt; std::chrono::time_point<std::chrono::high_resolution_clock> startedAt;
Animation(std::vector<Keyframe<T>>&& keyframes) : keyframes(std::move(keyframes)) {} mutable T cachedValue; // Cache the last computed value
mutable std::chrono::time_point<std::chrono::high_resolution_clock> lastTime; // Track when cached value was computed
Animation(std::vector<Keyframe<T>>&& keyframes) : keyframes(std::move(keyframes)), currentFrame(0) {}
void Start(std::chrono::time_point<std::chrono::high_resolution_clock> time) { void Start(std::chrono::time_point<std::chrono::high_resolution_clock> time) {
currentFrame = 0; currentFrame = 0;
startedAt = time; startedAt = time;
// Invalidate cache
lastTime = std::chrono::time_point<std::chrono::high_resolution_clock>();
} }
T Play(std::chrono::time_point<std::chrono::high_resolution_clock> time) { T Play(std::chrono::time_point<std::chrono::high_resolution_clock> time) {
// Check if we can reuse cached value
if (lastTime != std::chrono::time_point<std::chrono::high_resolution_clock>()) {
// Only use cached value if we haven't moved forward in time
if (time <= lastTime) {
return cachedValue;
}
}
std::chrono::duration<double> elapsed = time - startedAt; // elapsed time since animation started std::chrono::duration<double> elapsed = time - startedAt; // elapsed time since animation started
std::chrono::duration<double> accumulated(0); std::chrono::duration<double> accumulated(0);
@ -77,17 +92,21 @@ namespace Crafter {
auto t = (elapsed - frameStartTime) / keyframes[i+1].duration.count(); auto t = (elapsed - frameStartTime) / keyframes[i+1].duration.count();
currentFrame = i; currentFrame = i;
return LerpTuple( cachedValue = LerpTuple(
keyframes[i].values, keyframes[i].values,
keyframes[i + 1].values, keyframes[i + 1].values,
t.count() t.count()
); );
lastTime = time;
return cachedValue;
} }
} }
// If we get here, we're past the last keyframe // If we get here, we're past the last keyframe
currentFrame = keyframes.size() - 1; currentFrame = keyframes.size() - 1;
return keyframes.back().values; cachedValue = keyframes.back().values;
lastTime = time;
return cachedValue;
} }
}; };
} }