video_fb.c 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/video.h>
  19. #include <grub/video_fb.h>
  20. #include <grub/misc.h>
  21. #include <grub/mm.h>
  22. #include <grub/fbblit.h>
  23. #include <grub/fbfill.h>
  24. #include <grub/fbutil.h>
  25. #include <grub/bitmap.h>
  26. #include <grub/dl.h>
  27. GRUB_MOD_LICENSE ("GPLv3+");
  28. typedef grub_err_t (*grub_video_fb_doublebuf_update_screen_t) (void);
  29. typedef volatile void *framebuf_t;
  30. struct dirty
  31. {
  32. int first_line;
  33. int last_line;
  34. };
  35. static struct
  36. {
  37. struct grub_video_fbrender_target *render_target;
  38. struct grub_video_fbrender_target *back_target;
  39. struct grub_video_palette_data *palette;
  40. framebuf_t pages[2];
  41. unsigned int palette_size;
  42. struct dirty current_dirty;
  43. struct dirty previous_dirty;
  44. /* For page flipping strategy. */
  45. int displayed_page; /* The page # that is the front buffer. */
  46. int render_page; /* The page # that is the back buffer. */
  47. grub_video_fb_set_page_t set_page;
  48. char *offscreen_buffer;
  49. grub_video_fb_doublebuf_update_screen_t update_screen;
  50. } framebuffer;
  51. /* Specify "standard" VGA palette, some video cards may
  52. need this and this will also be used when using RGB modes. */
  53. struct grub_video_palette_data grub_video_fbstd_colors[GRUB_VIDEO_FBSTD_EXT_NUMCOLORS] =
  54. {
  55. /* Standard (3-bit) colors. */
  56. // {R, G, B, A}
  57. {0x00, 0x00, 0x00, 0xFF}, // 0 = black
  58. {0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
  59. {0x00, 0xA8, 0x00, 0xFF}, // 2 = green
  60. {0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
  61. {0xA8, 0x00, 0x00, 0xFF}, // 4 = red
  62. {0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
  63. {0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
  64. {0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
  65. /* Bright (4-bit) colors. */
  66. {0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
  67. {0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
  68. {0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
  69. {0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
  70. {0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
  71. {0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
  72. {0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
  73. {0xFE, 0xFE, 0xFE, 0xFF}, // 15 = white
  74. /* Extended (8-bit) colors. Completes preceding colors to full RGB332. */
  75. {0x00, 0x00, 0x55, 0xFF}, // RGB332 = (0, 0, 1)
  76. {0x00, 0x00, 0xFF, 0xFF}, // RGB332 = (0, 0, 3)
  77. {0x00, 0x24, 0x00, 0xFF}, // RGB332 = (0, 1, 0)
  78. {0x00, 0x24, 0x55, 0xFF}, // RGB332 = (0, 1, 1)
  79. {0x00, 0x24, 0xAA, 0xFF}, // RGB332 = (0, 1, 2)
  80. {0x00, 0x24, 0xFF, 0xFF}, // RGB332 = (0, 1, 3)
  81. {0x00, 0x48, 0x00, 0xFF}, // RGB332 = (0, 2, 0)
  82. {0x00, 0x48, 0x55, 0xFF}, // RGB332 = (0, 2, 1)
  83. {0x00, 0x48, 0xAA, 0xFF}, // RGB332 = (0, 2, 2)
  84. {0x00, 0x48, 0xFF, 0xFF}, // RGB332 = (0, 2, 3)
  85. {0x00, 0x6C, 0x00, 0xFF}, // RGB332 = (0, 3, 0)
  86. {0x00, 0x6C, 0x55, 0xFF}, // RGB332 = (0, 3, 1)
  87. {0x00, 0x6C, 0xAA, 0xFF}, // RGB332 = (0, 3, 2)
  88. {0x00, 0x6C, 0xFF, 0xFF}, // RGB332 = (0, 3, 3)
  89. {0x00, 0x90, 0x00, 0xFF}, // RGB332 = (0, 4, 0)
  90. {0x00, 0x90, 0x55, 0xFF}, // RGB332 = (0, 4, 1)
  91. {0x00, 0x90, 0xAA, 0xFF}, // RGB332 = (0, 4, 2)
  92. {0x00, 0x90, 0xFF, 0xFF}, // RGB332 = (0, 4, 3)
  93. {0x00, 0xB4, 0x55, 0xFF}, // RGB332 = (0, 5, 1)
  94. {0x00, 0xB4, 0xFF, 0xFF}, // RGB332 = (0, 5, 3)
  95. {0x00, 0xD8, 0x00, 0xFF}, // RGB332 = (0, 6, 0)
  96. {0x00, 0xD8, 0x55, 0xFF}, // RGB332 = (0, 6, 1)
  97. {0x00, 0xD8, 0xAA, 0xFF}, // RGB332 = (0, 6, 2)
  98. {0x00, 0xD8, 0xFF, 0xFF}, // RGB332 = (0, 6, 3)
  99. {0x00, 0xFC, 0x00, 0xFF}, // RGB332 = (0, 7, 0)
  100. {0x00, 0xFC, 0x55, 0xFF}, // RGB332 = (0, 7, 1)
  101. {0x00, 0xFC, 0xAA, 0xFF}, // RGB332 = (0, 7, 2)
  102. {0x00, 0xFC, 0xFF, 0xFF}, // RGB332 = (0, 7, 3)
  103. {0x24, 0x00, 0x00, 0xFF}, // RGB332 = (1, 0, 0)
  104. {0x24, 0x00, 0x55, 0xFF}, // RGB332 = (1, 0, 1)
  105. {0x24, 0x00, 0xAA, 0xFF}, // RGB332 = (1, 0, 2)
  106. {0x24, 0x00, 0xFF, 0xFF}, // RGB332 = (1, 0, 3)
  107. {0x24, 0x24, 0x00, 0xFF}, // RGB332 = (1, 1, 0)
  108. {0x24, 0x24, 0x55, 0xFF}, // RGB332 = (1, 1, 1)
  109. {0x24, 0x24, 0xAA, 0xFF}, // RGB332 = (1, 1, 2)
  110. {0x24, 0x24, 0xFF, 0xFF}, // RGB332 = (1, 1, 3)
  111. {0x24, 0x48, 0x00, 0xFF}, // RGB332 = (1, 2, 0)
  112. {0x24, 0x48, 0x55, 0xFF}, // RGB332 = (1, 2, 1)
  113. {0x24, 0x48, 0xAA, 0xFF}, // RGB332 = (1, 2, 2)
  114. {0x24, 0x48, 0xFF, 0xFF}, // RGB332 = (1, 2, 3)
  115. {0x24, 0x6C, 0x00, 0xFF}, // RGB332 = (1, 3, 0)
  116. {0x24, 0x6C, 0x55, 0xFF}, // RGB332 = (1, 3, 1)
  117. {0x24, 0x6C, 0xAA, 0xFF}, // RGB332 = (1, 3, 2)
  118. {0x24, 0x6C, 0xFF, 0xFF}, // RGB332 = (1, 3, 3)
  119. {0x24, 0x90, 0x00, 0xFF}, // RGB332 = (1, 4, 0)
  120. {0x24, 0x90, 0x55, 0xFF}, // RGB332 = (1, 4, 1)
  121. {0x24, 0x90, 0xAA, 0xFF}, // RGB332 = (1, 4, 2)
  122. {0x24, 0x90, 0xFF, 0xFF}, // RGB332 = (1, 4, 3)
  123. {0x24, 0xB4, 0x00, 0xFF}, // RGB332 = (1, 5, 0)
  124. {0x24, 0xB4, 0x55, 0xFF}, // RGB332 = (1, 5, 1)
  125. {0x24, 0xB4, 0xAA, 0xFF}, // RGB332 = (1, 5, 2)
  126. {0x24, 0xB4, 0xFF, 0xFF}, // RGB332 = (1, 5, 3)
  127. {0x24, 0xD8, 0x00, 0xFF}, // RGB332 = (1, 6, 0)
  128. {0x24, 0xD8, 0x55, 0xFF}, // RGB332 = (1, 6, 1)
  129. {0x24, 0xD8, 0xAA, 0xFF}, // RGB332 = (1, 6, 2)
  130. {0x24, 0xD8, 0xFF, 0xFF}, // RGB332 = (1, 6, 3)
  131. {0x24, 0xFC, 0x00, 0xFF}, // RGB332 = (1, 7, 0)
  132. {0x24, 0xFC, 0x55, 0xFF}, // RGB332 = (1, 7, 1)
  133. {0x24, 0xFC, 0xAA, 0xFF}, // RGB332 = (1, 7, 2)
  134. {0x24, 0xFC, 0xFF, 0xFF}, // RGB332 = (1, 7, 3)
  135. {0x48, 0x00, 0x00, 0xFF}, // RGB332 = (2, 0, 0)
  136. {0x48, 0x00, 0x55, 0xFF}, // RGB332 = (2, 0, 1)
  137. {0x48, 0x00, 0xAA, 0xFF}, // RGB332 = (2, 0, 2)
  138. {0x48, 0x00, 0xFF, 0xFF}, // RGB332 = (2, 0, 3)
  139. {0x48, 0x24, 0x00, 0xFF}, // RGB332 = (2, 1, 0)
  140. {0x48, 0x24, 0x55, 0xFF}, // RGB332 = (2, 1, 1)
  141. {0x48, 0x24, 0xAA, 0xFF}, // RGB332 = (2, 1, 2)
  142. {0x48, 0x24, 0xFF, 0xFF}, // RGB332 = (2, 1, 3)
  143. {0x48, 0x48, 0x00, 0xFF}, // RGB332 = (2, 2, 0)
  144. {0x48, 0x48, 0xAA, 0xFF}, // RGB332 = (2, 2, 2)
  145. {0x48, 0x6C, 0x00, 0xFF}, // RGB332 = (2, 3, 0)
  146. {0x48, 0x6C, 0x55, 0xFF}, // RGB332 = (2, 3, 1)
  147. {0x48, 0x6C, 0xAA, 0xFF}, // RGB332 = (2, 3, 2)
  148. {0x48, 0x6C, 0xFF, 0xFF}, // RGB332 = (2, 3, 3)
  149. {0x48, 0x90, 0x00, 0xFF}, // RGB332 = (2, 4, 0)
  150. {0x48, 0x90, 0x55, 0xFF}, // RGB332 = (2, 4, 1)
  151. {0x48, 0x90, 0xAA, 0xFF}, // RGB332 = (2, 4, 2)
  152. {0x48, 0x90, 0xFF, 0xFF}, // RGB332 = (2, 4, 3)
  153. {0x48, 0xB4, 0x00, 0xFF}, // RGB332 = (2, 5, 0)
  154. {0x48, 0xB4, 0x55, 0xFF}, // RGB332 = (2, 5, 1)
  155. {0x48, 0xB4, 0xAA, 0xFF}, // RGB332 = (2, 5, 2)
  156. {0x48, 0xB4, 0xFF, 0xFF}, // RGB332 = (2, 5, 3)
  157. {0x48, 0xD8, 0x00, 0xFF}, // RGB332 = (2, 6, 0)
  158. {0x48, 0xD8, 0x55, 0xFF}, // RGB332 = (2, 6, 1)
  159. {0x48, 0xD8, 0xAA, 0xFF}, // RGB332 = (2, 6, 2)
  160. {0x48, 0xD8, 0xFF, 0xFF}, // RGB332 = (2, 6, 3)
  161. {0x48, 0xFC, 0x00, 0xFF}, // RGB332 = (2, 7, 0)
  162. {0x48, 0xFC, 0xAA, 0xFF}, // RGB332 = (2, 7, 2)
  163. {0x6C, 0x00, 0x00, 0xFF}, // RGB332 = (3, 0, 0)
  164. {0x6C, 0x00, 0x55, 0xFF}, // RGB332 = (3, 0, 1)
  165. {0x6C, 0x00, 0xAA, 0xFF}, // RGB332 = (3, 0, 2)
  166. {0x6C, 0x00, 0xFF, 0xFF}, // RGB332 = (3, 0, 3)
  167. {0x6C, 0x24, 0x00, 0xFF}, // RGB332 = (3, 1, 0)
  168. {0x6C, 0x24, 0x55, 0xFF}, // RGB332 = (3, 1, 1)
  169. {0x6C, 0x24, 0xAA, 0xFF}, // RGB332 = (3, 1, 2)
  170. {0x6C, 0x24, 0xFF, 0xFF}, // RGB332 = (3, 1, 3)
  171. {0x6C, 0x48, 0x00, 0xFF}, // RGB332 = (3, 2, 0)
  172. {0x6C, 0x48, 0x55, 0xFF}, // RGB332 = (3, 2, 1)
  173. {0x6C, 0x48, 0xAA, 0xFF}, // RGB332 = (3, 2, 2)
  174. {0x6C, 0x48, 0xFF, 0xFF}, // RGB332 = (3, 2, 3)
  175. {0x6C, 0x6C, 0x00, 0xFF}, // RGB332 = (3, 3, 0)
  176. {0x6C, 0x6C, 0x55, 0xFF}, // RGB332 = (3, 3, 1)
  177. {0x6C, 0x6C, 0xAA, 0xFF}, // RGB332 = (3, 3, 2)
  178. {0x6C, 0x6C, 0xFF, 0xFF}, // RGB332 = (3, 3, 3)
  179. {0x6C, 0x90, 0x00, 0xFF}, // RGB332 = (3, 4, 0)
  180. {0x6C, 0x90, 0x55, 0xFF}, // RGB332 = (3, 4, 1)
  181. {0x6C, 0x90, 0xAA, 0xFF}, // RGB332 = (3, 4, 2)
  182. {0x6C, 0x90, 0xFF, 0xFF}, // RGB332 = (3, 4, 3)
  183. {0x6C, 0xB4, 0x00, 0xFF}, // RGB332 = (3, 5, 0)
  184. {0x6C, 0xB4, 0x55, 0xFF}, // RGB332 = (3, 5, 1)
  185. {0x6C, 0xB4, 0xAA, 0xFF}, // RGB332 = (3, 5, 2)
  186. {0x6C, 0xB4, 0xFF, 0xFF}, // RGB332 = (3, 5, 3)
  187. {0x6C, 0xD8, 0x00, 0xFF}, // RGB332 = (3, 6, 0)
  188. {0x6C, 0xD8, 0x55, 0xFF}, // RGB332 = (3, 6, 1)
  189. {0x6C, 0xD8, 0xAA, 0xFF}, // RGB332 = (3, 6, 2)
  190. {0x6C, 0xD8, 0xFF, 0xFF}, // RGB332 = (3, 6, 3)
  191. {0x6C, 0xFC, 0x00, 0xFF}, // RGB332 = (3, 7, 0)
  192. {0x6C, 0xFC, 0x55, 0xFF}, // RGB332 = (3, 7, 1)
  193. {0x6C, 0xFC, 0xAA, 0xFF}, // RGB332 = (3, 7, 2)
  194. {0x6C, 0xFC, 0xFF, 0xFF}, // RGB332 = (3, 7, 3)
  195. {0x90, 0x00, 0x00, 0xFF}, // RGB332 = (4, 0, 0)
  196. {0x90, 0x00, 0x55, 0xFF}, // RGB332 = (4, 0, 1)
  197. {0x90, 0x00, 0xAA, 0xFF}, // RGB332 = (4, 0, 2)
  198. {0x90, 0x00, 0xFF, 0xFF}, // RGB332 = (4, 0, 3)
  199. {0x90, 0x24, 0x00, 0xFF}, // RGB332 = (4, 1, 0)
  200. {0x90, 0x24, 0x55, 0xFF}, // RGB332 = (4, 1, 1)
  201. {0x90, 0x24, 0xAA, 0xFF}, // RGB332 = (4, 1, 2)
  202. {0x90, 0x24, 0xFF, 0xFF}, // RGB332 = (4, 1, 3)
  203. {0x90, 0x48, 0x00, 0xFF}, // RGB332 = (4, 2, 0)
  204. {0x90, 0x48, 0x55, 0xFF}, // RGB332 = (4, 2, 1)
  205. {0x90, 0x48, 0xAA, 0xFF}, // RGB332 = (4, 2, 2)
  206. {0x90, 0x48, 0xFF, 0xFF}, // RGB332 = (4, 2, 3)
  207. {0x90, 0x6C, 0x00, 0xFF}, // RGB332 = (4, 3, 0)
  208. {0x90, 0x6C, 0x55, 0xFF}, // RGB332 = (4, 3, 1)
  209. {0x90, 0x6C, 0xAA, 0xFF}, // RGB332 = (4, 3, 2)
  210. {0x90, 0x6C, 0xFF, 0xFF}, // RGB332 = (4, 3, 3)
  211. {0x90, 0x90, 0x00, 0xFF}, // RGB332 = (4, 4, 0)
  212. {0x90, 0x90, 0x55, 0xFF}, // RGB332 = (4, 4, 1)
  213. {0x90, 0x90, 0xAA, 0xFF}, // RGB332 = (4, 4, 2)
  214. {0x90, 0x90, 0xFF, 0xFF}, // RGB332 = (4, 4, 3)
  215. {0x90, 0xB4, 0x00, 0xFF}, // RGB332 = (4, 5, 0)
  216. {0x90, 0xB4, 0x55, 0xFF}, // RGB332 = (4, 5, 1)
  217. {0x90, 0xB4, 0xAA, 0xFF}, // RGB332 = (4, 5, 2)
  218. {0x90, 0xB4, 0xFF, 0xFF}, // RGB332 = (4, 5, 3)
  219. {0x90, 0xD8, 0x00, 0xFF}, // RGB332 = (4, 6, 0)
  220. {0x90, 0xD8, 0x55, 0xFF}, // RGB332 = (4, 6, 1)
  221. {0x90, 0xD8, 0xAA, 0xFF}, // RGB332 = (4, 6, 2)
  222. {0x90, 0xD8, 0xFF, 0xFF}, // RGB332 = (4, 6, 3)
  223. {0x90, 0xFC, 0x00, 0xFF}, // RGB332 = (4, 7, 0)
  224. {0x90, 0xFC, 0x55, 0xFF}, // RGB332 = (4, 7, 1)
  225. {0x90, 0xFC, 0xAA, 0xFF}, // RGB332 = (4, 7, 2)
  226. {0x90, 0xFC, 0xFF, 0xFF}, // RGB332 = (4, 7, 3)
  227. {0xB4, 0x00, 0x55, 0xFF}, // RGB332 = (5, 0, 1)
  228. {0xB4, 0x00, 0xFF, 0xFF}, // RGB332 = (5, 0, 3)
  229. {0xB4, 0x24, 0x00, 0xFF}, // RGB332 = (5, 1, 0)
  230. {0xB4, 0x24, 0x55, 0xFF}, // RGB332 = (5, 1, 1)
  231. {0xB4, 0x24, 0xAA, 0xFF}, // RGB332 = (5, 1, 2)
  232. {0xB4, 0x24, 0xFF, 0xFF}, // RGB332 = (5, 1, 3)
  233. {0xB4, 0x48, 0x55, 0xFF}, // RGB332 = (5, 2, 1)
  234. {0xB4, 0x48, 0xAA, 0xFF}, // RGB332 = (5, 2, 2)
  235. {0xB4, 0x48, 0xFF, 0xFF}, // RGB332 = (5, 2, 3)
  236. {0xB4, 0x6C, 0x00, 0xFF}, // RGB332 = (5, 3, 0)
  237. {0xB4, 0x6C, 0x55, 0xFF}, // RGB332 = (5, 3, 1)
  238. {0xB4, 0x6C, 0xAA, 0xFF}, // RGB332 = (5, 3, 2)
  239. {0xB4, 0x6C, 0xFF, 0xFF}, // RGB332 = (5, 3, 3)
  240. {0xB4, 0x90, 0x00, 0xFF}, // RGB332 = (5, 4, 0)
  241. {0xB4, 0x90, 0x55, 0xFF}, // RGB332 = (5, 4, 1)
  242. {0xB4, 0x90, 0xAA, 0xFF}, // RGB332 = (5, 4, 2)
  243. {0xB4, 0x90, 0xFF, 0xFF}, // RGB332 = (5, 4, 3)
  244. {0xB4, 0xB4, 0x00, 0xFF}, // RGB332 = (5, 5, 0)
  245. {0xB4, 0xB4, 0x55, 0xFF}, // RGB332 = (5, 5, 1)
  246. {0xB4, 0xB4, 0xFF, 0xFF}, // RGB332 = (5, 5, 3)
  247. {0xB4, 0xD8, 0x00, 0xFF}, // RGB332 = (5, 6, 0)
  248. {0xB4, 0xD8, 0x55, 0xFF}, // RGB332 = (5, 6, 1)
  249. {0xB4, 0xD8, 0xAA, 0xFF}, // RGB332 = (5, 6, 2)
  250. {0xB4, 0xD8, 0xFF, 0xFF}, // RGB332 = (5, 6, 3)
  251. {0xB4, 0xFC, 0x00, 0xFF}, // RGB332 = (5, 7, 0)
  252. {0xB4, 0xFC, 0x55, 0xFF}, // RGB332 = (5, 7, 1)
  253. {0xB4, 0xFC, 0xAA, 0xFF}, // RGB332 = (5, 7, 2)
  254. {0xB4, 0xFC, 0xFF, 0xFF}, // RGB332 = (5, 7, 3)
  255. {0xD8, 0x00, 0x00, 0xFF}, // RGB332 = (6, 0, 0)
  256. {0xD8, 0x00, 0x55, 0xFF}, // RGB332 = (6, 0, 1)
  257. {0xD8, 0x00, 0xAA, 0xFF}, // RGB332 = (6, 0, 2)
  258. {0xD8, 0x00, 0xFF, 0xFF}, // RGB332 = (6, 0, 3)
  259. {0xD8, 0x24, 0x00, 0xFF}, // RGB332 = (6, 1, 0)
  260. {0xD8, 0x24, 0x55, 0xFF}, // RGB332 = (6, 1, 1)
  261. {0xD8, 0x24, 0xAA, 0xFF}, // RGB332 = (6, 1, 2)
  262. {0xD8, 0x24, 0xFF, 0xFF}, // RGB332 = (6, 1, 3)
  263. {0xD8, 0x48, 0x00, 0xFF}, // RGB332 = (6, 2, 0)
  264. {0xD8, 0x48, 0x55, 0xFF}, // RGB332 = (6, 2, 1)
  265. {0xD8, 0x48, 0xAA, 0xFF}, // RGB332 = (6, 2, 2)
  266. {0xD8, 0x48, 0xFF, 0xFF}, // RGB332 = (6, 2, 3)
  267. {0xD8, 0x6C, 0x00, 0xFF}, // RGB332 = (6, 3, 0)
  268. {0xD8, 0x6C, 0x55, 0xFF}, // RGB332 = (6, 3, 1)
  269. {0xD8, 0x6C, 0xAA, 0xFF}, // RGB332 = (6, 3, 2)
  270. {0xD8, 0x6C, 0xFF, 0xFF}, // RGB332 = (6, 3, 3)
  271. {0xD8, 0x90, 0x00, 0xFF}, // RGB332 = (6, 4, 0)
  272. {0xD8, 0x90, 0x55, 0xFF}, // RGB332 = (6, 4, 1)
  273. {0xD8, 0x90, 0xAA, 0xFF}, // RGB332 = (6, 4, 2)
  274. {0xD8, 0x90, 0xFF, 0xFF}, // RGB332 = (6, 4, 3)
  275. {0xD8, 0xB4, 0x00, 0xFF}, // RGB332 = (6, 5, 0)
  276. {0xD8, 0xB4, 0x55, 0xFF}, // RGB332 = (6, 5, 1)
  277. {0xD8, 0xB4, 0xAA, 0xFF}, // RGB332 = (6, 5, 2)
  278. {0xD8, 0xB4, 0xFF, 0xFF}, // RGB332 = (6, 5, 3)
  279. {0xD8, 0xD8, 0x00, 0xFF}, // RGB332 = (6, 6, 0)
  280. {0xD8, 0xD8, 0x55, 0xFF}, // RGB332 = (6, 6, 1)
  281. {0xD8, 0xD8, 0xAA, 0xFF}, // RGB332 = (6, 6, 2)
  282. {0xD8, 0xD8, 0xFF, 0xFF}, // RGB332 = (6, 6, 3)
  283. {0xD8, 0xFC, 0x00, 0xFF}, // RGB332 = (6, 7, 0)
  284. {0xD8, 0xFC, 0x55, 0xFF}, // RGB332 = (6, 7, 1)
  285. {0xD8, 0xFC, 0xAA, 0xFF}, // RGB332 = (6, 7, 2)
  286. {0xD8, 0xFC, 0xFF, 0xFF}, // RGB332 = (6, 7, 3)
  287. {0xFC, 0x00, 0x00, 0xFF}, // RGB332 = (7, 0, 0)
  288. {0xFC, 0x00, 0x55, 0xFF}, // RGB332 = (7, 0, 1)
  289. {0xFC, 0x00, 0xAA, 0xFF}, // RGB332 = (7, 0, 2)
  290. {0xFC, 0x00, 0xFF, 0xFF}, // RGB332 = (7, 0, 3)
  291. {0xFC, 0x24, 0x00, 0xFF}, // RGB332 = (7, 1, 0)
  292. {0xFC, 0x24, 0x55, 0xFF}, // RGB332 = (7, 1, 1)
  293. {0xFC, 0x24, 0xAA, 0xFF}, // RGB332 = (7, 1, 2)
  294. {0xFC, 0x24, 0xFF, 0xFF}, // RGB332 = (7, 1, 3)
  295. {0xFC, 0x48, 0x00, 0xFF}, // RGB332 = (7, 2, 0)
  296. {0xFC, 0x48, 0xAA, 0xFF}, // RGB332 = (7, 2, 2)
  297. {0xFC, 0x6C, 0x00, 0xFF}, // RGB332 = (7, 3, 0)
  298. {0xFC, 0x6C, 0x55, 0xFF}, // RGB332 = (7, 3, 1)
  299. {0xFC, 0x6C, 0xAA, 0xFF}, // RGB332 = (7, 3, 2)
  300. {0xFC, 0x6C, 0xFF, 0xFF}, // RGB332 = (7, 3, 3)
  301. {0xFC, 0x90, 0x00, 0xFF}, // RGB332 = (7, 4, 0)
  302. {0xFC, 0x90, 0x55, 0xFF}, // RGB332 = (7, 4, 1)
  303. {0xFC, 0x90, 0xAA, 0xFF}, // RGB332 = (7, 4, 2)
  304. {0xFC, 0x90, 0xFF, 0xFF}, // RGB332 = (7, 4, 3)
  305. {0xFC, 0xB4, 0x00, 0xFF}, // RGB332 = (7, 5, 0)
  306. {0xFC, 0xB4, 0x55, 0xFF}, // RGB332 = (7, 5, 1)
  307. {0xFC, 0xB4, 0xAA, 0xFF}, // RGB332 = (7, 5, 2)
  308. {0xFC, 0xB4, 0xFF, 0xFF}, // RGB332 = (7, 5, 3)
  309. {0xFC, 0xD8, 0x00, 0xFF}, // RGB332 = (7, 6, 0)
  310. {0xFC, 0xD8, 0x55, 0xFF}, // RGB332 = (7, 6, 1)
  311. {0xFC, 0xD8, 0xAA, 0xFF}, // RGB332 = (7, 6, 2)
  312. {0xFC, 0xD8, 0xFF, 0xFF}, // RGB332 = (7, 6, 3)
  313. {0xFC, 0xFC, 0x00, 0xFF}, // RGB332 = (7, 7, 0)
  314. {0xFC, 0xFC, 0xAA, 0xFF}, // RGB332 = (7, 7, 2)
  315. };
  316. grub_err_t
  317. grub_video_fb_init (void)
  318. {
  319. grub_free (framebuffer.palette);
  320. framebuffer.render_target = 0;
  321. framebuffer.back_target = 0;
  322. framebuffer.palette = 0;
  323. framebuffer.palette_size = 0;
  324. framebuffer.set_page = 0;
  325. return GRUB_ERR_NONE;
  326. }
  327. grub_err_t
  328. grub_video_fb_fini (void)
  329. {
  330. /* TODO: destroy render targets. */
  331. grub_free (framebuffer.offscreen_buffer);
  332. grub_free (framebuffer.palette);
  333. framebuffer.render_target = 0;
  334. framebuffer.back_target = 0;
  335. framebuffer.palette = 0;
  336. framebuffer.palette_size = 0;
  337. framebuffer.set_page = 0;
  338. framebuffer.offscreen_buffer = 0;
  339. return GRUB_ERR_NONE;
  340. }
  341. grub_err_t
  342. grub_video_fb_get_info (struct grub_video_mode_info *mode_info)
  343. {
  344. /* Copy mode info from active render target. */
  345. grub_memcpy (mode_info, &framebuffer.render_target->mode_info,
  346. sizeof (struct grub_video_mode_info));
  347. return GRUB_ERR_NONE;
  348. }
  349. grub_err_t
  350. grub_video_fb_get_palette (unsigned int start, unsigned int count,
  351. struct grub_video_palette_data *palette_data)
  352. {
  353. unsigned int i;
  354. /* Assume that we know everything from index color palette. */
  355. for (i = 0; (i < count) && ((i + start) < framebuffer.palette_size); i++)
  356. palette_data[i] = framebuffer.palette[start + i];
  357. return GRUB_ERR_NONE;
  358. }
  359. grub_err_t
  360. grub_video_fb_set_palette (unsigned int start, unsigned int count,
  361. struct grub_video_palette_data *palette_data)
  362. {
  363. unsigned i;
  364. if (start + count > framebuffer.palette_size)
  365. {
  366. framebuffer.palette_size = start + count;
  367. framebuffer.palette = grub_realloc (framebuffer.palette,
  368. sizeof (framebuffer.palette[0])
  369. * framebuffer.palette_size);
  370. if (!framebuffer.palette)
  371. {
  372. grub_video_fb_fini ();
  373. return grub_errno;
  374. }
  375. }
  376. for (i = 0; (i < count) && ((i + start) < framebuffer.palette_size); i++)
  377. framebuffer.palette[start + i] = palette_data[i];
  378. return GRUB_ERR_NONE;
  379. }
  380. static grub_err_t
  381. grub_video_fb_set_area (void)
  382. {
  383. unsigned int viewport_x1 = framebuffer.render_target->viewport.x;
  384. unsigned int viewport_y1 = framebuffer.render_target->viewport.y;
  385. unsigned int viewport_width = framebuffer.render_target->viewport.width;
  386. unsigned int viewport_height = framebuffer.render_target->viewport.height;
  387. unsigned int viewport_x2 = viewport_x1 + viewport_width;
  388. unsigned int viewport_y2 = viewport_y1 + viewport_height;
  389. unsigned int region_x1 = framebuffer.render_target->region.x;
  390. unsigned int region_y1 = framebuffer.render_target->region.y;
  391. unsigned int region_width = framebuffer.render_target->region.width;
  392. unsigned int region_height = framebuffer.render_target->region.height;
  393. unsigned int region_x2 = region_x1 + region_width;
  394. unsigned int region_y2 = region_y1 + region_height;
  395. unsigned int max_x1 = grub_max (viewport_x1, region_x1);
  396. unsigned int min_x2 = grub_min (viewport_x2, region_x2);
  397. unsigned int max_y1 = grub_max (viewport_y1, region_y1);
  398. unsigned int min_y2 = grub_min (viewport_y2, region_y2);
  399. /* Viewport and region do not intersect. */
  400. if (viewport_width == 0 || viewport_height == 0 || region_width == 0
  401. || region_height == 0 || max_x1 >= min_x2 || max_y1 >= min_y2)
  402. {
  403. framebuffer.render_target->area.x = 0;
  404. framebuffer.render_target->area.y = 0;
  405. framebuffer.render_target->area.width = 0;
  406. framebuffer.render_target->area.height = 0;
  407. framebuffer.render_target->area_offset_x = 0;
  408. framebuffer.render_target->area_offset_y = 0;
  409. return GRUB_ERR_NONE;
  410. }
  411. /* There is non-zero intersection. */
  412. framebuffer.render_target->area.x = max_x1;
  413. framebuffer.render_target->area.y = max_y1;
  414. framebuffer.render_target->area.width = min_x2 - max_x1;
  415. framebuffer.render_target->area.height = min_y2 - max_y1;
  416. if (region_x1 > viewport_x1)
  417. framebuffer.render_target->area_offset_x = (int)region_x1
  418. - (int)viewport_x1;
  419. else
  420. framebuffer.render_target->area_offset_x = 0;
  421. if (region_y1 > viewport_y1)
  422. framebuffer.render_target->area_offset_y = (int)region_y1
  423. - (int)viewport_y1;
  424. else
  425. framebuffer.render_target->area_offset_y = 0;
  426. return GRUB_ERR_NONE;
  427. }
  428. grub_err_t
  429. grub_video_fb_set_viewport (unsigned int x, unsigned int y,
  430. unsigned int width, unsigned int height)
  431. {
  432. /* Make sure viewport is within screen dimensions. If viewport was set
  433. to be out of the screen, mark its size as zero. */
  434. if (x > framebuffer.render_target->mode_info.width)
  435. {
  436. x = 0;
  437. width = 0;
  438. }
  439. if (y > framebuffer.render_target->mode_info.height)
  440. {
  441. y = 0;
  442. height = 0;
  443. }
  444. if (x + width > framebuffer.render_target->mode_info.width)
  445. width = framebuffer.render_target->mode_info.width - x;
  446. if (y + height > framebuffer.render_target->mode_info.height)
  447. height = framebuffer.render_target->mode_info.height - y;
  448. framebuffer.render_target->viewport.x = x;
  449. framebuffer.render_target->viewport.y = y;
  450. framebuffer.render_target->viewport.width = width;
  451. framebuffer.render_target->viewport.height = height;
  452. /* Count drawing area only if needed. */
  453. if (framebuffer.render_target->area_enabled)
  454. grub_video_fb_set_area ();
  455. return GRUB_ERR_NONE;
  456. }
  457. grub_err_t
  458. grub_video_fb_get_viewport (unsigned int *x, unsigned int *y,
  459. unsigned int *width, unsigned int *height)
  460. {
  461. if (x) *x = framebuffer.render_target->viewport.x;
  462. if (y) *y = framebuffer.render_target->viewport.y;
  463. if (width) *width = framebuffer.render_target->viewport.width;
  464. if (height) *height = framebuffer.render_target->viewport.height;
  465. return GRUB_ERR_NONE;
  466. }
  467. grub_err_t
  468. grub_video_fb_set_region (unsigned int x, unsigned int y,
  469. unsigned int width, unsigned int height)
  470. {
  471. /* Make sure region is within screen dimensions. If region was set
  472. to be out of the screen, mark its size as zero. */
  473. if (x > framebuffer.render_target->mode_info.width)
  474. {
  475. x = 0;
  476. width = 0;
  477. }
  478. if (y > framebuffer.render_target->mode_info.height)
  479. {
  480. y = 0;
  481. height = 0;
  482. }
  483. if (x + width > framebuffer.render_target->mode_info.width)
  484. width = framebuffer.render_target->mode_info.width - x;
  485. if (y + height > framebuffer.render_target->mode_info.height)
  486. height = framebuffer.render_target->mode_info.height - y;
  487. framebuffer.render_target->region.x = x;
  488. framebuffer.render_target->region.y = y;
  489. framebuffer.render_target->region.width = width;
  490. framebuffer.render_target->region.height = height;
  491. /* If we have called set_region then area is needed. */
  492. grub_video_fb_set_area ();
  493. return GRUB_ERR_NONE;
  494. }
  495. grub_err_t
  496. grub_video_fb_get_region (unsigned int *x, unsigned int *y,
  497. unsigned int *width, unsigned int *height)
  498. {
  499. if (x) *x = framebuffer.render_target->region.x;
  500. if (y) *y = framebuffer.render_target->region.y;
  501. if (width) *width = framebuffer.render_target->region.width;
  502. if (height) *height = framebuffer.render_target->region.height;
  503. return GRUB_ERR_NONE;
  504. }
  505. grub_err_t
  506. grub_video_fb_set_area_status (grub_video_area_status_t area_status)
  507. {
  508. if (area_status == GRUB_VIDEO_AREA_ENABLED)
  509. framebuffer.render_target->area_enabled = 1;
  510. else
  511. framebuffer.render_target->area_enabled = 0;
  512. return GRUB_ERR_NONE;
  513. }
  514. grub_err_t
  515. grub_video_fb_get_area_status (grub_video_area_status_t *area_status)
  516. {
  517. if (!area_status)
  518. return GRUB_ERR_NONE;
  519. if (framebuffer.render_target->area_enabled)
  520. *area_status = GRUB_VIDEO_AREA_ENABLED;
  521. else
  522. *area_status = GRUB_VIDEO_AREA_DISABLED;
  523. return GRUB_ERR_NONE;
  524. }
  525. /* Maps color name to target optimized color format. */
  526. grub_video_color_t
  527. grub_video_fb_map_color (grub_uint32_t color_name)
  528. {
  529. /* TODO: implement color theme mapping code. */
  530. if (color_name < framebuffer.palette_size)
  531. {
  532. if ((framebuffer.render_target->mode_info.mode_type
  533. & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
  534. return color_name;
  535. else
  536. {
  537. grub_video_color_t color;
  538. color = grub_video_fb_map_rgb (framebuffer.palette[color_name].r,
  539. framebuffer.palette[color_name].g,
  540. framebuffer.palette[color_name].b);
  541. return color;
  542. }
  543. }
  544. return 0;
  545. }
  546. /* Maps RGB to target optimized color format. */
  547. grub_video_color_t
  548. grub_video_fb_map_rgb (grub_uint8_t red, grub_uint8_t green,
  549. grub_uint8_t blue)
  550. {
  551. if ((framebuffer.render_target->mode_info.mode_type
  552. & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
  553. {
  554. int minindex = 0;
  555. int delta = 0;
  556. int tmp;
  557. int val;
  558. unsigned i;
  559. /* Find best matching color. */
  560. for (i = 0; i < framebuffer.palette_size; i++)
  561. {
  562. val = framebuffer.palette[i].r - red;
  563. tmp = val * val;
  564. val = framebuffer.palette[i].g - green;
  565. tmp += val * val;
  566. val = framebuffer.palette[i].b - blue;
  567. tmp += val * val;
  568. if (i == 0)
  569. delta = tmp;
  570. if (tmp < delta)
  571. {
  572. delta = tmp;
  573. minindex = i;
  574. if (tmp == 0)
  575. break;
  576. }
  577. }
  578. return minindex;
  579. }
  580. else if ((framebuffer.render_target->mode_info.mode_type
  581. & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
  582. {
  583. if (red == framebuffer.render_target->mode_info.fg_red
  584. && green == framebuffer.render_target->mode_info.fg_green
  585. && blue == framebuffer.render_target->mode_info.fg_blue)
  586. return 1;
  587. else
  588. return 0;
  589. }
  590. else
  591. {
  592. grub_uint32_t value;
  593. grub_uint8_t alpha = 255; /* Opaque color. */
  594. red >>= 8 - framebuffer.render_target->mode_info.red_mask_size;
  595. green >>= 8 - framebuffer.render_target->mode_info.green_mask_size;
  596. blue >>= 8 - framebuffer.render_target->mode_info.blue_mask_size;
  597. alpha >>= 8 - framebuffer.render_target->mode_info.reserved_mask_size;
  598. value = red << framebuffer.render_target->mode_info.red_field_pos;
  599. value |= green << framebuffer.render_target->mode_info.green_field_pos;
  600. value |= blue << framebuffer.render_target->mode_info.blue_field_pos;
  601. value |= alpha << framebuffer.render_target->mode_info.reserved_field_pos;
  602. return value;
  603. }
  604. }
  605. /* Maps RGBA to target optimized color format. */
  606. grub_video_color_t
  607. grub_video_fb_map_rgba (grub_uint8_t red, grub_uint8_t green,
  608. grub_uint8_t blue, grub_uint8_t alpha)
  609. {
  610. if ((framebuffer.render_target->mode_info.mode_type
  611. & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
  612. {
  613. if ((framebuffer.render_target->mode_info.mode_type
  614. & GRUB_VIDEO_MODE_TYPE_ALPHA) != 0
  615. && alpha == 0)
  616. return 0xf0;
  617. /* No alpha available in index color modes, just use
  618. same value as in only RGB modes. */
  619. return grub_video_fb_map_rgb (red, green, blue);
  620. }
  621. else if ((framebuffer.render_target->mode_info.mode_type
  622. & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
  623. {
  624. if (red == framebuffer.render_target->mode_info.fg_red
  625. && green == framebuffer.render_target->mode_info.fg_green
  626. && blue == framebuffer.render_target->mode_info.fg_blue
  627. && alpha == framebuffer.render_target->mode_info.fg_alpha)
  628. return 1;
  629. else
  630. return 0;
  631. }
  632. else
  633. {
  634. grub_uint32_t value;
  635. red >>= 8 - framebuffer.render_target->mode_info.red_mask_size;
  636. green >>= 8 - framebuffer.render_target->mode_info.green_mask_size;
  637. blue >>= 8 - framebuffer.render_target->mode_info.blue_mask_size;
  638. alpha >>= 8 - framebuffer.render_target->mode_info.reserved_mask_size;
  639. value = red << framebuffer.render_target->mode_info.red_field_pos;
  640. value |= green << framebuffer.render_target->mode_info.green_field_pos;
  641. value |= blue << framebuffer.render_target->mode_info.blue_field_pos;
  642. value |= alpha << framebuffer.render_target->mode_info.reserved_field_pos;
  643. return value;
  644. }
  645. }
  646. /* Splits target optimized format to components. */
  647. grub_err_t
  648. grub_video_fb_unmap_color (grub_video_color_t color,
  649. grub_uint8_t *red, grub_uint8_t *green,
  650. grub_uint8_t *blue, grub_uint8_t *alpha)
  651. {
  652. struct grub_video_fbblit_info target_info;
  653. target_info.mode_info = &framebuffer.render_target->mode_info;
  654. target_info.data = framebuffer.render_target->data;
  655. grub_video_fb_unmap_color_int (&target_info, color, red, green, blue, alpha);
  656. return GRUB_ERR_NONE;
  657. }
  658. /* Splits color in source format to components. */
  659. void
  660. grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source,
  661. grub_video_color_t color,
  662. grub_uint8_t *red, grub_uint8_t *green,
  663. grub_uint8_t *blue, grub_uint8_t *alpha)
  664. {
  665. struct grub_video_mode_info *mode_info;
  666. mode_info = source->mode_info;
  667. if ((mode_info->mode_type
  668. & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0)
  669. {
  670. if ((framebuffer.render_target->mode_info.mode_type
  671. & GRUB_VIDEO_MODE_TYPE_ALPHA) != 0
  672. && color == 0xf0)
  673. {
  674. *red = 0;
  675. *green = 0;
  676. *blue = 0;
  677. *alpha = 0;
  678. return;
  679. }
  680. /* If we have an out-of-bounds color, return transparent black. */
  681. if (color > 255)
  682. {
  683. *red = 0;
  684. *green = 0;
  685. *blue = 0;
  686. *alpha = 0;
  687. return;
  688. }
  689. *red = framebuffer.palette[color].r;
  690. *green = framebuffer.palette[color].g;
  691. *blue = framebuffer.palette[color].b;
  692. *alpha = framebuffer.palette[color].a;
  693. return;
  694. }
  695. else if ((mode_info->mode_type
  696. & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
  697. {
  698. if (color & 1)
  699. {
  700. *red = mode_info->fg_red;
  701. *green = mode_info->fg_green;
  702. *blue = mode_info->fg_blue;
  703. *alpha = mode_info->fg_alpha;
  704. }
  705. else
  706. {
  707. *red = mode_info->bg_red;
  708. *green = mode_info->bg_green;
  709. *blue = mode_info->bg_blue;
  710. *alpha = mode_info->bg_alpha;
  711. }
  712. }
  713. else
  714. {
  715. grub_uint32_t tmp;
  716. /* Get red component. */
  717. tmp = color >> mode_info->red_field_pos;
  718. tmp &= (1 << mode_info->red_mask_size) - 1;
  719. tmp <<= 8 - mode_info->red_mask_size;
  720. tmp |= (1 << (8 - mode_info->red_mask_size)) - 1;
  721. *red = tmp & 0xFF;
  722. /* Get green component. */
  723. tmp = color >> mode_info->green_field_pos;
  724. tmp &= (1 << mode_info->green_mask_size) - 1;
  725. tmp <<= 8 - mode_info->green_mask_size;
  726. tmp |= (1 << (8 - mode_info->green_mask_size)) - 1;
  727. *green = tmp & 0xFF;
  728. /* Get blue component. */
  729. tmp = color >> mode_info->blue_field_pos;
  730. tmp &= (1 << mode_info->blue_mask_size) - 1;
  731. tmp <<= 8 - mode_info->blue_mask_size;
  732. tmp |= (1 << (8 - mode_info->blue_mask_size)) - 1;
  733. *blue = tmp & 0xFF;
  734. /* Get alpha component. */
  735. if (source->mode_info->reserved_mask_size > 0)
  736. {
  737. tmp = color >> mode_info->reserved_field_pos;
  738. tmp &= (1 << mode_info->reserved_mask_size) - 1;
  739. tmp <<= 8 - mode_info->reserved_mask_size;
  740. tmp |= (1 << (8 - mode_info->reserved_mask_size)) - 1;
  741. }
  742. else
  743. /* If there is no alpha component, assume it opaque. */
  744. tmp = 255;
  745. *alpha = tmp & 0xFF;
  746. }
  747. }
  748. static void
  749. dirty (int y, int height)
  750. {
  751. if (framebuffer.render_target != framebuffer.back_target)
  752. return;
  753. if (framebuffer.current_dirty.first_line > y)
  754. framebuffer.current_dirty.first_line = y;
  755. if (framebuffer.current_dirty.last_line < y + height)
  756. framebuffer.current_dirty.last_line = y + height;
  757. }
  758. grub_err_t
  759. grub_video_fb_fill_rect (grub_video_color_t color, int x, int y,
  760. unsigned int width, unsigned int height)
  761. {
  762. struct grub_video_fbblit_info target;
  763. unsigned int area_x;
  764. unsigned int area_y;
  765. unsigned int area_width;
  766. unsigned int area_height;
  767. if (framebuffer.render_target->area_enabled)
  768. {
  769. area_x = framebuffer.render_target->area.x;
  770. area_y = framebuffer.render_target->area.y;
  771. area_width = framebuffer.render_target->area.width;
  772. area_height = framebuffer.render_target->area.height;
  773. x -= framebuffer.render_target->area_offset_x;
  774. y -= framebuffer.render_target->area_offset_y;
  775. }
  776. else
  777. {
  778. area_x = framebuffer.render_target->viewport.x;
  779. area_y = framebuffer.render_target->viewport.y;
  780. area_width = framebuffer.render_target->viewport.width;
  781. area_height = framebuffer.render_target->viewport.height;
  782. }
  783. /* Make sure there is something to do. */
  784. if ((area_width == 0) || (area_height == 0))
  785. return GRUB_ERR_NONE;
  786. if ((x >= (int)area_width) || (x + (int)width < 0))
  787. return GRUB_ERR_NONE;
  788. if ((y >= (int)area_height) || (y + (int)height < 0))
  789. return GRUB_ERR_NONE;
  790. /* Do not allow drawing out of area. */
  791. if (x < 0)
  792. {
  793. width += x;
  794. x = 0;
  795. }
  796. if (y < 0)
  797. {
  798. height += y;
  799. y = 0;
  800. }
  801. if ((x + width) > area_width)
  802. width = area_width - x;
  803. if ((y + height) > area_height)
  804. height = area_height - y;
  805. /* Add area offset. */
  806. x += area_x;
  807. y += area_y;
  808. dirty (y, height);
  809. /* Use fbblit_info to encapsulate rendering. */
  810. target.mode_info = &framebuffer.render_target->mode_info;
  811. target.data = framebuffer.render_target->data;
  812. grub_video_fb_fill_dispatch (&target, color, x, y,
  813. width, height);
  814. return GRUB_ERR_NONE;
  815. }
  816. static inline grub_err_t __attribute__ ((always_inline))
  817. grub_video_fb_blit_source (struct grub_video_fbblit_info *source,
  818. enum grub_video_blit_operators oper, int x, int y,
  819. int offset_x, int offset_y,
  820. unsigned int width, unsigned int height)
  821. {
  822. struct grub_video_fbblit_info target;
  823. unsigned int area_x;
  824. unsigned int area_y;
  825. unsigned int area_width;
  826. unsigned int area_height;
  827. if (framebuffer.render_target->area_enabled)
  828. {
  829. area_x = framebuffer.render_target->area.x;
  830. area_y = framebuffer.render_target->area.y;
  831. area_width = framebuffer.render_target->area.width;
  832. area_height = framebuffer.render_target->area.height;
  833. x -= framebuffer.render_target->area_offset_x;
  834. y -= framebuffer.render_target->area_offset_y;
  835. }
  836. else
  837. {
  838. area_x = framebuffer.render_target->viewport.x;
  839. area_y = framebuffer.render_target->viewport.y;
  840. area_width = framebuffer.render_target->viewport.width;
  841. area_height = framebuffer.render_target->viewport.height;
  842. }
  843. /* Make sure there is something to do. */
  844. if ((area_width == 0) || (area_height == 0) || (width == 0) || (height == 0))
  845. return GRUB_ERR_NONE;
  846. if ((x >= (int)area_width) || (x + (int)width < 0))
  847. return GRUB_ERR_NONE;
  848. if ((y >= (int)area_height) || (y + (int)height < 0))
  849. return GRUB_ERR_NONE;
  850. if ((x + (int)source->mode_info->width) < 0)
  851. return GRUB_ERR_NONE;
  852. if ((y + (int)source->mode_info->height) < 0)
  853. return GRUB_ERR_NONE;
  854. if ((offset_x >= (int)source->mode_info->width)
  855. || (offset_x + (int)width < 0))
  856. return GRUB_ERR_NONE;
  857. if ((offset_y >= (int)source->mode_info->height)
  858. || (offset_y + (int)height < 0))
  859. return GRUB_ERR_NONE;
  860. /* If we have negative coordinates, optimize drawing to minimum. */
  861. if (offset_x < 0)
  862. {
  863. width += offset_x;
  864. x -= offset_x;
  865. offset_x = 0;
  866. }
  867. if (offset_y < 0)
  868. {
  869. height += offset_y;
  870. y -= offset_y;
  871. offset_y = 0;
  872. }
  873. if (x < 0)
  874. {
  875. width += x;
  876. offset_x -= x;
  877. x = 0;
  878. }
  879. if (y < 0)
  880. {
  881. height += y;
  882. offset_y -= y;
  883. y = 0;
  884. }
  885. /* Do not allow drawing out of area. */
  886. if ((x + width) > area_width)
  887. width = area_width - x;
  888. if ((y + height) > area_height)
  889. height = area_height - y;
  890. if ((offset_x + width) > source->mode_info->width)
  891. width = source->mode_info->width - offset_x;
  892. if ((offset_y + height) > source->mode_info->height)
  893. height = source->mode_info->height - offset_y;
  894. /* Limit drawing to source render target dimensions. */
  895. if (width > source->mode_info->width)
  896. width = source->mode_info->width;
  897. if (height > source->mode_info->height)
  898. height = source->mode_info->height;
  899. /* Add viewport offset. */
  900. x += area_x;
  901. y += area_y;
  902. /* Use fbblit_info to encapsulate rendering. */
  903. target.mode_info = &framebuffer.render_target->mode_info;
  904. target.data = framebuffer.render_target->data;
  905. /* Do actual blitting. */
  906. dirty (y, height);
  907. grub_video_fb_dispatch_blit (&target, source, oper, x, y, width, height,
  908. offset_x, offset_y);
  909. return GRUB_ERR_NONE;
  910. }
  911. grub_err_t
  912. grub_video_fb_blit_bitmap (struct grub_video_bitmap *bitmap,
  913. enum grub_video_blit_operators oper, int x, int y,
  914. int offset_x, int offset_y,
  915. unsigned int width, unsigned int height)
  916. {
  917. struct grub_video_fbblit_info source_info;
  918. source_info.mode_info = &bitmap->mode_info;
  919. source_info.data = bitmap->data;
  920. return grub_video_fb_blit_source (&source_info, oper, x, y,
  921. offset_x, offset_y, width, height);
  922. }
  923. grub_err_t
  924. grub_video_fb_blit_render_target (struct grub_video_fbrender_target *source,
  925. enum grub_video_blit_operators oper,
  926. int x, int y, int offset_x, int offset_y,
  927. unsigned int width, unsigned int height)
  928. {
  929. struct grub_video_fbblit_info source_info;
  930. source_info.mode_info = &source->mode_info;
  931. source_info.data = source->data;
  932. return grub_video_fb_blit_source (&source_info, oper, x, y,
  933. offset_x, offset_y, width, height);
  934. }
  935. grub_err_t
  936. grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
  937. {
  938. int width;
  939. int height;
  940. int src_x;
  941. int src_y;
  942. int dst_x;
  943. int dst_y;
  944. /* 1. Check if we have something to do. */
  945. if ((dx == 0) && (dy == 0))
  946. return GRUB_ERR_NONE;
  947. width = framebuffer.render_target->viewport.width - grub_abs (dx);
  948. height = framebuffer.render_target->viewport.height - grub_abs (dy);
  949. dirty (framebuffer.render_target->viewport.y,
  950. framebuffer.render_target->viewport.height);
  951. if (dx < 0)
  952. {
  953. src_x = framebuffer.render_target->viewport.x - dx;
  954. dst_x = framebuffer.render_target->viewport.x;
  955. }
  956. else
  957. {
  958. src_x = framebuffer.render_target->viewport.x;
  959. dst_x = framebuffer.render_target->viewport.x + dx;
  960. }
  961. if (dy < 0)
  962. {
  963. src_y = framebuffer.render_target->viewport.y - dy;
  964. dst_y = framebuffer.render_target->viewport.y;
  965. }
  966. else
  967. {
  968. src_y = framebuffer.render_target->viewport.y;
  969. dst_y = framebuffer.render_target->viewport.y + dy;
  970. }
  971. /* 2. Check if there is need to copy data. */
  972. if ((grub_abs (dx) < framebuffer.render_target->viewport.width)
  973. && (grub_abs (dy) < framebuffer.render_target->viewport.height))
  974. {
  975. /* 3. Move data in render target. */
  976. struct grub_video_fbblit_info target;
  977. int i, j;
  978. int linedelta, linelen;
  979. target.mode_info = &framebuffer.render_target->mode_info;
  980. target.data = framebuffer.render_target->data;
  981. linedelta = target.mode_info->pitch
  982. - width * target.mode_info->bytes_per_pixel;
  983. linelen = width * target.mode_info->bytes_per_pixel;
  984. #define DO_SCROLL \
  985. /* Check vertical direction of the move. */ \
  986. if (dy < 0 || (dy == 0 && dx < 0)) \
  987. { \
  988. dst = (void *) grub_video_fb_get_video_ptr (&target, \
  989. dst_x, dst_y); \
  990. src = (void *) grub_video_fb_get_video_ptr (&target, \
  991. src_x, src_y); \
  992. /* 3a. Move data upwards. */ \
  993. for (j = 0; j < height; j++) \
  994. { \
  995. for (i = 0; i < linelen; i++) \
  996. *(dst++) = *(src++); \
  997. dst += linedelta; \
  998. src += linedelta; \
  999. } \
  1000. } \
  1001. else \
  1002. { \
  1003. /* 3b. Move data downwards. */ \
  1004. dst = (void *) grub_video_fb_get_video_ptr (&target, \
  1005. dst_x + width, \
  1006. dst_y + height - 1); \
  1007. src = (void *) grub_video_fb_get_video_ptr (&target, \
  1008. src_x + width, \
  1009. src_y + height - 1); \
  1010. dst--; \
  1011. src--; \
  1012. for (j = 0; j < height; j++) \
  1013. { \
  1014. for (i = 0; i < linelen; i++) \
  1015. *(dst--) = *(src--); \
  1016. dst -= linedelta; \
  1017. src -= linedelta; \
  1018. } \
  1019. }
  1020. /* If everything is aligned on 32-bit use 32-bit copy. */
  1021. if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y)
  1022. % sizeof (grub_uint32_t) == 0
  1023. && (grub_addr_t) grub_video_fb_get_video_ptr (&target, dst_x, dst_y)
  1024. % sizeof (grub_uint32_t) == 0
  1025. && linelen % sizeof (grub_uint32_t) == 0
  1026. && linedelta % sizeof (grub_uint32_t) == 0)
  1027. {
  1028. grub_uint32_t *src, *dst;
  1029. linelen /= sizeof (grub_uint32_t);
  1030. linedelta /= sizeof (grub_uint32_t);
  1031. DO_SCROLL
  1032. }
  1033. /* If everything is aligned on 16-bit use 16-bit copy. */
  1034. else if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y)
  1035. % sizeof (grub_uint16_t) == 0
  1036. && (grub_addr_t) grub_video_fb_get_video_ptr (&target,
  1037. dst_x, dst_y)
  1038. % sizeof (grub_uint16_t) == 0
  1039. && linelen % sizeof (grub_uint16_t) == 0
  1040. && linedelta % sizeof (grub_uint16_t) == 0)
  1041. {
  1042. grub_uint16_t *src, *dst;
  1043. linelen /= sizeof (grub_uint16_t);
  1044. linedelta /= sizeof (grub_uint16_t);
  1045. DO_SCROLL
  1046. }
  1047. /* If not aligned at all use 8-bit copy. */
  1048. else
  1049. {
  1050. grub_uint8_t *src, *dst;
  1051. DO_SCROLL
  1052. }
  1053. }
  1054. /* 4. Fill empty space with specified color. In this implementation
  1055. there might be colliding areas but at the moment there is no need
  1056. to optimize this. */
  1057. /* 4a. Fill top & bottom parts. */
  1058. if (dy > 0)
  1059. grub_video_fb_fill_rect (color, 0, 0, framebuffer.render_target->viewport.width, dy);
  1060. else if (dy < 0)
  1061. {
  1062. if (framebuffer.render_target->viewport.height < grub_abs (dy))
  1063. dy = -framebuffer.render_target->viewport.height;
  1064. grub_video_fb_fill_rect (color, 0, framebuffer.render_target->viewport.height + dy,
  1065. framebuffer.render_target->viewport.width, -dy);
  1066. }
  1067. /* 4b. Fill left & right parts. */
  1068. if (dx > 0)
  1069. grub_video_fb_fill_rect (color, 0, 0,
  1070. dx, framebuffer.render_target->viewport.height);
  1071. else if (dx < 0)
  1072. {
  1073. if (framebuffer.render_target->viewport.width < grub_abs (dx))
  1074. dx = -framebuffer.render_target->viewport.width;
  1075. grub_video_fb_fill_rect (color, framebuffer.render_target->viewport.width + dx, 0,
  1076. -dx, framebuffer.render_target->viewport.height);
  1077. }
  1078. return GRUB_ERR_NONE;
  1079. }
  1080. grub_err_t
  1081. grub_video_fb_create_render_target (struct grub_video_fbrender_target **result,
  1082. unsigned int width, unsigned int height,
  1083. unsigned int mode_type __attribute__ ((unused)))
  1084. {
  1085. struct grub_video_fbrender_target *target;
  1086. unsigned int size;
  1087. /* Validate arguments. */
  1088. if ((! result)
  1089. || (width == 0)
  1090. || (height == 0))
  1091. return grub_error (GRUB_ERR_BUG,
  1092. "invalid argument given");
  1093. /* Allocate memory for render target. */
  1094. target = grub_malloc (sizeof (struct grub_video_fbrender_target));
  1095. if (! target)
  1096. return grub_errno;
  1097. /* TODO: Implement other types too.
  1098. Currently only 32bit render targets are supported. */
  1099. /* Mark render target as allocated. */
  1100. target->is_allocated = 1;
  1101. /* Maximize viewport, region and area. */
  1102. target->viewport.x = 0;
  1103. target->viewport.y = 0;
  1104. target->viewport.width = width;
  1105. target->viewport.height = height;
  1106. target->region.x = 0;
  1107. target->region.y = 0;
  1108. target->region.width = width;
  1109. target->region.height = height;
  1110. target->area_enabled = 0;
  1111. target->area.x = 0;
  1112. target->area.y = 0;
  1113. target->area.width = width;
  1114. target->area.height = height;
  1115. target->area_offset_x = 0;
  1116. target->area_offset_y = 0;
  1117. /* Setup render target format. */
  1118. target->mode_info.width = width;
  1119. target->mode_info.height = height;
  1120. switch (mode_type)
  1121. {
  1122. case GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
  1123. | GRUB_VIDEO_MODE_TYPE_ALPHA:
  1124. target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
  1125. | GRUB_VIDEO_MODE_TYPE_ALPHA;
  1126. target->mode_info.bpp = 8;
  1127. target->mode_info.bytes_per_pixel = 1;
  1128. target->mode_info.number_of_colors = 16;
  1129. target->mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR_ALPHA;
  1130. break;
  1131. default:
  1132. target->mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB
  1133. | GRUB_VIDEO_MODE_TYPE_ALPHA;
  1134. target->mode_info.bpp = 32;
  1135. target->mode_info.bytes_per_pixel = 4;
  1136. target->mode_info.red_mask_size = 8;
  1137. target->mode_info.red_field_pos = 0;
  1138. target->mode_info.green_mask_size = 8;
  1139. target->mode_info.green_field_pos = 8;
  1140. target->mode_info.blue_mask_size = 8;
  1141. target->mode_info.blue_field_pos = 16;
  1142. target->mode_info.reserved_mask_size = 8;
  1143. target->mode_info.reserved_field_pos = 24;
  1144. target->mode_info.number_of_colors = framebuffer.palette_size; /* Emulated palette. */
  1145. target->mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_RGBA_8888;
  1146. break;
  1147. }
  1148. target->mode_info.pitch = target->mode_info.bytes_per_pixel * width;
  1149. /* Calculate size needed for the data. */
  1150. size = (width * target->mode_info.bytes_per_pixel) * height;
  1151. target->data = grub_malloc (size);
  1152. if (! target->data)
  1153. {
  1154. grub_free (target);
  1155. return grub_errno;
  1156. }
  1157. /* Clear render target with black and maximum transparency. */
  1158. if (mode_type == (GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
  1159. | GRUB_VIDEO_MODE_TYPE_ALPHA))
  1160. grub_memset (target->data, 0xf0, size);
  1161. else
  1162. grub_memset (target->data, 0, size);
  1163. /* TODO: Add render target to render target list. */
  1164. /* Save result to caller. */
  1165. *result = target;
  1166. return GRUB_ERR_NONE;
  1167. }
  1168. grub_err_t
  1169. grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_target **result,
  1170. const struct grub_video_mode_info *mode_info,
  1171. void *ptr)
  1172. {
  1173. struct grub_video_fbrender_target *target;
  1174. unsigned y;
  1175. #ifndef GRUB_HAVE_UNALIGNED_ACCESS
  1176. if (!(mode_info->bytes_per_pixel & (mode_info->bytes_per_pixel - 1))
  1177. && ((grub_addr_t) ptr & (mode_info->bytes_per_pixel - 1)))
  1178. return grub_error (GRUB_ERR_BAD_ARGUMENT, "unaligned pointer");
  1179. if (!(mode_info->bytes_per_pixel & (mode_info->bytes_per_pixel - 1))
  1180. && (mode_info->pitch & (mode_info->bytes_per_pixel - 1)))
  1181. return grub_error (GRUB_ERR_BAD_ARGUMENT, "unaligned pitch");
  1182. #endif
  1183. /* Allocate memory for render target. */
  1184. target = grub_malloc (sizeof (struct grub_video_fbrender_target));
  1185. if (! target)
  1186. return grub_errno;
  1187. /* Mark framebuffer memory as non allocated. */
  1188. target->is_allocated = 0;
  1189. target->data = ptr;
  1190. grub_memcpy (&(target->mode_info), mode_info, sizeof (target->mode_info));
  1191. /* Reset viewport, region and area to match new mode. */
  1192. target->viewport.x = 0;
  1193. target->viewport.y = 0;
  1194. target->viewport.width = mode_info->width;
  1195. target->viewport.height = mode_info->height;
  1196. target->region.x = 0;
  1197. target->region.y = 0;
  1198. target->region.width = mode_info->width;
  1199. target->region.height = mode_info->height;
  1200. target->area_enabled = 0;
  1201. target->area.x = 0;
  1202. target->area.y = 0;
  1203. target->area.width = mode_info->width;
  1204. target->area.height = mode_info->height;
  1205. target->area_offset_x = 0;
  1206. target->area_offset_y = 0;
  1207. /* Clear render target with black and maximum transparency. */
  1208. for (y = 0; y < mode_info->height; y++)
  1209. grub_memset (target->data + mode_info->pitch * y, 0,
  1210. mode_info->bytes_per_pixel * mode_info->width);
  1211. /* Save result to caller. */
  1212. *result = target;
  1213. return GRUB_ERR_NONE;
  1214. }
  1215. grub_err_t
  1216. grub_video_fb_delete_render_target (struct grub_video_fbrender_target *target)
  1217. {
  1218. /* If there is no target, then just return without error. */
  1219. if (! target)
  1220. return GRUB_ERR_NONE;
  1221. /* TODO: Delist render target from render target list. */
  1222. /* If this is software render target, free it's memory. */
  1223. if (target->is_allocated)
  1224. grub_free (target->data);
  1225. /* Free render target. */
  1226. grub_free (target);
  1227. return GRUB_ERR_NONE;
  1228. }
  1229. grub_err_t
  1230. grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target)
  1231. {
  1232. if (target == (struct grub_video_fbrender_target *)
  1233. GRUB_VIDEO_RENDER_TARGET_DISPLAY)
  1234. target = framebuffer.back_target;
  1235. if (! target->data)
  1236. return grub_error (GRUB_ERR_BUG,
  1237. "invalid render target given");
  1238. framebuffer.render_target = target;
  1239. return GRUB_ERR_NONE;
  1240. }
  1241. grub_err_t
  1242. grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **target)
  1243. {
  1244. *target = framebuffer.render_target;
  1245. if (*target == framebuffer.back_target)
  1246. *target = (struct grub_video_fbrender_target *) GRUB_VIDEO_RENDER_TARGET_DISPLAY;
  1247. return GRUB_ERR_NONE;
  1248. }
  1249. static grub_err_t
  1250. doublebuf_blit_update_screen (void)
  1251. {
  1252. if (framebuffer.current_dirty.first_line
  1253. <= framebuffer.current_dirty.last_line)
  1254. grub_memcpy ((char *) framebuffer.pages[0]
  1255. + framebuffer.current_dirty.first_line
  1256. * framebuffer.back_target->mode_info.pitch,
  1257. (char *) framebuffer.back_target->data
  1258. + framebuffer.current_dirty.first_line
  1259. * framebuffer.back_target->mode_info.pitch,
  1260. framebuffer.back_target->mode_info.pitch
  1261. * (framebuffer.current_dirty.last_line
  1262. - framebuffer.current_dirty.first_line));
  1263. framebuffer.current_dirty.first_line
  1264. = framebuffer.back_target->mode_info.height;
  1265. framebuffer.current_dirty.last_line = 0;
  1266. return GRUB_ERR_NONE;
  1267. }
  1268. static grub_err_t
  1269. grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back,
  1270. struct grub_video_mode_info mode_info,
  1271. volatile void *framebuf)
  1272. {
  1273. grub_err_t err;
  1274. grub_size_t page_size = mode_info.pitch * mode_info.height;
  1275. framebuffer.offscreen_buffer = grub_zalloc (page_size);
  1276. if (! framebuffer.offscreen_buffer)
  1277. return grub_errno;
  1278. err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
  1279. &mode_info,
  1280. framebuffer.offscreen_buffer);
  1281. if (err)
  1282. {
  1283. grub_free (framebuffer.offscreen_buffer);
  1284. framebuffer.offscreen_buffer = 0;
  1285. return grub_errno;
  1286. }
  1287. (*back)->is_allocated = 1;
  1288. framebuffer.update_screen = doublebuf_blit_update_screen;
  1289. framebuffer.pages[0] = framebuf;
  1290. framebuffer.displayed_page = 0;
  1291. framebuffer.render_page = 0;
  1292. framebuffer.current_dirty.first_line = mode_info.height;
  1293. framebuffer.current_dirty.last_line = 0;
  1294. return GRUB_ERR_NONE;
  1295. }
  1296. static grub_err_t
  1297. doublebuf_pageflipping_update_screen (void)
  1298. {
  1299. int new_displayed_page;
  1300. grub_err_t err;
  1301. int first_line, last_line;
  1302. first_line = framebuffer.current_dirty.first_line;
  1303. last_line = framebuffer.current_dirty.last_line;
  1304. if (first_line > framebuffer.previous_dirty.first_line)
  1305. first_line = framebuffer.previous_dirty.first_line;
  1306. if (last_line < framebuffer.previous_dirty.last_line)
  1307. last_line = framebuffer.previous_dirty.last_line;
  1308. if (first_line <= last_line)
  1309. grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page]
  1310. + first_line * framebuffer.back_target->mode_info.pitch,
  1311. (char *) framebuffer.back_target->data
  1312. + first_line * framebuffer.back_target->mode_info.pitch,
  1313. framebuffer.back_target->mode_info.pitch
  1314. * (last_line - first_line));
  1315. framebuffer.previous_dirty = framebuffer.current_dirty;
  1316. framebuffer.current_dirty.first_line
  1317. = framebuffer.back_target->mode_info.height;
  1318. framebuffer.current_dirty.last_line = 0;
  1319. /* Swap the page numbers in the framebuffer struct. */
  1320. new_displayed_page = framebuffer.render_page;
  1321. framebuffer.render_page = framebuffer.displayed_page;
  1322. framebuffer.displayed_page = new_displayed_page;
  1323. err = framebuffer.set_page (framebuffer.displayed_page);
  1324. if (err)
  1325. {
  1326. /* Restore previous state. */
  1327. framebuffer.render_page = framebuffer.displayed_page;
  1328. framebuffer.displayed_page = new_displayed_page;
  1329. return err;
  1330. }
  1331. return GRUB_ERR_NONE;
  1332. }
  1333. static grub_err_t
  1334. doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info,
  1335. volatile void *page0_ptr,
  1336. grub_video_fb_set_page_t set_page_in,
  1337. volatile void *page1_ptr)
  1338. {
  1339. grub_err_t err;
  1340. grub_size_t page_size = mode_info->pitch * mode_info->height;
  1341. framebuffer.offscreen_buffer = grub_malloc (page_size);
  1342. if (! framebuffer.offscreen_buffer)
  1343. {
  1344. return grub_errno;
  1345. }
  1346. err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
  1347. mode_info,
  1348. framebuffer.offscreen_buffer);
  1349. if (err)
  1350. {
  1351. grub_free (framebuffer.offscreen_buffer);
  1352. framebuffer.offscreen_buffer = 0;
  1353. return grub_errno;
  1354. }
  1355. framebuffer.back_target->is_allocated = 1;
  1356. framebuffer.displayed_page = 0;
  1357. framebuffer.render_page = 1;
  1358. framebuffer.update_screen = doublebuf_pageflipping_update_screen;
  1359. framebuffer.pages[0] = page0_ptr;
  1360. framebuffer.pages[1] = page1_ptr;
  1361. framebuffer.current_dirty.first_line
  1362. = framebuffer.back_target->mode_info.height;
  1363. framebuffer.current_dirty.last_line = 0;
  1364. framebuffer.previous_dirty.first_line
  1365. = framebuffer.back_target->mode_info.height;
  1366. framebuffer.previous_dirty.last_line = 0;
  1367. /* Set the framebuffer memory data pointer and display the right page. */
  1368. err = set_page_in (framebuffer.displayed_page);
  1369. if (err)
  1370. {
  1371. grub_video_fb_delete_render_target (framebuffer.back_target);
  1372. return err;
  1373. }
  1374. framebuffer.set_page = set_page_in;
  1375. return GRUB_ERR_NONE;
  1376. }
  1377. /* Select the best double buffering mode available. */
  1378. grub_err_t
  1379. grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
  1380. struct grub_video_mode_info *mode_info,
  1381. volatile void *page0_ptr,
  1382. grub_video_fb_set_page_t set_page_in,
  1383. volatile void *page1_ptr)
  1384. {
  1385. grub_err_t err;
  1386. /* Do double buffering only if it's either requested or efficient. */
  1387. if (set_page_in && grub_video_check_mode_flag (mode_type, mode_mask,
  1388. GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
  1389. 1))
  1390. {
  1391. mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
  1392. mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP;
  1393. err = doublebuf_pageflipping_init (mode_info, page0_ptr,
  1394. set_page_in,
  1395. page1_ptr);
  1396. if (!err)
  1397. {
  1398. framebuffer.render_target = framebuffer.back_target;
  1399. return GRUB_ERR_NONE;
  1400. }
  1401. mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
  1402. | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
  1403. grub_errno = GRUB_ERR_NONE;
  1404. }
  1405. if (grub_video_check_mode_flag (mode_type, mode_mask,
  1406. GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
  1407. 1))
  1408. {
  1409. /* It was much nicer with the cast directly at function call but
  1410. some older gcc versions don't accept it properly.*/
  1411. void *tmp = (void *) page0_ptr;
  1412. mode_info->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
  1413. | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
  1414. err = grub_video_fb_doublebuf_blit_init (&framebuffer.back_target,
  1415. *mode_info,
  1416. tmp);
  1417. if (!err)
  1418. {
  1419. framebuffer.render_target = framebuffer.back_target;
  1420. return GRUB_ERR_NONE;
  1421. }
  1422. mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
  1423. | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
  1424. grub_errno = GRUB_ERR_NONE;
  1425. }
  1426. /* Fall back to no double buffering. */
  1427. err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
  1428. mode_info,
  1429. (void *) page0_ptr);
  1430. if (err)
  1431. return err;
  1432. framebuffer.update_screen = 0;
  1433. framebuffer.pages[0] = page0_ptr;
  1434. framebuffer.displayed_page = 0;
  1435. framebuffer.render_page = 0;
  1436. framebuffer.set_page = 0;
  1437. framebuffer.current_dirty.first_line
  1438. = framebuffer.back_target->mode_info.height;
  1439. framebuffer.current_dirty.last_line = 0;
  1440. mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
  1441. framebuffer.render_target = framebuffer.back_target;
  1442. return GRUB_ERR_NONE;
  1443. }
  1444. grub_err_t
  1445. grub_video_fb_swap_buffers (void)
  1446. {
  1447. grub_err_t err;
  1448. if (!framebuffer.update_screen)
  1449. return GRUB_ERR_NONE;
  1450. err = framebuffer.update_screen ();
  1451. if (err)
  1452. return err;
  1453. return GRUB_ERR_NONE;
  1454. }
  1455. grub_err_t
  1456. grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info,
  1457. void **framebuf)
  1458. {
  1459. grub_memcpy (mode_info, &(framebuffer.back_target->mode_info),
  1460. sizeof (*mode_info));
  1461. /* We are about to load a kernel. Switch back to page zero, since some
  1462. kernel drivers expect that. */
  1463. if (framebuffer.set_page && framebuffer.displayed_page != 0)
  1464. {
  1465. framebuffer.update_screen ();
  1466. }
  1467. *framebuf = (void *) framebuffer.pages[framebuffer.displayed_page];
  1468. grub_video_fb_fini ();
  1469. return GRUB_ERR_NONE;
  1470. }