blob: 6a10657ac95f9f0266313c4b6264100df0a8e9f3 [file] [log] [blame]
Nico Hubera455f0e2018-01-07 11:40:40 +01001with Ada.Numerics.Discrete_Random;
Nico Huberfda2d6e2017-07-09 16:47:52 +02002with Ada.Unchecked_Conversion;
Nico Huber1d0abe42017-03-05 14:14:09 +01003with Ada.Command_Line;
4with Interfaces.C;
5
Nico Huber3b654a02017-07-15 22:27:14 +02006with HW.Time;
Nico Huber1d0abe42017-03-05 14:14:09 +01007with HW.Debug;
Nico Huberfda2d6e2017-07-09 16:47:52 +02008with HW.PCI.Dev;
9with HW.MMIO_Range;
Nico Huber3b654a02017-07-15 22:27:14 +020010with HW.GFX.GMA.Config;
Nico Huber1d0abe42017-03-05 14:14:09 +010011with HW.GFX.GMA.Display_Probing;
12
Nico Huberfda2d6e2017-07-09 16:47:52 +020013package body HW.GFX.GMA.GFX_Test
14is
15 pragma Disable_Atomic_Synchronization;
Nico Huber1d0abe42017-03-05 14:14:09 +010016
Nico Hubera455f0e2018-01-07 11:40:40 +010017 Primary_Delay_MS : constant := 8_000;
18 Secondary_Delay_MS : constant := 4_000;
Nico Hubera563ec22019-09-29 19:07:27 +020019 HP_Delay_MS : constant := 500;
Nico Hubera455f0e2018-01-07 11:40:40 +010020 Seed : constant := 12345;
21
Nico Hubera63e8332018-02-01 16:41:30 +010022 package Rand_P is new Ada.Numerics.Discrete_Random (Natural);
Nico Huberd8282b62018-06-18 00:44:55 +020023 function Rand (Gen : Rand_P.Generator)
24 return Int32 is (Int32 (Rand_P.Random (Gen)));
Nico Hubera455f0e2018-01-07 11:40:40 +010025
Nico Huber5ef4d602017-12-13 13:56:47 +010026 Start_X : constant := 0;
27 Start_Y : constant := 0;
28
Nico Huberfda2d6e2017-07-09 16:47:52 +020029 package Dev is new PCI.Dev (PCI.Address'(0, 2, 0));
Nico Huber1d0abe42017-03-05 14:14:09 +010030
Nico Huberc76749d2018-06-09 22:04:55 +020031 type GTT_Entry is record
32 Addr : GTT_Address_Type;
33 Valid : Boolean;
34 end record;
35 GTT_Backup : array (GTT_Range) of GTT_Entry;
Nico Huber3b654a02017-07-15 22:27:14 +020036
37 procedure Backup_GTT
38 is
39 begin
40 for Idx in GTT_Range loop
Nico Huberc76749d2018-06-09 22:04:55 +020041 Read_GTT (GTT_Backup (Idx).Addr, GTT_Backup (Idx).Valid, Idx);
Nico Huber3b654a02017-07-15 22:27:14 +020042 end loop;
43 end Backup_GTT;
44
45 procedure Restore_GTT
46 is
47 begin
48 for Idx in GTT_Range loop
Nico Huberc76749d2018-06-09 22:04:55 +020049 Write_GTT (Idx, GTT_Backup (Idx).Addr, GTT_Backup (Idx).Valid);
Nico Huber3b654a02017-07-15 22:27:14 +020050 end loop;
51 end Restore_GTT;
52
Nico Huber1d0abe42017-03-05 14:14:09 +010053 type Pixel_Type is record
54 Red : Byte;
55 Green : Byte;
56 Blue : Byte;
57 Alpha : Byte;
58 end record;
59
60 for Pixel_Type use record
61 Blue at 0 range 0 .. 7;
62 Green at 1 range 0 .. 7;
63 Red at 2 range 0 .. 7;
64 Alpha at 3 range 0 .. 7;
65 end record;
66
Nico Huber244ea7e2017-08-28 11:38:23 +020067 White : constant Pixel_Type := (255, 255, 255, 255);
68 Black : constant Pixel_Type := ( 0, 0, 0, 255);
69 Red : constant Pixel_Type := (255, 0, 0, 255);
70 Green : constant Pixel_Type := ( 0, 255, 0, 255);
71 Blue : constant Pixel_Type := ( 0, 0, 255, 255);
72
Nico Huberfda2d6e2017-07-09 16:47:52 +020073 function Pixel_To_Word (P : Pixel_Type) return Word32
74 with
75 SPARK_Mode => Off
76 is
77 function To_Word is new Ada.Unchecked_Conversion (Pixel_Type, Word32);
78 begin
79 return To_Word (P);
80 end Pixel_To_Word;
81
Nico Huber7bb10c62018-01-12 14:07:44 +010082 Max_W : constant := 4096;
83 Max_H : constant := 2160;
84 FB_Align : constant := 16#0004_0000#;
85 Cursor_Align : constant := 16#0001_0000#;
86 Max_Cursor_Wid : constant := 256;
87 subtype Screen_Index is Natural range 0 .. 3 *
88 (Max_W * Max_H + FB_Align / 4 +
89 3 * Max_Cursor_Wid * Max_Cursor_Wid + Cursor_Align / 4)
90 - 1;
Nico Huberfda2d6e2017-07-09 16:47:52 +020091 type Screen_Type is array (Screen_Index) of Word32;
Nico Huber1d0abe42017-03-05 14:14:09 +010092
Nico Huber34be6542017-12-13 09:26:24 +010093 function Screen_Offset (FB : Framebuffer_Type) return Natural is
94 (Natural (Phys_Offset (FB) / 4));
95
Nico Huberfda2d6e2017-07-09 16:47:52 +020096 package Screen is new MMIO_Range (0, Word32, Screen_Index, Screen_Type);
Nico Huber1d0abe42017-03-05 14:14:09 +010097
Nico Huber3b654a02017-07-15 22:27:14 +020098 Screen_Backup : Screen_Type;
99
100 procedure Backup_Screen (FB : Framebuffer_Type)
101 is
Nico Huber34be6542017-12-13 09:26:24 +0100102 First : constant Screen_Index := Screen_Offset (FB);
Nico Huber3b654a02017-07-15 22:27:14 +0200103 Last : constant Screen_Index := First + Natural (FB_Size (FB)) / 4 - 1;
104 begin
105 for Idx in Screen_Index range First .. Last loop
106 Screen.Read (Screen_Backup (Idx), Idx);
107 end loop;
108 end Backup_Screen;
109
110 procedure Restore_Screen (FB : Framebuffer_Type)
111 is
Nico Huber34be6542017-12-13 09:26:24 +0100112 First : constant Screen_Index := Screen_Offset (FB);
Nico Huber3b654a02017-07-15 22:27:14 +0200113 Last : constant Screen_Index := First + Natural (FB_Size (FB)) / 4 - 1;
114 begin
115 for Idx in Screen_Index range First .. Last loop
116 Screen.Write (Idx, Screen_Backup (Idx));
117 end loop;
118 end Restore_Screen;
Nico Huber1d0abe42017-03-05 14:14:09 +0100119
Nico Huber5ef4d602017-12-13 13:56:47 +0100120 function Drawing_Width (FB : Framebuffer_Type) return Natural is
121 (Natural (FB.Width + 2 * Start_X));
122
123 function Drawing_Height (FB : Framebuffer_Type) return Natural is
124 (Natural (FB.Height + 2 * Start_Y));
125
Nico Huber244ea7e2017-08-28 11:38:23 +0200126 function Corner_Fill
127 (X, Y : Natural;
128 FB : Framebuffer_Type;
129 Pipe : Pipe_Index)
130 return Pixel_Type
131 is
132 Xrel : constant Integer :=
Nico Huber5ef4d602017-12-13 13:56:47 +0100133 (if X < 32 then X else X - (Drawing_Width (FB) - 32));
Nico Huber244ea7e2017-08-28 11:38:23 +0200134 Yrel : constant Integer :=
Nico Huber5ef4d602017-12-13 13:56:47 +0100135 (if Y < 32 then Y else Y - (Drawing_Height (FB) - 32));
Nico Huber244ea7e2017-08-28 11:38:23 +0200136
137 function Color (Idx : Natural) return Pixel_Type is
138 (case (Idx + Pipe_Index'Pos (Pipe)) mod 4 is
139 when 0 => Blue, when 1 => Black,
140 when 3 => Green, when others => Red);
141 begin
142 return
143 (if Xrel mod 16 = 0 or Xrel = 31 or Yrel mod 16 = 0 or Yrel = 31 then
144 White
145 elsif Yrel < 16 then
146 (if Xrel < 16 then Color (0) else Color (1))
147 else
148 (if Xrel < 16 then Color (3) else Color (2)));
149 end Corner_Fill;
150
Nico Huber1d0abe42017-03-05 14:14:09 +0100151 function Fill
152 (X, Y : Natural;
153 Framebuffer : Framebuffer_Type;
Nico Huber244ea7e2017-08-28 11:38:23 +0200154 Pipe : Pipe_Index)
Nico Huber1d0abe42017-03-05 14:14:09 +0100155 return Pixel_Type
156 is
157 use type HW.Byte;
158
Nico Huber5ef4d602017-12-13 13:56:47 +0100159 Xp : constant Natural := X * 256 / Drawing_Width (Framebuffer);
160 Yp : constant Natural := Y * 256 / Drawing_Height (Framebuffer);
Nico Huber1d0abe42017-03-05 14:14:09 +0100161 Xn : constant Natural := 255 - Xp;
162 Yn : constant Natural := 255 - Yp;
163
164 function Map (X, Y : Natural) return Byte is
165 begin
166 return Byte (X * Y / 255);
167 end Map;
168 begin
169 return
170 (case Pipe is
171 when GMA.Primary => (Map (Xn, Yn), Map (Xp, Yn), Map (Xp, Yp), 255),
172 when GMA.Secondary => (Map (Xn, Yp), Map (Xn, Yn), Map (Xp, Yn), 255),
173 when GMA.Tertiary => (Map (Xp, Yp), Map (Xn, Yp), Map (Xn, Yn), 255));
174 end Fill;
175
176 procedure Test_Screen
177 (Framebuffer : Framebuffer_Type;
178 Pipe : GMA.Pipe_Index)
179 is
Nico Huber1d0abe42017-03-05 14:14:09 +0100180 P : Pixel_Type;
181 -- We have pixel offset wheras the framebuffer has a byte offset
Nico Huber34be6542017-12-13 09:26:24 +0100182 Offset_Y : Natural := Screen_Offset (Framebuffer);
Nico Huber1d0abe42017-03-05 14:14:09 +0100183 Offset : Natural;
Nico Huber9ca69f12017-08-28 14:31:46 +0200184
185 function Top_Test (X, Y : Natural) return Boolean
186 is
Nico Huber5ef4d602017-12-13 13:56:47 +0100187 C : constant Natural := Drawing_Width (Framebuffer) / 2;
188 S_Y : constant Natural := 3 * (Y - Start_Y) / 2;
Nico Huber9ca69f12017-08-28 14:31:46 +0200189 Left : constant Integer := X - C + S_Y;
190 Right : constant Integer := X - C - S_Y;
191 begin
192 return
Nico Huber5ef4d602017-12-13 13:56:47 +0100193 (Y - Start_Y) < 12 and
Nico Huber9ca69f12017-08-28 14:31:46 +0200194 ((-1 <= Left and Left <= 0) or
195 (0 <= Right and Right <= 1));
196 end Top_Test;
Nico Huber1d0abe42017-03-05 14:14:09 +0100197 begin
Nico Huber5ef4d602017-12-13 13:56:47 +0100198 for Y in 0 .. Drawing_Height (Framebuffer) - 1 loop
Nico Huber1d0abe42017-03-05 14:14:09 +0100199 Offset := Offset_Y;
Nico Huber5ef4d602017-12-13 13:56:47 +0100200 for X in 0 .. Drawing_Width (Framebuffer) - 1 loop
201 if (X < 32 or X >= Drawing_Width (Framebuffer) - 32) and
202 (Y < 32 or Y >= Drawing_Height (Framebuffer) - 32)
Nico Huber244ea7e2017-08-28 11:38:23 +0200203 then
204 P := Corner_Fill (X, Y, Framebuffer, Pipe);
Nico Huber9ca69f12017-08-28 14:31:46 +0200205 elsif Framebuffer.Rotation /= No_Rotation and then
206 Top_Test (X, Y)
207 then
208 P := White;
Nico Huber244ea7e2017-08-28 11:38:23 +0200209 elsif Y mod 16 = 0 or X mod 16 = 0 then
210 P := Black;
Nico Huber1d0abe42017-03-05 14:14:09 +0100211 else
212 P := Fill (X, Y, Framebuffer, Pipe);
213 end if;
Nico Huberfda2d6e2017-07-09 16:47:52 +0200214 Screen.Write (Offset, Pixel_To_Word (P));
Nico Huber1d0abe42017-03-05 14:14:09 +0100215 Offset := Offset + 1;
216 end loop;
217 Offset_Y := Offset_Y + Natural (Framebuffer.Stride);
218 end loop;
219 end Test_Screen;
220
Nico Huber7bb10c62018-01-12 14:07:44 +0100221 function Donut (X, Y, Max : Cursor_Pos) return Byte
222 is
223 ZZ : constant Int32 := Max * Max * 2;
224 Dist_Center : constant Int32 := ((X * X + Y * Y) * 255) / ZZ;
225 Dist_Circle : constant Int32 := Dist_Center - 20;
226 begin
227 return Byte (255 - Int32'Min (255, 6 * abs Dist_Circle + 64));
228 end Donut;
229
230 procedure Draw_Cursor (Pipe : Pipe_Index; Cursor : Cursor_Type)
231 is
232 use type HW.Byte;
233 Width : constant Width_Type := Cursor_Width (Cursor.Size);
234 Screen_Offset : Natural :=
235 Natural (Shift_Left (Word32 (Cursor.GTT_Offset), 12) / 4);
236 begin
237 if Cursor.Mode /= ARGB_Cursor then
238 return;
239 end if;
240 for Y in Cursor_Pos range -Width / 2 .. Width / 2 - 1 loop
241 for X in Cursor_Pos range -Width / 2 .. Width / 2 - 1 loop
242 declare
243 D : constant Byte := Donut (X, Y, Width / 2);
244 begin
245 -- Hardware seems to expect pre-multiplied alpha (i.e.
246 -- color components already contain the alpha).
247 Screen.Write
248 (Index => Screen_Offset,
249 Value => Pixel_To_Word (
250 (Red => (if Pipe = Secondary then D / 2 else 0),
251 Green => (if Pipe = Tertiary then D / 2 else 0),
252 Blue => (if Pipe = Primary then D / 2 else 0),
253 Alpha => D)));
254 Screen_Offset := Screen_Offset + 1;
255 end;
256 end loop;
257 end loop;
258 end Draw_Cursor;
259
Nico Huber1d0abe42017-03-05 14:14:09 +0100260 procedure Calc_Framebuffer
261 (FB : out Framebuffer_Type;
262 Mode : in Mode_Type;
Nico Huber88f3c982017-08-28 13:31:38 +0200263 Rotation : in Rotation_Type;
Nico Huber1d0abe42017-03-05 14:14:09 +0100264 Offset : in out Word32)
265 is
Nico Huberc5c767a2018-06-03 01:09:04 +0200266 Width : constant Width_Type := Mode.H_Visible;
267 Height : constant Height_Type := Mode.V_Visible;
Nico Huber1d0abe42017-03-05 14:14:09 +0100268 begin
269 Offset := (Offset + FB_Align - 1) and not (FB_Align - 1);
Nico Huber88f3c982017-08-28 13:31:38 +0200270 if Rotation = Rotated_90 or Rotation = Rotated_270 then
271 FB :=
Nico Huberc5c767a2018-06-03 01:09:04 +0200272 (Width => Height,
273 Height => Width,
Nico Huber5ef4d602017-12-13 13:56:47 +0100274 Start_X => Start_X,
275 Start_Y => Start_Y,
Nico Huber88f3c982017-08-28 13:31:38 +0200276 BPC => 8,
Nico Huberc5c767a2018-06-03 01:09:04 +0200277 Stride => Div_Round_Up (Height + 2 * Start_X, 32) * 32,
278 V_Stride => Div_Round_Up (Width + 2 * Start_Y, 32) * 32,
Nico Huber88f3c982017-08-28 13:31:38 +0200279 Tiling => Y_Tiled,
280 Rotation => Rotation,
Nico Huber34be6542017-12-13 09:26:24 +0100281 Offset => Offset + Word32 (GTT_Rotation_Offset) * GTT_Page_Size);
Nico Huber88f3c982017-08-28 13:31:38 +0200282 else
283 FB :=
Nico Huber5ef4d602017-12-13 13:56:47 +0100284 (Width => Width,
285 Height => Height,
286 Start_X => Start_X,
287 Start_Y => Start_Y,
Nico Huber88f3c982017-08-28 13:31:38 +0200288 BPC => 8,
Nico Huber5ef4d602017-12-13 13:56:47 +0100289 Stride => Div_Round_Up (Width + 2 * Start_X, 16) * 16,
290 V_Stride => Height + 2 * Start_Y,
Nico Huber88f3c982017-08-28 13:31:38 +0200291 Tiling => Linear,
292 Rotation => Rotation,
293 Offset => Offset);
294 end if;
Nico Huberb7470492017-11-30 14:48:35 +0100295 Offset := Offset + Word32 (FB_Size (FB));
Nico Huber1d0abe42017-03-05 14:14:09 +0100296 end Calc_Framebuffer;
297
Nico Huber7bb10c62018-01-12 14:07:44 +0100298 type Cursor_Array is array (Cursor_Size) of Cursor_Type;
299 Cursors : array (Pipe_Index) of Cursor_Array;
300
301 procedure Prepare_Cursors
302 (Cursors : out Cursor_Array;
303 Offset : in out Word32)
304 is
Nico Huber7bb10c62018-01-12 14:07:44 +0100305 GMA_Phys_Base_Mask : constant := 16#fff0_0000#;
306
307 Phys_Base : Word32;
308 Success : Boolean;
309 begin
Nico Huber87719ae2024-06-20 13:06:05 +0000310 if Config.GMA_Base_Is_64bit then
311 Dev.Read32 (Phys_Base, Config.GMA_Phys_Base_Index + 4);
312 if Phys_Base /= 0 then
313 pragma Debug (Debug.Put_Line ("Cannot handle 64-bit DSM yet."));
314 return;
315 end if;
316 end if;
317
318 Dev.Read32 (Phys_Base, Config.GMA_Phys_Base_Index);
Nico Huber7bb10c62018-01-12 14:07:44 +0100319 Phys_Base := Phys_Base and GMA_Phys_Base_Mask;
320 Success := Phys_Base /= GMA_Phys_Base_Mask and Phys_Base /= 0;
321 if not Success then
322 Debug.Put_Line ("Failed to read stolen memory base.");
323 return;
324 end if;
325
326 for Size in Cursor_Size loop
327 Offset := (Offset + Cursor_Align - 1) and not (Cursor_Align - 1);
328 declare
329 Width : constant Width_Type := Cursor_Width (Size);
330 GTT_End : constant Word32 := Offset + Word32 (Width * Width) * 4;
331 begin
332 Cursors (Size) :=
333 (Mode => ARGB_Cursor,
334 Size => Size,
335 Center_X => Width,
336 Center_Y => Width,
337 GTT_Offset => GTT_Range (Shift_Right (Offset, 12)));
338 while Offset < GTT_End loop
339 GMA.Write_GTT
340 (GTT_Page => GTT_Range (Offset / GTT_Page_Size),
341 Device_Address => GTT_Address_Type (Phys_Base + Offset),
342 Valid => True);
343 Offset := Offset + GTT_Page_Size;
344 end loop;
345 end;
346 end loop;
347 end Prepare_Cursors;
348
Nico Huber3b654a02017-07-15 22:27:14 +0200349 Pipes : GMA.Pipe_Configs;
350
Nico Huberd8282b62018-06-18 00:44:55 +0200351 procedure Prepare_Configs (Rotation : Rotation_Type; Gen : Rand_P.Generator)
Nico Huber1d0abe42017-03-05 14:14:09 +0100352 is
353 use type HW.GFX.GMA.Port_Type;
354
Nico Huberfda2d6e2017-07-09 16:47:52 +0200355 Offset : Word32 := 0;
Nico Huber3b654a02017-07-15 22:27:14 +0200356 Success : Boolean;
Nico Huber1d0abe42017-03-05 14:14:09 +0100357 begin
358 GMA.Display_Probing.Scan_Ports (Pipes);
359
360 for Pipe in GMA.Pipe_Index loop
361 if Pipes (Pipe).Port /= GMA.Disabled then
362 Calc_Framebuffer
363 (FB => Pipes (Pipe).Framebuffer,
364 Mode => Pipes (Pipe).Mode,
Nico Huber88f3c982017-08-28 13:31:38 +0200365 Rotation => Rotation,
Nico Huber1d0abe42017-03-05 14:14:09 +0100366 Offset => Offset);
Nico Huber3b654a02017-07-15 22:27:14 +0200367 GMA.Setup_Default_FB
368 (FB => Pipes (Pipe).Framebuffer,
369 Clear => False,
370 Success => Success);
371 if not Success then
372 Pipes (Pipe).Port := GMA.Disabled;
373 end if;
Nico Huber1d0abe42017-03-05 14:14:09 +0100374 end if;
Nico Huber7bb10c62018-01-12 14:07:44 +0100375 Prepare_Cursors (Cursors (Pipe), Offset);
Nico Huberd8282b62018-06-18 00:44:55 +0200376 Pipes (Pipe).Cursor := Cursors (Pipe) (Cursor_Size'Val (Rand (Gen) mod 3));
Nico Huber1d0abe42017-03-05 14:14:09 +0100377 end loop;
378
379 GMA.Dump_Configs (Pipes);
380 end Prepare_Configs;
381
Nico Hubera63e8332018-02-01 16:41:30 +0100382 procedure Script_Cursors
Nico Hubera563ec22019-09-29 19:07:27 +0200383 (Pipes : in out GMA.Pipe_Configs;
384 Hotplug_List : out Display_Probing.Port_List;
385 Total_Deadline : in Time.T;
386 Time_MS : in Natural)
Nico Hubera63e8332018-02-01 16:41:30 +0100387 is
388 type Corner is (UL, UR, LR, LL);
389 type Cursor_Script_Entry is record
390 Rel : Corner;
391 X, Y : Int32;
392 end record;
393 Cursor_Script : constant array (Natural range 0 .. 19) of Cursor_Script_Entry :=
394 ((UL, 16, 16), (UL, 16, 16), (UL, 16, 16), (UL, -32, 0), (UL, 16, 16),
395 (UR, -16, 16), (UR, -16, 16), (UR, -16, 16), (UR, 0, -32), (UR, -16, 16),
396 (LR, -16, -16), (LR, -16, -16), (LR, -16, -16), (LR, 32, 0), (LR, -16, -16),
397 (LL, 16, -16), (LL, 16, -16), (LL, 16, -16), (LL, 0, 32), (LL, 16, -16));
398
399 Deadline : constant Time.T := Time.MS_From_Now (Time_MS);
Nico Hubera563ec22019-09-29 19:07:27 +0200400 HP_Deadline : Time.T := Time.MS_From_Now (HP_Delay_MS);
Nico Hubera63e8332018-02-01 16:41:30 +0100401 Timed_Out : Boolean := False;
402 Cnt : Word32 := 0;
403 begin
Nico Hubera563ec22019-09-29 19:07:27 +0200404 Hotplug_List := (others => Disabled);
Nico Hubera63e8332018-02-01 16:41:30 +0100405 loop
406 for Pipe in Pipe_Index loop
407 exit when Pipes (Pipe).Port = GMA.Disabled;
408 declare
409 C : Cursor_Type renames Pipes (Pipe).Cursor;
410 FB : Framebuffer_Type renames Pipes (Pipe).Framebuffer;
Nico Huberc5c767a2018-06-03 01:09:04 +0200411 Width : constant Width_Type := Rotated_Width (FB);
412 Height : constant Height_Type := Rotated_Height (FB);
Nico Hubera63e8332018-02-01 16:41:30 +0100413 CS : Cursor_Script_Entry renames Cursor_Script
414 (Natural (Cnt) mod (Cursor_Script'Last + 1));
415 begin
416 C.Center_X := CS.X;
417 C.Center_Y := CS.Y;
418 case CS.Rel is
419 when UL => null;
420 when UR => C.Center_X := CS.X + Width;
421 when LR => C.Center_X := CS.X + Width;
422 C.Center_Y := CS.Y + Height;
423 when LL => C.Center_Y := CS.Y + Height;
424 end case;
425 GMA.Place_Cursor (Pipe, C.Center_X, C.Center_Y);
426 end;
427 end loop;
Nico Hubera563ec22019-09-29 19:07:27 +0200428
429 Timed_Out := Time.Timed_Out (HP_Deadline);
430 if Timed_Out then
431 HP_Deadline := Time.MS_From_Now (HP_Delay_MS);
432 GMA.Display_Probing.Hotplug_Events (Hotplug_List);
433 if Hotplug_List (Hotplug_List'First) /= Disabled then
434 return;
435 end if;
436 end if;
437
438 Timed_Out := Time.Timed_Out (Total_Deadline);
439 exit when Timed_Out;
Nico Hubera63e8332018-02-01 16:41:30 +0100440 Timed_Out := Time.Timed_Out (Deadline);
441 exit when Timed_Out;
442 Time.M_Delay (160);
443 Cnt := Cnt + 1;
444 end loop;
445 end Script_Cursors;
446
447 type Cursor_Info is record
448 X_Velo, Y_Velo : Int32;
449 X_Acc, Y_Acc : Int32;
450 Color : Pipe_Index;
451 Size : Cursor_Size;
452 end record;
Nico Huberd8282b62018-06-18 00:44:55 +0200453 function Cursor_Rand (Gen : Rand_P.Generator)
454 return Int32 is (Rand (Gen) mod 51 - 25);
455 Cursor_Infos : array (Pipe_Index) of Cursor_Info;
Nico Hubera63e8332018-02-01 16:41:30 +0100456
457 procedure Move_Cursors
Nico Hubera563ec22019-09-29 19:07:27 +0200458 (Pipes : in out GMA.Pipe_Configs;
459 Hotplug_List : out Display_Probing.Port_List;
460 Total_Deadline : in Time.T;
461 Time_MS : in Natural;
462 Gen : in Rand_P.Generator)
Nico Hubera63e8332018-02-01 16:41:30 +0100463 is
464 procedure Select_New_Cursor
465 (P : in Pipe_Index;
466 C : in out Cursor_Type;
467 CI : in out Cursor_Info)
468 is
469 Old_C : constant Cursor_Type := C;
470 begin
471 -- change either size or color
Nico Huberd8282b62018-06-18 00:44:55 +0200472 if Rand (Gen) mod 2 = 0 then
Nico Hubera63e8332018-02-01 16:41:30 +0100473 CI.Color := Pipe_Index'Val
Nico Huberd8282b62018-06-18 00:44:55 +0200474 ((Pipe_Index'Pos (CI.Color) + 1 + Rand (Gen) mod 2) mod 3);
Nico Hubera63e8332018-02-01 16:41:30 +0100475 else
476 CI.Size := Cursor_Size'Val
Nico Huberd8282b62018-06-18 00:44:55 +0200477 ((Cursor_Size'Pos (CI.Size) + 1 + Rand (Gen) mod 2) mod 3);
Nico Hubera63e8332018-02-01 16:41:30 +0100478 end if;
479 C := Cursors (CI.Color) (CI.Size);
480 C.Center_X := Old_C.Center_X;
481 C.Center_Y := Old_C.Center_Y;
482 GMA.Update_Cursor (P, C);
483 end Select_New_Cursor;
484
485 Deadline : constant Time.T := Time.MS_From_Now (Time_MS);
Nico Hubera563ec22019-09-29 19:07:27 +0200486 HP_Deadline : Time.T := Time.MS_From_Now (HP_Delay_MS);
Nico Hubera63e8332018-02-01 16:41:30 +0100487 Timed_Out : Boolean := False;
488 Cnt : Word32 := 0;
489 begin
Nico Hubera563ec22019-09-29 19:07:27 +0200490 Hotplug_List := (others => Disabled);
Nico Hubera63e8332018-02-01 16:41:30 +0100491 for Pipe in Pipe_Index loop
492 exit when Pipes (Pipe).Port = GMA.Disabled;
493 Select_New_Cursor (Pipe, Pipes (Pipe).Cursor, Cursor_Infos (Pipe));
494 end loop;
495 loop
496 for Pipe in Pipe_Index loop
497 exit when Pipes (Pipe).Port = GMA.Disabled;
498 declare
499 C : Cursor_Type renames Pipes (Pipe).Cursor;
500 CI : Cursor_Info renames Cursor_Infos (Pipe);
501 FB : Framebuffer_Type renames Pipes (Pipe).Framebuffer;
Nico Huberc5c767a2018-06-03 01:09:04 +0200502 Width : constant Width_Type := Rotated_Width (FB);
503 Height : constant Height_Type := Rotated_Height (FB);
Nico Hubera63e8332018-02-01 16:41:30 +0100504
505 Update : Boolean := False;
506 begin
507 if Cnt mod 16 = 0 then
Nico Huberd8282b62018-06-18 00:44:55 +0200508 CI.X_Acc := Cursor_Rand (Gen);
509 CI.Y_Acc := Cursor_Rand (Gen);
Nico Hubera63e8332018-02-01 16:41:30 +0100510 end if;
511 CI.X_Velo := CI.X_Velo + CI.X_Acc;
512 CI.Y_Velo := CI.Y_Velo + CI.Y_Acc;
513 C.Center_X := C.Center_X + CI.X_Velo / 100;
514 C.Center_Y := C.Center_Y + CI.Y_Velo / 100;
515 if C.Center_X not in 0 .. Width - 1 then
516 C.Center_X := Int32'Max (0, Int32'Min (Width, C.Center_X));
517 CI.X_Velo := -CI.X_Velo;
518 Update := True;
519 end if;
520 if C.Center_Y not in 0 .. Height - 1 then
521 C.Center_Y := Int32'Max (0, Int32'Min (Height, C.Center_Y));
522 CI.Y_Velo := -CI.Y_Velo;
523 Update := True;
524 end if;
525 if Update then
526 Select_New_Cursor (Pipe, C, CI);
527 else
528 GMA.Place_Cursor (Pipe, C.Center_X, C.Center_Y);
529 end if;
530 end;
531 end loop;
Nico Hubera563ec22019-09-29 19:07:27 +0200532
533 Timed_Out := Time.Timed_Out (HP_Deadline);
534 if Timed_Out then
535 HP_Deadline := Time.MS_From_Now (HP_Delay_MS);
536 GMA.Display_Probing.Hotplug_Events (Hotplug_List);
537 if Hotplug_List (Hotplug_List'First) /= Disabled then
538 return;
539 end if;
540 end if;
541
542 Timed_Out := Time.Timed_Out (Total_Deadline);
543 exit when Timed_Out;
Nico Hubera63e8332018-02-01 16:41:30 +0100544 Timed_Out := Time.Timed_Out (Deadline);
545 exit when Timed_Out;
546 Time.M_Delay (16); -- ~60 fps
547 Cnt := Cnt + 1;
548 end loop;
549 end Move_Cursors;
550
Nico Hubera563ec22019-09-29 19:07:27 +0200551 procedure Run_The_Show (Deadline : Time.T; Gen : Rand_P.Generator)
552 is
553 Timed_Out : Boolean;
554 Hotplug_List : GMA.Display_Probing.Port_List;
555
556 New_Pipes : GMA.Pipe_Configs := Pipes;
557
558 function Rand_Div (Num : Position_Type) return Position_Type is
559 (case Rand (Gen) mod 4 is
560 when 3 => Rand (Gen) mod Num / 3,
561 when 2 => Rand (Gen) mod Num / 2,
562 when 1 => Rand (Gen) mod Num,
563 when others => 0);
564 begin
565 for Pipe in GMA.Pipe_Index loop
566 if Pipes (Pipe).Port /= GMA.Disabled then
567 Test_Screen
568 (Framebuffer => Pipes (Pipe).Framebuffer,
569 Pipe => Pipe);
570 end if;
571 for Size in Cursor_Size loop
572 Draw_Cursor (Pipe, Cursors (Pipe) (Size));
573 end loop;
574 end loop;
575
576 Cursor_Infos :=
577 (others =>
578 (Color => Pipe_Index'Val (Rand (Gen) mod 3),
579 Size => Cursor_Size'Val (Rand (Gen) mod 3),
580 X_Velo => 3 * Cursor_Rand (Gen),
581 Y_Velo => 3 * Cursor_Rand (Gen),
582 others => Cursor_Rand (Gen)));
583
584 Script_Cursors (Pipes, Hotplug_List, Deadline, Primary_Delay_MS);
585 if Hotplug_List (Hotplug_List'First) /= Disabled then
586 return;
587 end if;
588 Timed_Out := Time.Timed_Out (Deadline);
589 if Timed_Out then
590 return;
591 end if;
592
593 Rand_P.Reset (Gen, Seed);
594 loop
595 GMA.Display_Probing.Hotplug_Events (Hotplug_List);
596 if Hotplug_List (Hotplug_List'First) /= Disabled then
597 return;
598 end if;
599 New_Pipes := Pipes;
600 for Pipe in GMA.Pipe_Index loop
601 exit when Pipes (Pipe).Port = Disabled;
602 declare
603 New_FB : Framebuffer_Type renames
604 New_Pipes (Pipe).Framebuffer;
605 Cursor : Cursor_Type renames New_Pipes (Pipe).Cursor;
606 Width : constant Width_Type :=
607 Pipes (Pipe).Framebuffer.Width;
608 Height : constant Height_Type :=
609 Pipes (Pipe).Framebuffer.Height;
610 begin
611 New_FB.Start_X := Position_Type'Min
612 (Width - 320, Rand_Div (Width));
613 New_FB.Start_Y := Position_Type'Min
614 (Height - 320, Rand_Div (Height));
615 New_FB.Width := Width_Type'Max
616 (320, Width - New_FB.Start_X - Rand_Div (Width));
617 New_FB.Height := Height_Type'Max
618 (320, Height - New_FB.Start_Y - Rand_Div (Height));
619
620 Cursor.Center_X := Rotated_Width (New_FB) / 2;
621 Cursor.Center_Y := Rotated_Height (New_FB) / 2;
622 GMA.Update_Cursor (Pipe, Cursor);
623 end;
624 end loop;
625 GMA.Dump_Configs (New_Pipes);
626 GMA.Update_Outputs (New_Pipes);
627 Move_Cursors
628 (New_Pipes, Hotplug_List, Deadline, Secondary_Delay_MS, Gen);
629 exit when Hotplug_List (Hotplug_List'First) /= Disabled;
630
631 Timed_Out := Time.Timed_Out (Deadline);
632 exit when Timed_Out;
633 end loop;
634 end Run_The_Show;
635
Nico Huber3b654a02017-07-15 22:27:14 +0200636 procedure Print_Usage
637 is
638 begin
Nico Huber30d89712021-06-11 14:13:24 +0200639 Debug.Put ("Usage: ");
640 Debug.Put (Ada.Command_Line.Command_Name);
641 Debug.Put_Line (" <delay seconds> [(0|90|180|270)]");
Nico Huber3b654a02017-07-15 22:27:14 +0200642 Debug.New_Line;
643 end Print_Usage;
644
Nico Huber1d0abe42017-03-05 14:14:09 +0100645 procedure Main
646 is
Nico Huber1d0abe42017-03-05 14:14:09 +0100647 use type HW.GFX.GMA.Port_Type;
Nico Huberfda2d6e2017-07-09 16:47:52 +0200648 use type HW.Word64;
Nico Huber1d0abe42017-03-05 14:14:09 +0100649 use type Interfaces.C.int;
650
Nico Huberfda2d6e2017-07-09 16:47:52 +0200651 Res_Addr : Word64;
652
Nico Hubera455f0e2018-01-07 11:40:40 +0100653 Delay_MS : Natural;
Nico Huber88f3c982017-08-28 13:31:38 +0200654 Rotation : Rotation_Type := No_Rotation;
Nico Huber3b654a02017-07-15 22:27:14 +0200655
Nico Huberfda2d6e2017-07-09 16:47:52 +0200656 Dev_Init,
Nico Huber1d0abe42017-03-05 14:14:09 +0100657 Initialized : Boolean;
658
Nico Huberd8282b62018-06-18 00:44:55 +0200659 Gen : Rand_P.Generator;
660
Nico Hubera563ec22019-09-29 19:07:27 +0200661 Deadline : Time.T;
662 Timed_Out : Boolean;
663 Hotplug_List : GMA.Display_Probing.Port_List;
664
Nico Huber1d0abe42017-03-05 14:14:09 +0100665 function iopl (level : Interfaces.C.int) return Interfaces.C.int;
666 pragma Import (C, iopl, "iopl");
667 begin
Nico Huber88f3c982017-08-28 13:31:38 +0200668 if Ada.Command_Line.Argument_Count < 1 then
Nico Huber3b654a02017-07-15 22:27:14 +0200669 Print_Usage;
670 return;
671 end if;
672
Nico Hubera455f0e2018-01-07 11:40:40 +0100673 Delay_MS := Natural'Value (Ada.Command_Line.Argument (1)) * 1_000;
Nico Huber3b654a02017-07-15 22:27:14 +0200674
Nico Huber88f3c982017-08-28 13:31:38 +0200675 if Ada.Command_Line.Argument_Count >= 2 then
676 declare
677 Rotation_Degree : constant String := Ada.Command_Line.Argument (2);
678 begin
679 if Rotation_Degree = "0" then Rotation := No_Rotation;
680 elsif Rotation_Degree = "90" then Rotation := Rotated_90;
681 elsif Rotation_Degree = "180" then Rotation := Rotated_180;
682 elsif Rotation_Degree = "270" then Rotation := Rotated_270;
683 else Print_Usage; return; end if;
684 end;
685 end if;
686
Nico Huber1d0abe42017-03-05 14:14:09 +0100687 if iopl (3) /= 0 then
688 Debug.Put_Line ("Failed to change i/o privilege level.");
689 return;
690 end if;
691
Nico Huberfda2d6e2017-07-09 16:47:52 +0200692 Dev.Initialize (Dev_Init);
693 if not Dev_Init then
694 Debug.Put_Line ("Failed to map PCI config.");
Nico Huber1d0abe42017-03-05 14:14:09 +0100695 return;
696 end if;
697
Nico Huberfda2d6e2017-07-09 16:47:52 +0200698 Dev.Map (Res_Addr, PCI.Res2, WC => True);
699 if Res_Addr = 0 then
700 Debug.Put_Line ("Failed to map PCI resource2.");
701 return;
702 end if;
703 Screen.Set_Base_Address (Res_Addr);
704
Nico Huber1d0abe42017-03-05 14:14:09 +0100705 GMA.Initialize
Nico Huber2b6f6992017-07-09 18:11:34 +0200706 (Clean_State => True,
Nico Huber1d0abe42017-03-05 14:14:09 +0100707 Success => Initialized);
708
709 if Initialized then
Nico Huber3b654a02017-07-15 22:27:14 +0200710 Backup_GTT;
711
Nico Hubera563ec22019-09-29 19:07:27 +0200712 Deadline := Time.MS_From_Now (Delay_MS);
713 loop
714 Prepare_Configs (Rotation, Gen);
Nico Huber1d0abe42017-03-05 14:14:09 +0100715
Nico Hubera563ec22019-09-29 19:07:27 +0200716 GMA.Update_Outputs (Pipes);
Nico Huber1d0abe42017-03-05 14:14:09 +0100717
Nico Hubera563ec22019-09-29 19:07:27 +0200718 if not (for all P in Pipe_Index => Pipes (P).Port = Disabled) then
719 for Pipe in GMA.Pipe_Index loop
720 if Pipes (Pipe).Port /= GMA.Disabled then
721 Backup_Screen (Pipes (Pipe).Framebuffer);
722 end if;
Nico Hubera455f0e2018-01-07 11:40:40 +0100723 end loop;
Nico Huber3b654a02017-07-15 22:27:14 +0200724
Nico Hubera563ec22019-09-29 19:07:27 +0200725 Run_The_Show (Deadline, Gen);
726
727 for Pipe in GMA.Pipe_Index loop
728 if Pipes (Pipe).Port /= GMA.Disabled then
729 Restore_Screen (Pipes (Pipe).Framebuffer);
730 end if;
731 end loop;
732 else
733 loop
734 Time.M_Delay (HP_Delay_MS);
735 GMA.Display_Probing.Hotplug_Events (Hotplug_List);
736 exit when Hotplug_List (Hotplug_List'First) /= Disabled;
737
738 Timed_Out := Time.Timed_Out (Deadline);
739 exit when Timed_Out;
740 end loop;
Nico Huber3b654a02017-07-15 22:27:14 +0200741 end if;
Nico Hubera563ec22019-09-29 19:07:27 +0200742
743 Timed_Out := Time.Timed_Out (Deadline);
744 exit when Timed_Out;
Nico Huber3b654a02017-07-15 22:27:14 +0200745 end loop;
Nico Hubera563ec22019-09-29 19:07:27 +0200746
Nico Huber3b654a02017-07-15 22:27:14 +0200747 Restore_GTT;
Nico Huber1d0abe42017-03-05 14:14:09 +0100748 end if;
749 end Main;
750
Nico Huberfda2d6e2017-07-09 16:47:52 +0200751end HW.GFX.GMA.GFX_Test;