Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
test_backbuf_publish.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
41#include "develop/develop.h" // dt_dev_set_backbuf()
43
44#include <stdarg.h>
45#include <stddef.h>
46// cmocka.h declares `extern jmp_buf global_expect_assert_env' at file scope without including
47// <setjmp.h> itself. Same suppression as test_metadata_notify.c, and for the same reason.
48#include <setjmp.h> // NOLINT(misc-include-cleaner)
49#include <stdint.h>
50#include <cmocka.h>
51
52#include <glib.h>
53
54/* Two publications a clipping module's edit mode swaps between: the cropped frame, and the full
55 * transformed one it neutralises the crop to show. Different shape, different cacheline. */
56#define SHAPE_A_W 4032
57#define SHAPE_A_H 3024
58#define SHAPE_A_HASH 0x1111111111111111ull
59#define SHAPE_B_W 5104
60#define SHAPE_B_H 3880
61#define SHAPE_B_HASH 0x2222222222222222ull
62
63typedef struct publisher_t
64{
66 volatile gint stop;
67 guint64 publications;
69
70static gpointer _publisher_main(gpointer user_data)
71{
72 publisher_t *p = (publisher_t *)user_data;
73 while(!g_atomic_int_get(&p->stop))
74 {
77 p->publications += 2;
78 }
79 return NULL;
80}
81
83static gboolean _pairing_is_coherent(const uint64_t hash, const size_t width, const size_t height)
84{
85 if(hash == SHAPE_A_HASH) return width == SHAPE_A_W && height == SHAPE_A_H;
86 if(hash == SHAPE_B_HASH) return width == SHAPE_B_W && height == SHAPE_B_H;
87 return TRUE; // the seed value; not a publication either side authored
88}
89
90/* How long to hunt. Long enough that a miss means something on an idle machine, short enough
91 * that the suite stays a suite. */
92#define HUNT_MICROSECONDS 400000
93
95{
96 (void)state;
97 publisher_t p = { { 0 } };
99
100 GThread *writer = g_thread_new("backbuf-publisher", _publisher_main, &p);
101 assert_non_null(writer);
102
103 gint64 crossed = 0;
104 gint64 reads = 0;
105 const gint64 deadline = g_get_monotonic_time() + HUNT_MICROSECONDS;
106 while(g_get_monotonic_time() < deadline && crossed == 0)
107 {
108 /* The display path's shape: take the hash, resolve a cacheline from it, and only then ask
109 * how wide the pixels are. The resolve is what makes the window wide enough to matter; a
110 * compiler barrier stands in for it. */
111 const uint64_t hash = dt_dev_backbuf_get_hash(&p.backbuf);
112 __asm__ __volatile__("" ::: "memory");
113 const size_t width = p.backbuf.width;
114 const size_t height = p.backbuf.height;
115
116 reads++;
117 if(!_pairing_is_coherent(hash, width, height)) crossed++;
118 }
119
120 g_atomic_int_set(&p.stop, 1);
121 g_thread_join(writer);
122
123 print_message("field-by-field: %" G_GINT64_FORMAT " reads, %" G_GINT64_FORMAT " crossed pairings\n", reads,
124 crossed);
125 assert_true(crossed > 0);
126}
127
129{
130 (void)state;
131 publisher_t p = { { 0 } };
133
134 GThread *writer = g_thread_new("backbuf-publisher", _publisher_main, &p);
135 assert_non_null(writer);
136
137 gint64 crossed = 0;
138 gint64 reads = 0;
139 const gint64 deadline = g_get_monotonic_time() + HUNT_MICROSECONDS;
140 while(g_get_monotonic_time() < deadline)
141 {
142 const dt_backbuf_state_t published = dt_dev_backbuf_snapshot(&p.backbuf);
143 reads++;
144 if(!_pairing_is_coherent(published.hash, published.width, published.height)) crossed++;
145 }
146
147 g_atomic_int_set(&p.stop, 1);
148 g_thread_join(writer);
149
150 print_message("snapshot: %" G_GINT64_FORMAT " reads, %" G_GINT64_FORMAT " crossed pairings\n", reads, crossed);
151 assert_int_equal(crossed, 0);
152}
153
157{
158 (void)state;
159 dt_backbuf_t backbuf = { 0 };
161
163
164 const dt_backbuf_state_t published = dt_dev_backbuf_snapshot(&backbuf);
165 assert_int_equal(published.hash, DT_PIXELPIPE_CACHE_HASH_INVALID);
166 assert_int_equal(published.width, SHAPE_A_W);
167 assert_int_equal(published.height, SHAPE_A_H);
168}
169
170int main(void)
171{
172 const struct CMUnitTest tests[] = {
176 };
177 return cmocka_run_group_tests(tests, NULL, NULL);
178}
179
180// clang-format off
181// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
182// vim: shiftwidth=2 expandtab tabstop=2 cindent
183// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
184// clang-format on
#define TRUE
Definition ashift_lsd.c:162
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_dev_set_backbuf(dt_backbuf_t *backbuf, const int width, const int height, const size_t bpp, const int64_t hash, const int64_t history_hash)
Definition develop.c:2134
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define DT_PIXELPIPE_CACHE_HASH_INVALID
static dt_backbuf_state_t dt_dev_backbuf_snapshot(const dt_backbuf_t *backbuf)
Read the whole record as one publication.
static void dt_dev_backbuf_set_hash(dt_backbuf_t *backbuf, const uint64_t hash)
static uint64_t dt_dev_backbuf_get_hash(const dt_backbuf_t *backbuf)
const float uint32_t state[4]
unsigned __int64 uint64_t
Definition strptime.c:75
One coherent publication, by value.
What the pipeline last published: which cacheline, and what shape its pixels are in.
dt_backbuf_t backbuf
volatile gint stop
static void test_snapshot_never_crosses_publications(void **state)
static gpointer _publisher_main(gpointer user_data)
#define SHAPE_B_H
#define HUNT_MICROSECONDS
static void test_field_by_field_read_crosses_publications(void **state)
static gboolean _pairing_is_coherent(const uint64_t hash, const size_t width, const size_t height)
Is this (hash, width, height) triple one that was ever published together?
#define SHAPE_A_HASH
int main(void)
static void test_single_field_setter_is_a_publication(void **state)
A single-field setter must publish coherently too – the histogram backbuffers are invalidated that wa...
#define SHAPE_B_HASH
#define SHAPE_B_W
#define SHAPE_A_H
#define SHAPE_A_W