Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sp_quad_blend.c 32KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. /**************************************************************************
  2. *
  3. * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sub license, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial portions
  16. * of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21. * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
  22. * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. **************************************************************************/
  27. /**
  28. * quad blending
  29. * \author Brian Paul
  30. */
  31. #include "pipe/p_defines.h"
  32. #include "util/u_math.h"
  33. #include "util/u_memory.h"
  34. #include "util/u_format.h"
  35. #include "sp_context.h"
  36. #include "sp_quad.h"
  37. #include "sp_tile_cache.h"
  38. #include "sp_quad_pipe.h"
  39. #define VEC4_COPY(DST, SRC) \
  40. do { \
  41. DST[0] = SRC[0]; \
  42. DST[1] = SRC[1]; \
  43. DST[2] = SRC[2]; \
  44. DST[3] = SRC[3]; \
  45. } while(0)
  46. #define VEC4_SCALAR(DST, SRC) \
  47. do { \
  48. DST[0] = SRC; \
  49. DST[1] = SRC; \
  50. DST[2] = SRC; \
  51. DST[3] = SRC; \
  52. } while(0)
  53. #define VEC4_ADD(R, A, B) \
  54. do { \
  55. R[0] = A[0] + B[0]; \
  56. R[1] = A[1] + B[1]; \
  57. R[2] = A[2] + B[2]; \
  58. R[3] = A[3] + B[3]; \
  59. } while (0)
  60. #define VEC4_SUB(R, A, B) \
  61. do { \
  62. R[0] = A[0] - B[0]; \
  63. R[1] = A[1] - B[1]; \
  64. R[2] = A[2] - B[2]; \
  65. R[3] = A[3] - B[3]; \
  66. } while (0)
  67. /** Add and limit result to ceiling of 1.0 */
  68. #define VEC4_ADD_SAT(R, A, B) \
  69. do { \
  70. R[0] = A[0] + B[0]; if (R[0] > 1.0f) R[0] = 1.0f; \
  71. R[1] = A[1] + B[1]; if (R[1] > 1.0f) R[1] = 1.0f; \
  72. R[2] = A[2] + B[2]; if (R[2] > 1.0f) R[2] = 1.0f; \
  73. R[3] = A[3] + B[3]; if (R[3] > 1.0f) R[3] = 1.0f; \
  74. } while (0)
  75. /** Subtract and limit result to floor of 0.0 */
  76. #define VEC4_SUB_SAT(R, A, B) \
  77. do { \
  78. R[0] = A[0] - B[0]; if (R[0] < 0.0f) R[0] = 0.0f; \
  79. R[1] = A[1] - B[1]; if (R[1] < 0.0f) R[1] = 0.0f; \
  80. R[2] = A[2] - B[2]; if (R[2] < 0.0f) R[2] = 0.0f; \
  81. R[3] = A[3] - B[3]; if (R[3] < 0.0f) R[3] = 0.0f; \
  82. } while (0)
  83. #define VEC4_MUL(R, A, B) \
  84. do { \
  85. R[0] = A[0] * B[0]; \
  86. R[1] = A[1] * B[1]; \
  87. R[2] = A[2] * B[2]; \
  88. R[3] = A[3] * B[3]; \
  89. } while (0)
  90. #define VEC4_MIN(R, A, B) \
  91. do { \
  92. R[0] = (A[0] < B[0]) ? A[0] : B[0]; \
  93. R[1] = (A[1] < B[1]) ? A[1] : B[1]; \
  94. R[2] = (A[2] < B[2]) ? A[2] : B[2]; \
  95. R[3] = (A[3] < B[3]) ? A[3] : B[3]; \
  96. } while (0)
  97. #define VEC4_MAX(R, A, B) \
  98. do { \
  99. R[0] = (A[0] > B[0]) ? A[0] : B[0]; \
  100. R[1] = (A[1] > B[1]) ? A[1] : B[1]; \
  101. R[2] = (A[2] > B[2]) ? A[2] : B[2]; \
  102. R[3] = (A[3] > B[3]) ? A[3] : B[3]; \
  103. } while (0)
  104. static void
  105. logicop_quad(struct quad_stage *qs,
  106. float (*quadColor)[4],
  107. float (*dest)[4])
  108. {
  109. struct softpipe_context *softpipe = qs->softpipe;
  110. ubyte src[4][4], dst[4][4], res[4][4];
  111. uint *src4 = (uint *) src;
  112. uint *dst4 = (uint *) dst;
  113. uint *res4 = (uint *) res;
  114. uint j;
  115. /* convert to ubyte */
  116. for (j = 0; j < 4; j++) { /* loop over R,G,B,A channels */
  117. dst[j][0] = float_to_ubyte(dest[j][0]); /* P0 */
  118. dst[j][1] = float_to_ubyte(dest[j][1]); /* P1 */
  119. dst[j][2] = float_to_ubyte(dest[j][2]); /* P2 */
  120. dst[j][3] = float_to_ubyte(dest[j][3]); /* P3 */
  121. src[j][0] = float_to_ubyte(quadColor[j][0]); /* P0 */
  122. src[j][1] = float_to_ubyte(quadColor[j][1]); /* P1 */
  123. src[j][2] = float_to_ubyte(quadColor[j][2]); /* P2 */
  124. src[j][3] = float_to_ubyte(quadColor[j][3]); /* P3 */
  125. }
  126. switch (softpipe->blend->logicop_func) {
  127. case PIPE_LOGICOP_CLEAR:
  128. for (j = 0; j < 4; j++)
  129. res4[j] = 0;
  130. break;
  131. case PIPE_LOGICOP_NOR:
  132. for (j = 0; j < 4; j++)
  133. res4[j] = ~(src4[j] | dst4[j]);
  134. break;
  135. case PIPE_LOGICOP_AND_INVERTED:
  136. for (j = 0; j < 4; j++)
  137. res4[j] = ~src4[j] & dst4[j];
  138. break;
  139. case PIPE_LOGICOP_COPY_INVERTED:
  140. for (j = 0; j < 4; j++)
  141. res4[j] = ~src4[j];
  142. break;
  143. case PIPE_LOGICOP_AND_REVERSE:
  144. for (j = 0; j < 4; j++)
  145. res4[j] = src4[j] & ~dst4[j];
  146. break;
  147. case PIPE_LOGICOP_INVERT:
  148. for (j = 0; j < 4; j++)
  149. res4[j] = ~dst4[j];
  150. break;
  151. case PIPE_LOGICOP_XOR:
  152. for (j = 0; j < 4; j++)
  153. res4[j] = dst4[j] ^ src4[j];
  154. break;
  155. case PIPE_LOGICOP_NAND:
  156. for (j = 0; j < 4; j++)
  157. res4[j] = ~(src4[j] & dst4[j]);
  158. break;
  159. case PIPE_LOGICOP_AND:
  160. for (j = 0; j < 4; j++)
  161. res4[j] = src4[j] & dst4[j];
  162. break;
  163. case PIPE_LOGICOP_EQUIV:
  164. for (j = 0; j < 4; j++)
  165. res4[j] = ~(src4[j] ^ dst4[j]);
  166. break;
  167. case PIPE_LOGICOP_NOOP:
  168. for (j = 0; j < 4; j++)
  169. res4[j] = dst4[j];
  170. break;
  171. case PIPE_LOGICOP_OR_INVERTED:
  172. for (j = 0; j < 4; j++)
  173. res4[j] = ~src4[j] | dst4[j];
  174. break;
  175. case PIPE_LOGICOP_COPY:
  176. for (j = 0; j < 4; j++)
  177. res4[j] = src4[j];
  178. break;
  179. case PIPE_LOGICOP_OR_REVERSE:
  180. for (j = 0; j < 4; j++)
  181. res4[j] = src4[j] | ~dst4[j];
  182. break;
  183. case PIPE_LOGICOP_OR:
  184. for (j = 0; j < 4; j++)
  185. res4[j] = src4[j] | dst4[j];
  186. break;
  187. case PIPE_LOGICOP_SET:
  188. for (j = 0; j < 4; j++)
  189. res4[j] = ~0;
  190. break;
  191. default:
  192. assert(0 && "invalid logicop mode");
  193. }
  194. for (j = 0; j < 4; j++) {
  195. quadColor[j][0] = ubyte_to_float(res[j][0]);
  196. quadColor[j][1] = ubyte_to_float(res[j][1]);
  197. quadColor[j][2] = ubyte_to_float(res[j][2]);
  198. quadColor[j][3] = ubyte_to_float(res[j][3]);
  199. }
  200. }
  201. static void
  202. blend_quad(struct quad_stage *qs,
  203. float (*quadColor)[4],
  204. float (*dest)[4],
  205. unsigned cbuf,
  206. boolean has_dst_alpha)
  207. {
  208. static const float zero[4] = { 0, 0, 0, 0 };
  209. static const float one[4] = { 1, 1, 1, 1 };
  210. struct softpipe_context *softpipe = qs->softpipe;
  211. float source[4][QUAD_SIZE] = { { 0 } };
  212. /*
  213. * Compute src/first term RGB
  214. */
  215. switch (softpipe->blend->rt[cbuf].rgb_src_factor) {
  216. case PIPE_BLENDFACTOR_ONE:
  217. VEC4_COPY(source[0], quadColor[0]); /* R */
  218. VEC4_COPY(source[1], quadColor[1]); /* G */
  219. VEC4_COPY(source[2], quadColor[2]); /* B */
  220. break;
  221. case PIPE_BLENDFACTOR_SRC_COLOR:
  222. VEC4_MUL(source[0], quadColor[0], quadColor[0]); /* R */
  223. VEC4_MUL(source[1], quadColor[1], quadColor[1]); /* G */
  224. VEC4_MUL(source[2], quadColor[2], quadColor[2]); /* B */
  225. break;
  226. case PIPE_BLENDFACTOR_SRC_ALPHA:
  227. {
  228. const float *alpha = quadColor[3];
  229. VEC4_MUL(source[0], quadColor[0], alpha); /* R */
  230. VEC4_MUL(source[1], quadColor[1], alpha); /* G */
  231. VEC4_MUL(source[2], quadColor[2], alpha); /* B */
  232. }
  233. break;
  234. case PIPE_BLENDFACTOR_DST_COLOR:
  235. VEC4_MUL(source[0], quadColor[0], dest[0]); /* R */
  236. VEC4_MUL(source[1], quadColor[1], dest[1]); /* G */
  237. VEC4_MUL(source[2], quadColor[2], dest[2]); /* B */
  238. break;
  239. case PIPE_BLENDFACTOR_DST_ALPHA:
  240. if (has_dst_alpha) {
  241. const float *alpha = dest[3];
  242. VEC4_MUL(source[0], quadColor[0], alpha); /* R */
  243. VEC4_MUL(source[1], quadColor[1], alpha); /* G */
  244. VEC4_MUL(source[2], quadColor[2], alpha); /* B */
  245. }
  246. else {
  247. VEC4_COPY(source[0], quadColor[0]); /* R */
  248. VEC4_COPY(source[1], quadColor[1]); /* G */
  249. VEC4_COPY(source[2], quadColor[2]); /* B */
  250. }
  251. break;
  252. case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
  253. if (has_dst_alpha) {
  254. const float *alpha = quadColor[3];
  255. float diff[4], temp[4];
  256. VEC4_SUB(diff, one, dest[3]);
  257. VEC4_MIN(temp, alpha, diff);
  258. VEC4_MUL(source[0], quadColor[0], temp); /* R */
  259. VEC4_MUL(source[1], quadColor[1], temp); /* G */
  260. VEC4_MUL(source[2], quadColor[2], temp); /* B */
  261. }
  262. else {
  263. VEC4_COPY(source[0], zero); /* R */
  264. VEC4_COPY(source[1], zero); /* G */
  265. VEC4_COPY(source[2], zero); /* B */
  266. }
  267. break;
  268. case PIPE_BLENDFACTOR_CONST_COLOR:
  269. {
  270. float comp[4];
  271. VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */
  272. VEC4_MUL(source[0], quadColor[0], comp); /* R */
  273. VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */
  274. VEC4_MUL(source[1], quadColor[1], comp); /* G */
  275. VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */
  276. VEC4_MUL(source[2], quadColor[2], comp); /* B */
  277. }
  278. break;
  279. case PIPE_BLENDFACTOR_CONST_ALPHA:
  280. {
  281. float alpha[4];
  282. VEC4_SCALAR(alpha, softpipe->blend_color.color[3]);
  283. VEC4_MUL(source[0], quadColor[0], alpha); /* R */
  284. VEC4_MUL(source[1], quadColor[1], alpha); /* G */
  285. VEC4_MUL(source[2], quadColor[2], alpha); /* B */
  286. }
  287. break;
  288. case PIPE_BLENDFACTOR_SRC1_COLOR:
  289. assert(0); /* to do */
  290. break;
  291. case PIPE_BLENDFACTOR_SRC1_ALPHA:
  292. assert(0); /* to do */
  293. break;
  294. case PIPE_BLENDFACTOR_ZERO:
  295. VEC4_COPY(source[0], zero); /* R */
  296. VEC4_COPY(source[1], zero); /* G */
  297. VEC4_COPY(source[2], zero); /* B */
  298. break;
  299. case PIPE_BLENDFACTOR_INV_SRC_COLOR:
  300. {
  301. float inv_comp[4];
  302. VEC4_SUB(inv_comp, one, quadColor[0]); /* R */
  303. VEC4_MUL(source[0], quadColor[0], inv_comp); /* R */
  304. VEC4_SUB(inv_comp, one, quadColor[1]); /* G */
  305. VEC4_MUL(source[1], quadColor[1], inv_comp); /* G */
  306. VEC4_SUB(inv_comp, one, quadColor[2]); /* B */
  307. VEC4_MUL(source[2], quadColor[2], inv_comp); /* B */
  308. }
  309. break;
  310. case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
  311. {
  312. float inv_alpha[4];
  313. VEC4_SUB(inv_alpha, one, quadColor[3]);
  314. VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */
  315. VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */
  316. VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */
  317. }
  318. break;
  319. case PIPE_BLENDFACTOR_INV_DST_ALPHA:
  320. if (has_dst_alpha) {
  321. float inv_alpha[4];
  322. VEC4_SUB(inv_alpha, one, dest[3]);
  323. VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */
  324. VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */
  325. VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */
  326. }
  327. else {
  328. VEC4_COPY(source[0], zero); /* R */
  329. VEC4_COPY(source[1], zero); /* G */
  330. VEC4_COPY(source[2], zero); /* B */
  331. }
  332. break;
  333. case PIPE_BLENDFACTOR_INV_DST_COLOR:
  334. {
  335. float inv_comp[4];
  336. VEC4_SUB(inv_comp, one, dest[0]); /* R */
  337. VEC4_MUL(source[0], quadColor[0], inv_comp); /* R */
  338. VEC4_SUB(inv_comp, one, dest[1]); /* G */
  339. VEC4_MUL(source[1], quadColor[1], inv_comp); /* G */
  340. VEC4_SUB(inv_comp, one, dest[2]); /* B */
  341. VEC4_MUL(source[2], quadColor[2], inv_comp); /* B */
  342. }
  343. break;
  344. case PIPE_BLENDFACTOR_INV_CONST_COLOR:
  345. {
  346. float inv_comp[4];
  347. /* R */
  348. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]);
  349. VEC4_MUL(source[0], quadColor[0], inv_comp);
  350. /* G */
  351. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]);
  352. VEC4_MUL(source[1], quadColor[1], inv_comp);
  353. /* B */
  354. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]);
  355. VEC4_MUL(source[2], quadColor[2], inv_comp);
  356. }
  357. break;
  358. case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
  359. {
  360. float inv_alpha[4];
  361. VEC4_SCALAR(inv_alpha, 1.0f - softpipe->blend_color.color[3]);
  362. VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */
  363. VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */
  364. VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */
  365. }
  366. break;
  367. case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
  368. assert(0); /* to do */
  369. break;
  370. case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
  371. assert(0); /* to do */
  372. break;
  373. default:
  374. assert(0 && "invalid rgb src factor");
  375. }
  376. /*
  377. * Compute src/first term A
  378. */
  379. switch (softpipe->blend->rt[cbuf].alpha_src_factor) {
  380. case PIPE_BLENDFACTOR_ONE:
  381. VEC4_COPY(source[3], quadColor[3]); /* A */
  382. break;
  383. case PIPE_BLENDFACTOR_SRC_COLOR:
  384. /* fall-through */
  385. case PIPE_BLENDFACTOR_SRC_ALPHA:
  386. {
  387. const float *alpha = quadColor[3];
  388. VEC4_MUL(source[3], quadColor[3], alpha); /* A */
  389. }
  390. break;
  391. case PIPE_BLENDFACTOR_DST_COLOR:
  392. /* fall-through */
  393. case PIPE_BLENDFACTOR_DST_ALPHA:
  394. if (has_dst_alpha)
  395. VEC4_MUL(source[3], quadColor[3], dest[3]); /* A */
  396. else
  397. VEC4_COPY(source[3], quadColor[3]); /* A */
  398. break;
  399. case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
  400. /* multiply alpha by 1.0 */
  401. VEC4_COPY(source[3], quadColor[3]); /* A */
  402. break;
  403. case PIPE_BLENDFACTOR_CONST_COLOR:
  404. /* fall-through */
  405. case PIPE_BLENDFACTOR_CONST_ALPHA:
  406. {
  407. float comp[4];
  408. VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */
  409. VEC4_MUL(source[3], quadColor[3], comp); /* A */
  410. }
  411. break;
  412. case PIPE_BLENDFACTOR_ZERO:
  413. VEC4_COPY(source[3], zero); /* A */
  414. break;
  415. case PIPE_BLENDFACTOR_INV_SRC_COLOR:
  416. /* fall-through */
  417. case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
  418. {
  419. float inv_alpha[4];
  420. VEC4_SUB(inv_alpha, one, quadColor[3]);
  421. VEC4_MUL(source[3], quadColor[3], inv_alpha); /* A */
  422. }
  423. break;
  424. case PIPE_BLENDFACTOR_INV_DST_COLOR:
  425. /* fall-through */
  426. case PIPE_BLENDFACTOR_INV_DST_ALPHA:
  427. if (has_dst_alpha) {
  428. float inv_alpha[4];
  429. VEC4_SUB(inv_alpha, one, dest[3]);
  430. VEC4_MUL(source[3], quadColor[3], inv_alpha); /* A */
  431. }
  432. else {
  433. VEC4_COPY(source[3], zero); /* A */
  434. }
  435. break;
  436. case PIPE_BLENDFACTOR_INV_CONST_COLOR:
  437. /* fall-through */
  438. case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
  439. {
  440. float inv_comp[4];
  441. /* A */
  442. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]);
  443. VEC4_MUL(source[3], quadColor[3], inv_comp);
  444. }
  445. break;
  446. default:
  447. assert(0 && "invalid alpha src factor");
  448. }
  449. /*
  450. * Compute dest/second term RGB
  451. */
  452. switch (softpipe->blend->rt[cbuf].rgb_dst_factor) {
  453. case PIPE_BLENDFACTOR_ONE:
  454. /* dest = dest * 1 NO-OP, leave dest as-is */
  455. break;
  456. case PIPE_BLENDFACTOR_SRC_COLOR:
  457. VEC4_MUL(dest[0], dest[0], quadColor[0]); /* R */
  458. VEC4_MUL(dest[1], dest[1], quadColor[1]); /* G */
  459. VEC4_MUL(dest[2], dest[2], quadColor[2]); /* B */
  460. break;
  461. case PIPE_BLENDFACTOR_SRC_ALPHA:
  462. VEC4_MUL(dest[0], dest[0], quadColor[3]); /* R * A */
  463. VEC4_MUL(dest[1], dest[1], quadColor[3]); /* G * A */
  464. VEC4_MUL(dest[2], dest[2], quadColor[3]); /* B * A */
  465. break;
  466. case PIPE_BLENDFACTOR_DST_ALPHA:
  467. if (has_dst_alpha) {
  468. VEC4_MUL(dest[0], dest[0], dest[3]); /* R * A */
  469. VEC4_MUL(dest[1], dest[1], dest[3]); /* G * A */
  470. VEC4_MUL(dest[2], dest[2], dest[3]); /* B * A */
  471. }
  472. else {
  473. /* dest = dest * 1 NO-OP, leave dest as-is */
  474. }
  475. break;
  476. case PIPE_BLENDFACTOR_DST_COLOR:
  477. VEC4_MUL(dest[0], dest[0], dest[0]); /* R */
  478. VEC4_MUL(dest[1], dest[1], dest[1]); /* G */
  479. VEC4_MUL(dest[2], dest[2], dest[2]); /* B */
  480. break;
  481. case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
  482. if (has_dst_alpha) {
  483. const float *alpha = quadColor[3];
  484. float diff[4], temp[4];
  485. VEC4_SUB(diff, one, dest[3]);
  486. VEC4_MIN(temp, alpha, diff);
  487. VEC4_MUL(dest[0], quadColor[0], temp); /* R */
  488. VEC4_MUL(dest[1], quadColor[1], temp); /* G */
  489. VEC4_MUL(dest[2], quadColor[2], temp); /* B */
  490. }
  491. else {
  492. VEC4_COPY(dest[0], zero); /* R */
  493. VEC4_COPY(dest[1], zero); /* G */
  494. VEC4_COPY(dest[2], zero); /* B */
  495. }
  496. break;
  497. case PIPE_BLENDFACTOR_CONST_COLOR:
  498. {
  499. float comp[4];
  500. VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */
  501. VEC4_MUL(dest[0], dest[0], comp); /* R */
  502. VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */
  503. VEC4_MUL(dest[1], dest[1], comp); /* G */
  504. VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */
  505. VEC4_MUL(dest[2], dest[2], comp); /* B */
  506. }
  507. break;
  508. case PIPE_BLENDFACTOR_CONST_ALPHA:
  509. {
  510. float comp[4];
  511. VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */
  512. VEC4_MUL(dest[0], dest[0], comp); /* R */
  513. VEC4_MUL(dest[1], dest[1], comp); /* G */
  514. VEC4_MUL(dest[2], dest[2], comp); /* B */
  515. }
  516. break;
  517. case PIPE_BLENDFACTOR_ZERO:
  518. VEC4_COPY(dest[0], zero); /* R */
  519. VEC4_COPY(dest[1], zero); /* G */
  520. VEC4_COPY(dest[2], zero); /* B */
  521. break;
  522. case PIPE_BLENDFACTOR_SRC1_COLOR:
  523. case PIPE_BLENDFACTOR_SRC1_ALPHA:
  524. /* XXX what are these? */
  525. assert(0);
  526. break;
  527. case PIPE_BLENDFACTOR_INV_SRC_COLOR:
  528. {
  529. float inv_comp[4];
  530. VEC4_SUB(inv_comp, one, quadColor[0]); /* R */
  531. VEC4_MUL(dest[0], inv_comp, dest[0]); /* R */
  532. VEC4_SUB(inv_comp, one, quadColor[1]); /* G */
  533. VEC4_MUL(dest[1], inv_comp, dest[1]); /* G */
  534. VEC4_SUB(inv_comp, one, quadColor[2]); /* B */
  535. VEC4_MUL(dest[2], inv_comp, dest[2]); /* B */
  536. }
  537. break;
  538. case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
  539. {
  540. float one_minus_alpha[QUAD_SIZE];
  541. VEC4_SUB(one_minus_alpha, one, quadColor[3]);
  542. VEC4_MUL(dest[0], dest[0], one_minus_alpha); /* R */
  543. VEC4_MUL(dest[1], dest[1], one_minus_alpha); /* G */
  544. VEC4_MUL(dest[2], dest[2], one_minus_alpha); /* B */
  545. }
  546. break;
  547. case PIPE_BLENDFACTOR_INV_DST_ALPHA:
  548. if (has_dst_alpha) {
  549. float inv_comp[4];
  550. VEC4_SUB(inv_comp, one, dest[3]); /* A */
  551. VEC4_MUL(dest[0], inv_comp, dest[0]); /* R */
  552. VEC4_MUL(dest[1], inv_comp, dest[1]); /* G */
  553. VEC4_MUL(dest[2], inv_comp, dest[2]); /* B */
  554. }
  555. else {
  556. VEC4_COPY(dest[0], zero); /* R */
  557. VEC4_COPY(dest[1], zero); /* G */
  558. VEC4_COPY(dest[2], zero); /* B */
  559. }
  560. break;
  561. case PIPE_BLENDFACTOR_INV_DST_COLOR:
  562. {
  563. float inv_comp[4];
  564. VEC4_SUB(inv_comp, one, dest[0]); /* R */
  565. VEC4_MUL(dest[0], dest[0], inv_comp); /* R */
  566. VEC4_SUB(inv_comp, one, dest[1]); /* G */
  567. VEC4_MUL(dest[1], dest[1], inv_comp); /* G */
  568. VEC4_SUB(inv_comp, one, dest[2]); /* B */
  569. VEC4_MUL(dest[2], dest[2], inv_comp); /* B */
  570. }
  571. break;
  572. case PIPE_BLENDFACTOR_INV_CONST_COLOR:
  573. {
  574. float inv_comp[4];
  575. /* R */
  576. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]);
  577. VEC4_MUL(dest[0], dest[0], inv_comp);
  578. /* G */
  579. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]);
  580. VEC4_MUL(dest[1], dest[1], inv_comp);
  581. /* B */
  582. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]);
  583. VEC4_MUL(dest[2], dest[2], inv_comp);
  584. }
  585. break;
  586. case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
  587. {
  588. float inv_comp[4];
  589. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]);
  590. VEC4_MUL(dest[0], dest[0], inv_comp);
  591. VEC4_MUL(dest[1], dest[1], inv_comp);
  592. VEC4_MUL(dest[2], dest[2], inv_comp);
  593. }
  594. break;
  595. case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
  596. case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
  597. /* XXX what are these? */
  598. assert(0);
  599. break;
  600. default:
  601. assert(0 && "invalid rgb dst factor");
  602. }
  603. /*
  604. * Compute dest/second term A
  605. */
  606. switch (softpipe->blend->rt[cbuf].alpha_dst_factor) {
  607. case PIPE_BLENDFACTOR_ONE:
  608. /* dest = dest * 1 NO-OP, leave dest as-is */
  609. break;
  610. case PIPE_BLENDFACTOR_SRC_COLOR:
  611. /* fall-through */
  612. case PIPE_BLENDFACTOR_SRC_ALPHA:
  613. VEC4_MUL(dest[3], dest[3], quadColor[3]); /* A * A */
  614. break;
  615. case PIPE_BLENDFACTOR_DST_COLOR:
  616. /* fall-through */
  617. case PIPE_BLENDFACTOR_DST_ALPHA:
  618. if (has_dst_alpha) {
  619. VEC4_MUL(dest[3], dest[3], dest[3]); /* A */
  620. }
  621. else {
  622. /* dest = dest * 1 NO-OP, leave dest as-is */
  623. }
  624. break;
  625. case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
  626. /* dest = dest * 1 NO-OP, leave dest as-is */
  627. break;
  628. case PIPE_BLENDFACTOR_CONST_COLOR:
  629. /* fall-through */
  630. case PIPE_BLENDFACTOR_CONST_ALPHA:
  631. {
  632. float comp[4];
  633. VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */
  634. VEC4_MUL(dest[3], dest[3], comp); /* A */
  635. }
  636. break;
  637. case PIPE_BLENDFACTOR_ZERO:
  638. VEC4_COPY(dest[3], zero); /* A */
  639. break;
  640. case PIPE_BLENDFACTOR_INV_SRC_COLOR:
  641. /* fall-through */
  642. case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
  643. {
  644. float one_minus_alpha[QUAD_SIZE];
  645. VEC4_SUB(one_minus_alpha, one, quadColor[3]);
  646. VEC4_MUL(dest[3], dest[3], one_minus_alpha); /* A */
  647. }
  648. break;
  649. case PIPE_BLENDFACTOR_INV_DST_COLOR:
  650. /* fall-through */
  651. case PIPE_BLENDFACTOR_INV_DST_ALPHA:
  652. if (has_dst_alpha) {
  653. float inv_comp[4];
  654. VEC4_SUB(inv_comp, one, dest[3]); /* A */
  655. VEC4_MUL(dest[3], inv_comp, dest[3]); /* A */
  656. }
  657. else {
  658. VEC4_COPY(dest[3], zero); /* A */
  659. }
  660. break;
  661. case PIPE_BLENDFACTOR_INV_CONST_COLOR:
  662. /* fall-through */
  663. case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
  664. {
  665. float inv_comp[4];
  666. VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]);
  667. VEC4_MUL(dest[3], dest[3], inv_comp);
  668. }
  669. break;
  670. default:
  671. assert(0 && "invalid alpha dst factor");
  672. }
  673. /*
  674. * Combine RGB terms
  675. */
  676. switch (softpipe->blend->rt[cbuf].rgb_func) {
  677. case PIPE_BLEND_ADD:
  678. VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */
  679. VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */
  680. VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */
  681. break;
  682. case PIPE_BLEND_SUBTRACT:
  683. VEC4_SUB_SAT(quadColor[0], source[0], dest[0]); /* R */
  684. VEC4_SUB_SAT(quadColor[1], source[1], dest[1]); /* G */
  685. VEC4_SUB_SAT(quadColor[2], source[2], dest[2]); /* B */
  686. break;
  687. case PIPE_BLEND_REVERSE_SUBTRACT:
  688. VEC4_SUB_SAT(quadColor[0], dest[0], source[0]); /* R */
  689. VEC4_SUB_SAT(quadColor[1], dest[1], source[1]); /* G */
  690. VEC4_SUB_SAT(quadColor[2], dest[2], source[2]); /* B */
  691. break;
  692. case PIPE_BLEND_MIN:
  693. VEC4_MIN(quadColor[0], source[0], dest[0]); /* R */
  694. VEC4_MIN(quadColor[1], source[1], dest[1]); /* G */
  695. VEC4_MIN(quadColor[2], source[2], dest[2]); /* B */
  696. break;
  697. case PIPE_BLEND_MAX:
  698. VEC4_MAX(quadColor[0], source[0], dest[0]); /* R */
  699. VEC4_MAX(quadColor[1], source[1], dest[1]); /* G */
  700. VEC4_MAX(quadColor[2], source[2], dest[2]); /* B */
  701. break;
  702. default:
  703. assert(0 && "invalid rgb blend func");
  704. }
  705. /*
  706. * Combine A terms
  707. */
  708. switch (softpipe->blend->rt[cbuf].alpha_func) {
  709. case PIPE_BLEND_ADD:
  710. VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */
  711. break;
  712. case PIPE_BLEND_SUBTRACT:
  713. VEC4_SUB_SAT(quadColor[3], source[3], dest[3]); /* A */
  714. break;
  715. case PIPE_BLEND_REVERSE_SUBTRACT:
  716. VEC4_SUB_SAT(quadColor[3], dest[3], source[3]); /* A */
  717. break;
  718. case PIPE_BLEND_MIN:
  719. VEC4_MIN(quadColor[3], source[3], dest[3]); /* A */
  720. break;
  721. case PIPE_BLEND_MAX:
  722. VEC4_MAX(quadColor[3], source[3], dest[3]); /* A */
  723. break;
  724. default:
  725. assert(0 && "invalid alpha blend func");
  726. }
  727. }
  728. static void
  729. colormask_quad(unsigned colormask,
  730. float (*quadColor)[4],
  731. float (*dest)[4])
  732. {
  733. /* R */
  734. if (!(colormask & PIPE_MASK_R))
  735. COPY_4V(quadColor[0], dest[0]);
  736. /* G */
  737. if (!(colormask & PIPE_MASK_G))
  738. COPY_4V(quadColor[1], dest[1]);
  739. /* B */
  740. if (!(colormask & PIPE_MASK_B))
  741. COPY_4V(quadColor[2], dest[2]);
  742. /* A */
  743. if (!(colormask & PIPE_MASK_A))
  744. COPY_4V(quadColor[3], dest[3]);
  745. }
  746. static void
  747. blend_fallback(struct quad_stage *qs,
  748. struct quad_header *quads[],
  749. unsigned nr)
  750. {
  751. struct softpipe_context *softpipe = qs->softpipe;
  752. const struct pipe_blend_state *blend = softpipe->blend;
  753. unsigned cbuf;
  754. for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++)
  755. {
  756. /* which blend/mask state index to use: */
  757. const uint blend_buf = blend->independent_blend_enable ? cbuf : 0;
  758. float dest[4][QUAD_SIZE];
  759. struct softpipe_cached_tile *tile
  760. = sp_get_cached_tile(softpipe->cbuf_cache[cbuf],
  761. quads[0]->input.x0,
  762. quads[0]->input.y0);
  763. boolean has_dst_alpha
  764. = util_format_has_alpha(softpipe->framebuffer.cbufs[cbuf]->format);
  765. uint q, i, j;
  766. for (q = 0; q < nr; q++) {
  767. struct quad_header *quad = quads[q];
  768. float (*quadColor)[4] = quad->output.color[cbuf];
  769. const int itx = (quad->input.x0 & (TILE_SIZE-1));
  770. const int ity = (quad->input.y0 & (TILE_SIZE-1));
  771. /* get/swizzle dest colors
  772. */
  773. for (j = 0; j < QUAD_SIZE; j++) {
  774. int x = itx + (j & 1);
  775. int y = ity + (j >> 1);
  776. for (i = 0; i < 4; i++) {
  777. dest[i][j] = tile->data.color[y][x][i];
  778. }
  779. }
  780. if (blend->logicop_enable) {
  781. logicop_quad( qs, quadColor, dest );
  782. }
  783. else if (blend->rt[blend_buf].blend_enable) {
  784. blend_quad( qs, quadColor, dest, cbuf, has_dst_alpha );
  785. }
  786. if (blend->rt[blend_buf].colormask != 0xf)
  787. colormask_quad( blend->rt[cbuf].colormask, quadColor, dest);
  788. /* Output color values
  789. */
  790. for (j = 0; j < QUAD_SIZE; j++) {
  791. if (quad->inout.mask & (1 << j)) {
  792. int x = itx + (j & 1);
  793. int y = ity + (j >> 1);
  794. for (i = 0; i < 4; i++) { /* loop over color chans */
  795. tile->data.color[y][x][i] = quadColor[i][j];
  796. }
  797. }
  798. }
  799. }
  800. }
  801. }
  802. static void
  803. blend_single_add_src_alpha_inv_src_alpha(struct quad_stage *qs,
  804. struct quad_header *quads[],
  805. unsigned nr)
  806. {
  807. static const float one[4] = { 1, 1, 1, 1 };
  808. float one_minus_alpha[QUAD_SIZE];
  809. float dest[4][QUAD_SIZE];
  810. float source[4][QUAD_SIZE];
  811. uint i, j, q;
  812. struct softpipe_cached_tile *tile
  813. = sp_get_cached_tile(qs->softpipe->cbuf_cache[0],
  814. quads[0]->input.x0,
  815. quads[0]->input.y0);
  816. for (q = 0; q < nr; q++) {
  817. struct quad_header *quad = quads[q];
  818. float (*quadColor)[4] = quad->output.color[0];
  819. const float *alpha = quadColor[3];
  820. const int itx = (quad->input.x0 & (TILE_SIZE-1));
  821. const int ity = (quad->input.y0 & (TILE_SIZE-1));
  822. /* get/swizzle dest colors */
  823. for (j = 0; j < QUAD_SIZE; j++) {
  824. int x = itx + (j & 1);
  825. int y = ity + (j >> 1);
  826. for (i = 0; i < 4; i++) {
  827. dest[i][j] = tile->data.color[y][x][i];
  828. }
  829. }
  830. VEC4_MUL(source[0], quadColor[0], alpha); /* R */
  831. VEC4_MUL(source[1], quadColor[1], alpha); /* G */
  832. VEC4_MUL(source[2], quadColor[2], alpha); /* B */
  833. VEC4_MUL(source[3], quadColor[3], alpha); /* A */
  834. VEC4_SUB(one_minus_alpha, one, alpha);
  835. VEC4_MUL(dest[0], dest[0], one_minus_alpha); /* R */
  836. VEC4_MUL(dest[1], dest[1], one_minus_alpha); /* G */
  837. VEC4_MUL(dest[2], dest[2], one_minus_alpha); /* B */
  838. VEC4_MUL(dest[3], dest[3], one_minus_alpha); /* B */
  839. VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */
  840. VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */
  841. VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */
  842. VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */
  843. for (j = 0; j < QUAD_SIZE; j++) {
  844. if (quad->inout.mask & (1 << j)) {
  845. int x = itx + (j & 1);
  846. int y = ity + (j >> 1);
  847. for (i = 0; i < 4; i++) { /* loop over color chans */
  848. tile->data.color[y][x][i] = quadColor[i][j];
  849. }
  850. }
  851. }
  852. }
  853. }
  854. static void
  855. blend_single_add_one_one(struct quad_stage *qs,
  856. struct quad_header *quads[],
  857. unsigned nr)
  858. {
  859. float dest[4][QUAD_SIZE];
  860. uint i, j, q;
  861. struct softpipe_cached_tile *tile
  862. = sp_get_cached_tile(qs->softpipe->cbuf_cache[0],
  863. quads[0]->input.x0,
  864. quads[0]->input.y0);
  865. for (q = 0; q < nr; q++) {
  866. struct quad_header *quad = quads[q];
  867. float (*quadColor)[4] = quad->output.color[0];
  868. const int itx = (quad->input.x0 & (TILE_SIZE-1));
  869. const int ity = (quad->input.y0 & (TILE_SIZE-1));
  870. /* get/swizzle dest colors */
  871. for (j = 0; j < QUAD_SIZE; j++) {
  872. int x = itx + (j & 1);
  873. int y = ity + (j >> 1);
  874. for (i = 0; i < 4; i++) {
  875. dest[i][j] = tile->data.color[y][x][i];
  876. }
  877. }
  878. VEC4_ADD_SAT(quadColor[0], quadColor[0], dest[0]); /* R */
  879. VEC4_ADD_SAT(quadColor[1], quadColor[1], dest[1]); /* G */
  880. VEC4_ADD_SAT(quadColor[2], quadColor[2], dest[2]); /* B */
  881. VEC4_ADD_SAT(quadColor[3], quadColor[3], dest[3]); /* A */
  882. for (j = 0; j < QUAD_SIZE; j++) {
  883. if (quad->inout.mask & (1 << j)) {
  884. int x = itx + (j & 1);
  885. int y = ity + (j >> 1);
  886. for (i = 0; i < 4; i++) { /* loop over color chans */
  887. tile->data.color[y][x][i] = quadColor[i][j];
  888. }
  889. }
  890. }
  891. }
  892. }
  893. static void
  894. single_output_color(struct quad_stage *qs,
  895. struct quad_header *quads[],
  896. unsigned nr)
  897. {
  898. uint i, j, q;
  899. struct softpipe_cached_tile *tile
  900. = sp_get_cached_tile(qs->softpipe->cbuf_cache[0],
  901. quads[0]->input.x0,
  902. quads[0]->input.y0);
  903. for (q = 0; q < nr; q++) {
  904. struct quad_header *quad = quads[q];
  905. float (*quadColor)[4] = quad->output.color[0];
  906. const int itx = (quad->input.x0 & (TILE_SIZE-1));
  907. const int ity = (quad->input.y0 & (TILE_SIZE-1));
  908. for (j = 0; j < QUAD_SIZE; j++) {
  909. if (quad->inout.mask & (1 << j)) {
  910. int x = itx + (j & 1);
  911. int y = ity + (j >> 1);
  912. for (i = 0; i < 4; i++) { /* loop over color chans */
  913. tile->data.color[y][x][i] = quadColor[i][j];
  914. }
  915. }
  916. }
  917. }
  918. }
  919. static void
  920. blend_noop(struct quad_stage *qs,
  921. struct quad_header *quads[],
  922. unsigned nr)
  923. {
  924. }
  925. static void
  926. choose_blend_quad(struct quad_stage *qs,
  927. struct quad_header *quads[],
  928. unsigned nr)
  929. {
  930. struct softpipe_context *softpipe = qs->softpipe;
  931. const struct pipe_blend_state *blend = softpipe->blend;
  932. qs->run = blend_fallback;
  933. if (softpipe->framebuffer.nr_cbufs == 0) {
  934. qs->run = blend_noop;
  935. }
  936. else if (!softpipe->blend->logicop_enable &&
  937. softpipe->blend->rt[0].colormask == 0xf &&
  938. softpipe->framebuffer.nr_cbufs == 1)
  939. {
  940. if (!blend->rt[0].blend_enable) {
  941. qs->run = single_output_color;
  942. }
  943. else if (blend->rt[0].rgb_src_factor == blend->rt[0].alpha_src_factor &&
  944. blend->rt[0].rgb_dst_factor == blend->rt[0].alpha_dst_factor &&
  945. blend->rt[0].rgb_func == blend->rt[0].alpha_func)
  946. {
  947. if (blend->rt[0].alpha_func == PIPE_BLEND_ADD) {
  948. if (blend->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
  949. blend->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_ONE) {
  950. qs->run = blend_single_add_one_one;
  951. }
  952. else if (blend->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_SRC_ALPHA &&
  953. blend->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA)
  954. qs->run = blend_single_add_src_alpha_inv_src_alpha;
  955. }
  956. }
  957. }
  958. qs->run(qs, quads, nr);
  959. }
  960. static void blend_begin(struct quad_stage *qs)
  961. {
  962. qs->run = choose_blend_quad;
  963. }
  964. static void blend_destroy(struct quad_stage *qs)
  965. {
  966. FREE( qs );
  967. }
  968. struct quad_stage *sp_quad_blend_stage( struct softpipe_context *softpipe )
  969. {
  970. struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
  971. stage->softpipe = softpipe;
  972. stage->begin = blend_begin;
  973. stage->run = choose_blend_quad;
  974. stage->destroy = blend_destroy;
  975. return stage;
  976. }