Allegro 4.4 RC2 - polygon3d
Niunio

This is the possible bug I was talking the last months. May be it only affects to Pascal because I can't reproduce it in C.

The problem is "polygon3d" generates a segmentation fault when rendering textured 3D polygons with "POLYTYPE_PTEX" modifier when the polygon is (almost) perpendicular to the screen plane. After some tests I did find it fails with angles <188, 74, 188>, <196, 53, 128>, <31, 62, 188> and its equivalents (<1212, 330, 1212>, <193, 53, 384>, etc).

The attached file is the simplest test program I used (included the wrapper units needed). Just change the initial angle values to reproduce the error faster. You can compile it with Free Pascal (included in several Linux distros). To compile, from the same directory, just execute "fpc -g test" ("-g" generates debug information). Of course you need Allegro installed.

GullRaDriel

I will perhaps give it a go this evening, but no promise Niunio.

Thomas Fjellstrom

I don't think it can be a real allegro bug if you can't reproduce it in C.

Niunio

[edit] I've updated the attached file on the first message because I find an error in one of the loops. Anyway, it fails the same way[/edit]

I tried to reproduce it in C, so I translate my test program to C:

#SelectExpand
1/* Testing 3D polygons. */ 2 3#include <allegro.h> 4#include <stdio.h> 5#include <stdlib.h> 6 7 8 BITMAP *Texture, *BackBuffer; 9 10 11 12/* Creates a texture to be used by the cube. */ 13 void CreateTexture (void) 14 { 15 int Black, White, Green; 16 17 Black = makecol (0, 0, 0); 18 White = makecol (255, 255, 255); 19 Green = makecol (0, 255, 0); 20 if (!(Texture = create_bitmap (32, 32))) 21 puts ("Can't create texture."); 22 clear_to_color (Texture, Black); 23 line (Texture, 0, 0, 31, 31, White); 24 line (Texture, 0, 32, 32, 0, White); 25 rect (Texture, 0, 0, 31, 31, White); 26 textout_ex (Texture, font, "dead", 0, 0, Green, -1); 27 textout_ex (Texture, font, "pigs", 0, 8, Green, -1); 28 textout_ex (Texture, font, "cant", 0, 16, Green, -1); 29 textout_ex (Texture, font, "fly.", 0, 24, Green, -1); 30 } 31 32 33 34/* This procedure tests the polygon. */ 35 void DoTest (int aMode) 36 { 37 V3D_f Vertex[2], VertexR[2]; 38 float Ax, Ay, Az, 39 Rx, Ry, Rz; 40 int Vtx; 41 MATRIX_f Matrix; 42 43 /* Vertex. */ 44 Vertex[0].x = 0; 45 Vertex[1].x = -1; 46 Vertex[2].x = 1; 47 Vertex[0].y = 1; 48 Vertex[1].y = 0; 49 Vertex[2].y = 0; 50 Vertex[0].z = 0; 51 Vertex[1].z = 0; 52 Vertex[2].z = 0; 53 /* Texture mapping. */ 54 Vertex[0].u = 15; 55 Vertex[1].u = 0; 56 Vertex[2].u = 31; 57 Vertex[0].v = 0; 58 Vertex[1].v = 31; 59 Vertex[2].v = 31; 60 for (Vtx=0; Vtx<3; ++Vtx) { 61 VertexR[Vtx].u = Vertex[Vtx].u; 62 VertexR[Vtx].v = Vertex[Vtx].v; 63 } 64 /* Angles. */ 65 Ax = 0; 66 Ay = 0; 67 Az = 0; 68 Rx = (float)((rand () % 32) - 16) / 8; 69 Ry = (float)((rand () % 32) - 16) / 8; 70 Rz = (float)((rand () % 32) - 16) / 8; 71 /* Testing. */ 72 do { 73 /* Animation. */ 74 Ax += Rx; 75 Ay += Ry; 76 Az += Rz; 77printf ("<%d, %d, %d>\n", (int)Ax, (int)Ay, (int)Az); 78 get_transformation_matrix_f (&Matrix, 1, Ax, Ay, Az, 0, 0, -3); 79 for (Vtx=0; Vtx<3; ++Vtx) { 80 apply_matrix_f (&Matrix, 81 Vertex [Vtx].x, Vertex [Vtx].y, Vertex [Vtx].z, 82 &(VertexR[Vtx].x), &(VertexR[Vtx].y), &(VertexR[Vtx].z)); 83 persp_project_f (VertexR[Vtx].x, VertexR[Vtx].y, VertexR[Vtx].z, 84 &(VertexR[Vtx].x), &(VertexR[Vtx].y)); 85 } 86 /* Output. */ 87 clear_bitmap (BackBuffer); 88 textout_centre_ex (BackBuffer, font, 89 aMode == POLYTYPE_ATEX ? "POLYTYPE_ATEX" : "POLYTYPE_PTEX", 90 160, 1, makecol (255, 255, 255), -1); 91 triangle3d_f (BackBuffer, aMode, Texture, &(VertexR[0]), &(VertexR[1]), &(VertexR[2])); 92 vsync; 93 blit (BackBuffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); 94 } while (!keypressed ()); 95 readkey (); /* Clear buffer. */ 96 } 97 98 99 100int main (void) /* The program starts here. */ 101{ 102/* You should always do this at the start of Allegro programs. */ 103 if (allegro_init () != 0) { 104 puts ("Can't initialize Allegro!"); 105 return EXIT_FAILURE; 106 } 107 install_keyboard (); 108 install_timer (); 109 110/* Set a graphics mode sized 320x200. */ 111 if (set_gfx_mode (GFX_AUTODETECT_WINDOWED, 320, 200, 0, 0) != 0) 112 if (set_gfx_mode (GFX_SAFE, 320, 200, 0, 0) != 0) { 113 set_gfx_mode (GFX_TEXT, 0, 0, 0, 0); 114 /* Show an error message. */ 115 allegro_message ("Error setting graphics mode"); 116 allegro_exit (); 117 return EXIT_FAILURE; 118 } 119 BackBuffer = create_bitmap (SCREEN_W, SCREEN_H); 120 CreateTexture (); 121 set_projection_viewport (0, 0, SCREEN_W, SCREEN_H); 122 123 DoTest (POLYTYPE_ATEX); 124 DoTest (POLYTYPE_PTEX); 125 126 destroy_bitmap (BackBuffer); 127 destroy_bitmap (Texture); 128 allegro_exit (); 129 return EXIT_SUCCESS; 130} 131 132END_OF_MAIN ();

