• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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