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#ifdef _WIN32
55#include "win/main_wrapper.h"
56#endif
57
58/* Two publications a clipping module's edit mode swaps between: the cropped frame, and the full
59 * transformed one it neutralises the crop to show. Different shape, different cacheline. */
60#define SHAPE_A_W 4032
61#define SHAPE_A_H 3024
62#define SHAPE_A_HASH 0x1111111111111111ull
63#define SHAPE_B_W 5104
64#define SHAPE_B_H 3880
65#define SHAPE_B_HASH 0x2222222222222222ull
66
67typedef struct publisher_t
68{
70 volatile gint stop;
71 guint64 publications;
73
74static gpointer _publisher_main(gpointer user_data)
75{
76 publisher_t *p = (publisher_t *)user_data;
77 while(!g_atomic_int_get(&p->stop))
78 {
81 p->publications += 2;
82 }
83 return NULL;
84}
85
87static gboolean _pairing_is_coherent(const uint64_t hash, const size_t width, const size_t height)
88{
89 if(hash == SHAPE_A_HASH) return width == SHAPE_A_W && height == SHAPE_A_H;
90 if(hash == SHAPE_B_HASH) return width == SHAPE_B_W && height == SHAPE_B_H;
91 return TRUE; // the seed value; not a publication either side authored
92}
93
94/* How long to hunt. Long enough that a miss means something on an idle machine, short enough
95 * that the suite stays a suite. */
96#define HUNT_MICROSECONDS 400000
97
99{
100 (void)state;
101 publisher_t p = { { 0 } };
103
104 GThread *writer = g_thread_new("backbuf-publisher", _publisher_main, &p);
105 assert_non_null(writer);
106
107 gint64 crossed = 0;
108 gint64 reads = 0;
109 const gint64 deadline = g_get_monotonic_time() + HUNT_MICROSECONDS;
110 while(g_get_monotonic_time() < deadline && crossed == 0)
111 {
112 /* The display path's shape: take the hash, resolve a cacheline from it, and only then ask
113 * how wide the pixels are. The resolve is what makes the window wide enough to matter; a
114 * compiler barrier stands in for it. */
115 const uint64_t hash = dt_dev_backbuf_get_hash(&p.backbuf);
116 __asm__ __volatile__("" ::: "memory");
117 const size_t width = p.backbuf.width;
118 const size_t height = p.backbuf.height;
119
120 reads++;
121 if(!_pairing_is_coherent(hash, width, height)) crossed++;
122 }
123
124 g_atomic_int_set(&p.stop, 1);
125 g_thread_join(writer);
126
127 print_message("field-by-field: %" G_GINT64_FORMAT " reads, %" G_GINT64_FORMAT " crossed pairings\n", reads,
128 crossed);
129 assert_true(crossed > 0);
130}
131
133{
134 (void)state;
135 publisher_t p = { { 0 } };
137
138 GThread *writer = g_thread_new("backbuf-publisher", _publisher_main, &p);
139 assert_non_null(writer);
140
141 gint64 crossed = 0;
142 gint64 reads = 0;
143 const gint64 deadline = g_get_monotonic_time() + HUNT_MICROSECONDS;
144 while(g_get_monotonic_time() < deadline)
145 {
146 const dt_backbuf_state_t published = dt_dev_backbuf_snapshot(&p.backbuf);
147 reads++;
148 if(!_pairing_is_coherent(published.hash, published.width, published.height)) crossed++;
149 }
150
151 g_atomic_int_set(&p.stop, 1);
152 g_thread_join(writer);
153
154 print_message("snapshot: %" G_GINT64_FORMAT " reads, %" G_GINT64_FORMAT " crossed pairings\n", reads, crossed);
155 assert_int_equal(crossed, 0);
156}
157
161{
162 (void)state;
163 dt_backbuf_t backbuf = { 0 };
165
167
168 const dt_backbuf_state_t published = dt_dev_backbuf_snapshot(&backbuf);
169 assert_int_equal(published.hash, DT_PIXELPIPE_CACHE_HASH_INVALID);
170 assert_int_equal(published.width, SHAPE_A_W);
171 assert_int_equal(published.height, SHAPE_A_H);
172}
173
174int main(int argc, char *argv[])
175{
176 const struct CMUnitTest tests[] = {
180 };
181 return cmocka_run_group_tests(tests, NULL, NULL);
182}
183
184// clang-format off
185// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
186// vim: shiftwidth=2 expandtab tabstop=2 cindent
187// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
188// 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:2226
hash
Definition layers.h:90
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)
int main()
Definition prova.c:47
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
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