I think it's a perfect translation of the Pascal program, but I don't know why it's so chaotic. ???

GullRaDriel

And so, is the bug also visible in C with your chaotic (;-)) test program ?

gnolam

That code has an array overrun.

Niunio said:
V3D_f Vertex[2], VertexR[2];

[...]

    Vertex[2].x =  1;

GullRaDriel

ouch ^^

Niunio
gnolam said:

That code has an array overrun.

Duh! :-X

And so, is the bug also visible in C with your chaotic (;-)) test program ?

Once fixed the problem gnolam pointed to it seems to work. :-/

I don't think it can be a real allegro bug if you can't reproduce it in C.

I'm not sure. If you use Allegro.pas with Allegro 4.4.0 RC1 there is a similar problem with rotate_sprite, and previously with fixed-point maths, but there are no problems with RC2 and I didn't change my code. ???

May be there's a calling convention issue or something?

Peter Wang

I can reproduce the crash in the pascal version. It doesn't crash under valgrind though, nor does valgrind flag anything strange.

EDIT: fpc is probably enabling overflow detection in float->int conversion. The problem is in cscan.h (FUNC_POLY_SCANLINE_PTEX):

   for (x = w - 1; x >= 0; x -= 4) {
      long nextu, nextv, du, dv;
      PIXEL_PTR s;
      unsigned long color;

      fu += dfu;
      fv += dfv;
      fz += dfz;
      nextu = fu * z1;   // here
      nextv = fv * z1;   // here
      // ...snip...
   }

If I change nextu, nextv to int64_t instead of long, the SIGFPE goes away.

Next question is if this is the correct fix.

Niunio

fpc is probably enabling overflow detection in float->int conversion. The problem is in cscan.h (FUNC_POLY_SCANLINE_PTEX):

   for (x = w - 1; x >= 0; x -= 4) {
      long nextu, nextv, du, dv;
      PIXEL_PTR s;
      unsigned long color;

      fu += dfu;
      fv += dfv;
      fz += dfz;
      nextu = fu * z1;   // here
      nextv = fv * z1;   // here
      // ...snip...
   }

If I change nextu, nextv to int64_t instead of long, the SIGFPE goes away.

Next question is if this is the correct fix.

I confirm this change fixes the problem. Thanks for the tip, Peter. :)

Pascal is very strict about data typing, but I didn't know that "strictness" affects also to libraries written and compiled in other languages! :o

Thomas Fjellstrom

If it uses a CPU exception to handle the conversion, yeah it'll break anything ;)

Niunio

A small update:

I was testing the fix suggested by Peter. It seems to work but should be applied in more functions. I did changed it in all the ones that uses similar code in cscan.h file and now all examples works. :D

If it uses a CPU exception to handle the conversion, yeah it'll break anything

Didn't know about CPU exception. That explains a lot. Thanks.

So, next release will have this change, will not?

Elias

int64_t looks like a better choice than long here - it's in general only very rare situations where you would want to use long instead of int64_t. But when that code originally was written most likely we didn't have the fixed-width types yet.

Thread #602423. Printed from Allegro.cc