1 #include <cstdint>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <array>
5 #include <memory>
6
7 #include <gtest/gtest.h>
8
9 #include "GL/osmesa.h"
10 #include "util/macros.h"
11 #include "util/u_endian.h"
12 #include "util/u_math.h"
13
14 typedef struct {
15 unsigned format;
16 GLenum type;
17 int bpp;
18 uint64_t expected;
19 } Params;
20
21 class OSMesaRenderTestFixture : public testing::TestWithParam<Params> {};
22
23 std::string
name_params(const testing::TestParamInfo<Params> params)24 name_params(const testing::TestParamInfo<Params> params) {
25 auto p = params.param;
26 std::string first, second;
27 switch (p.format) {
28 case OSMESA_RGBA:
29 first = "rgba";
30 break;
31 case OSMESA_BGRA:
32 first = "bgra";
33 break;
34 case OSMESA_RGB:
35 first = "rgb";
36 break;
37 case OSMESA_RGB_565:
38 first = "rgb_565";
39 break;
40 case OSMESA_ARGB:
41 first = "argb";
42 break;
43 }
44
45 switch (p.type) {
46 case GL_UNSIGNED_SHORT:
47 second = "unsigned_short";
48 break;
49 case GL_UNSIGNED_BYTE:
50 second = "unsigned_byte";
51 break;
52 case GL_FLOAT:
53 second = "float";
54 break;
55 case GL_UNSIGNED_SHORT_5_6_5:
56 second = "unsigned_short_565";
57 break;
58 }
59
60 return first + "_" + second;
61 };
62
TEST_P(OSMesaRenderTestFixture,Render)63 TEST_P(OSMesaRenderTestFixture, Render)
64 {
65 auto p = GetParam();
66 const int w = 2, h = 2;
67 uint8_t pixels[w * h * 8] = { 0 };
68
69 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
70 OSMesaCreateContext(p.format, NULL), &OSMesaDestroyContext};
71 ASSERT_TRUE(ctx);
72
73 auto ret = OSMesaMakeCurrent(ctx.get(), &pixels, p.type, w, h);
74 ASSERT_EQ(ret, GL_TRUE);
75
76 glClearColor(0.25, 1.0, 0.5, 0.75);
77
78 uint64_t expected = p.expected;
79
80 /* All the formats other than 565 and RGB/byte are array formats, but our
81 * expected values are packed, so byte swap appropriately.
82 */
83 if (UTIL_ARCH_BIG_ENDIAN) {
84 switch (p.bpp) {
85 case 8:
86 expected = util_bswap64(expected);
87 break;
88
89 case 4:
90 expected = util_bswap32(expected);
91 break;
92
93 case 3:
94 case 2:
95 break;
96 }
97 }
98
99 glClear(GL_COLOR_BUFFER_BIT);
100 glFinish();
101
102 #if 0 /* XXX */
103 for (unsigned i = 0; i < ARRAY_SIZE(pixels); i += 4) {
104 fprintf(stderr, "pixel %d: %02x %02x %02x %02x\n",
105 i / 4,
106 pixels[i + 0],
107 pixels[i + 1],
108 pixels[i + 2],
109 pixels[i + 3]);
110 }
111 #endif
112
113 for (unsigned i = 0; i < w * h; i++) {
114 switch (p.bpp) {
115 case 2: {
116 uint16_t color = 0;
117 memcpy(&color, &pixels[i * p.bpp], p.bpp);
118 ASSERT_EQ(expected, color);
119 break;
120 }
121
122 case 3: {
123 uint32_t color = ((pixels[i * p.bpp + 0] << 0) |
124 (pixels[i * p.bpp + 1] << 8) |
125 (pixels[i * p.bpp + 2] << 16));
126 ASSERT_EQ(expected, color);
127 break;
128 }
129
130 case 4: {
131 uint32_t color = 0;
132 memcpy(&color, &pixels[i * p.bpp], p.bpp);
133 ASSERT_EQ(expected, color);
134 break;
135 }
136
137 case 8: {
138 uint64_t color = 0;
139 memcpy(&color, &pixels[i * p.bpp], p.bpp);
140 ASSERT_EQ(expected, color);
141 break;
142 }
143
144 default:
145 unreachable("bad bpp");
146 }
147 }
148 }
149
150 INSTANTIATE_TEST_CASE_P(
151 OSMesaRenderTest,
152 OSMesaRenderTestFixture,
153 testing::Values(
154 Params{ OSMESA_RGBA, GL_UNSIGNED_BYTE, 4, 0xbf80ff40 },
155 Params{ OSMESA_BGRA, GL_UNSIGNED_BYTE, 4, 0xbf40ff80 },
156 Params{ OSMESA_ARGB, GL_UNSIGNED_BYTE, 4, 0x80ff40bf},
157 Params{ OSMESA_RGB, GL_UNSIGNED_BYTE, 3, 0x80ff40 },
158 Params{ OSMESA_RGBA, GL_UNSIGNED_SHORT, 8, 0xbfff8000ffff4000ull },
159 Params{ OSMESA_RGB_565, GL_UNSIGNED_SHORT_5_6_5, 2, ((0x10 << 0) |
160 (0x3f << 5) |
161 (0x8 << 11)) }
162 ),
163 name_params
164 );
165
TEST(OSMesaRenderTest,depth)166 TEST(OSMesaRenderTest, depth)
167 {
168 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
169 OSMesaCreateContextExt(OSMESA_RGB_565, 24, 8, 0, NULL), &OSMesaDestroyContext};
170 ASSERT_TRUE(ctx);
171
172 const int w = 3, h = 2;
173 uint8_t pixels[4096 * h * 2] = {0}; /* different cpp from our depth! */
174 auto ret = OSMesaMakeCurrent(ctx.get(), &pixels, GL_UNSIGNED_SHORT_5_6_5, w, h);
175 ASSERT_EQ(ret, GL_TRUE);
176
177 /* Expand the row length for the color buffer so we can see that it doesn't affect depth. */
178 OSMesaPixelStore(OSMESA_ROW_LENGTH, 4096);
179
180 uint32_t *depth;
181 GLint dw, dh, depth_cpp;
182 ASSERT_EQ(true, OSMesaGetDepthBuffer(ctx.get(), &dw, &dh, &depth_cpp, (void **)&depth));
183
184 ASSERT_EQ(dw, w);
185 ASSERT_EQ(dh, h);
186 ASSERT_EQ(depth_cpp, 4);
187
188 glClearDepth(1.0);
189 glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
190 glFinish();
191 EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff);
192 EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff);
193 EXPECT_EQ(depth[w * 1 + 0], 0x00ffffff);
194 EXPECT_EQ(depth[w * 1 + 1], 0x00ffffff);
195
196 /* Scissor to the top half and clear */
197 glEnable(GL_SCISSOR_TEST);
198 glScissor(0, 1, 2, 1);
199 glClearDepth(0.0);
200 glClear(GL_DEPTH_BUFFER_BIT);
201 glFinish();
202 EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff);
203 EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff);
204 EXPECT_EQ(depth[w * 1 + 0], 0x00000000);
205 EXPECT_EQ(depth[w * 1 + 1], 0x00000000);
206
207 /* Y_UP didn't affect depth buffer orientation in classic osmesa. */
208 OSMesaPixelStore(OSMESA_Y_UP, false);
209 glScissor(0, 1, 1, 1);
210 glClearDepth(1.0);
211 glClear(GL_DEPTH_BUFFER_BIT);
212 glFinish();
213 EXPECT_EQ(depth[w * 0 + 0], 0x00ffffff);
214 EXPECT_EQ(depth[w * 0 + 1], 0x00ffffff);
215 EXPECT_EQ(depth[w * 1 + 0], 0x00ffffff);
216 EXPECT_EQ(depth[w * 1 + 1], 0x00000000);
217 }
218
TEST(OSMesaRenderTest,depth_get_no_attachment)219 TEST(OSMesaRenderTest, depth_get_no_attachment)
220 {
221 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
222 OSMesaCreateContextExt(OSMESA_RGBA, 0, 0, 0, NULL), &OSMesaDestroyContext};
223 ASSERT_TRUE(ctx);
224
225 uint32_t pixel;
226 auto ret = OSMesaMakeCurrent(ctx.get(), &pixel, GL_UNSIGNED_BYTE, 1, 1);
227 ASSERT_EQ(ret, GL_TRUE);
228
229 uint32_t *depth;
230 GLint dw = 1, dh = 1, depth_cpp = 1;
231 ASSERT_EQ(false, OSMesaGetDepthBuffer(ctx.get(), &dw, &dh, &depth_cpp, (void **)&depth));
232 ASSERT_EQ(depth_cpp, NULL);
233 ASSERT_EQ(dw, 0);
234 ASSERT_EQ(dh, 0);
235 ASSERT_EQ(depth_cpp, 0);
236 }
237
be_bswap32(uint32_t x)238 static uint32_t be_bswap32(uint32_t x)
239 {
240 if (UTIL_ARCH_BIG_ENDIAN)
241 return util_bswap32(x);
242 else
243 return x;
244 }
245
TEST(OSMesaRenderTest,separate_buffers_per_context)246 TEST(OSMesaRenderTest, separate_buffers_per_context)
247 {
248 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx1{
249 OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext};
250 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx2{
251 OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext};
252 ASSERT_TRUE(ctx1);
253 ASSERT_TRUE(ctx2);
254
255 uint32_t pixel1, pixel2;
256
257 ASSERT_EQ(OSMesaMakeCurrent(ctx1.get(), &pixel1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
258 glClearColor(1.0, 0.0, 0.0, 0.0);
259 glClear(GL_COLOR_BUFFER_BIT);
260 glFinish();
261 EXPECT_EQ(pixel1, be_bswap32(0x000000ff));
262
263 ASSERT_EQ(OSMesaMakeCurrent(ctx2.get(), &pixel2, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
264 glClearColor(0.0, 1.0, 0.0, 0.0);
265 glClear(GL_COLOR_BUFFER_BIT);
266 glFinish();
267 EXPECT_EQ(pixel1, be_bswap32(0x000000ff));
268 EXPECT_EQ(pixel2, be_bswap32(0x0000ff00));
269
270 /* Leave a dangling render to pixel2 as we switch contexts (there should be
271 */
272 glClearColor(0.0, 0.0, 1.0, 0.0);
273 glClear(GL_COLOR_BUFFER_BIT);
274
275 ASSERT_EQ(OSMesaMakeCurrent(ctx1.get(), &pixel1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
276 /* Draw something off screen to trigger a real flush. We should have the
277 * same contents in pixel1 as before
278 */
279 glBegin(GL_TRIANGLES);
280 glVertex2f(-2, -2);
281 glVertex2f(-2, -2);
282 glVertex2f(-2, -2);
283 glEnd();
284 glFinish();
285 EXPECT_EQ(pixel1, be_bswap32(0x000000ff));
286 EXPECT_EQ(pixel2, be_bswap32(0x00ff0000));
287 }
288
TEST(OSMesaRenderTest,resize)289 TEST(OSMesaRenderTest, resize)
290 {
291 std::unique_ptr<osmesa_context, decltype(&OSMesaDestroyContext)> ctx{
292 OSMesaCreateContext(GL_RGBA, NULL), &OSMesaDestroyContext};
293 ASSERT_TRUE(ctx);
294
295 uint32_t draw1[1], draw2[4];
296
297 ASSERT_EQ(OSMesaMakeCurrent(ctx.get(), draw1, GL_UNSIGNED_BYTE, 1, 1), GL_TRUE);
298 glClearColor(1.0, 0.0, 0.0, 0.0);
299 glClear(GL_COLOR_BUFFER_BIT);
300 glFinish();
301 EXPECT_EQ(draw1[0], be_bswap32(0x000000ff));
302
303 ASSERT_EQ(OSMesaMakeCurrent(ctx.get(), draw2, GL_UNSIGNED_BYTE, 2, 2), GL_TRUE);
304 glClearColor(0.0, 1.0, 0.0, 0.0);
305 glClear(GL_COLOR_BUFFER_BIT);
306 glFinish();
307 for (unsigned i = 0; i < ARRAY_SIZE(draw2); i++)
308 EXPECT_EQ(draw2[i], be_bswap32(0x0000ff00));
309 EXPECT_EQ(draw1[0], be_bswap32(0x000000ff));
310 }
311