test-render.cpp revision 7ec681f3
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
14typedef struct {
15   unsigned format;
16   GLenum type;
17   int bpp;
18   uint64_t expected;
19} Params;
20
21class OSMesaRenderTestFixture : public testing::TestWithParam<Params> {};
22
23std::string
24name_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
63TEST_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
150INSTANTIATE_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
166TEST(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
219TEST(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
238static 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
246TEST(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
289TEST(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