Skip to content

Commit b8ec0c2

Browse files
committed
Split blit/non-blit ops into separate comp. units
1 parent 2aec439 commit b8ec0c2

File tree

7 files changed

+320
-241
lines changed

7 files changed

+320
-241
lines changed

kos/src/apps/showpic/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ do_showpic(struct screen_buffer *screen,
348348
// video_gfx_lrot90(&flipgfx);
349349
video_gfx_setblend(&flipgfx, GFX_BLENDMODE_ALPHA_OVERRIDE(200));
350350
video_gfx_stretch3(&screen_gfx, blit_x, blit_y,
351-
&flipgfx, 0, 0,
351+
&flipgfx, 100, 100,
352352
blit_w, blit_h,
353353
&image_gfx, 0, 0,
354354
video_gfx_getclipw(&image_gfx),
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
/*[[[magic
2+
local gcc_opt = options.setdefault("GCC.options", []);
3+
gcc_opt.removeif(x -> x.startswith("-O"));
4+
gcc_opt.append("-O3"); // Force _all_ optimizations because stuff in here is performance-critical
5+
]]]*/
6+
/* Copyright (c) 2019-2025 Griefer@Work *
7+
* *
8+
* This software is provided 'as-is', without any express or implied *
9+
* warranty. In no event will the authors be held liable for any damages *
10+
* arising from the use of this software. *
11+
* *
12+
* Permission is granted to anyone to use this software for any purpose, *
13+
* including commercial applications, and to alter it and redistribute it *
14+
* freely, subject to the following restrictions: *
15+
* *
16+
* 1. The origin of this software must not be misrepresented; you must not *
17+
* claim that you wrote the original software. If you use this software *
18+
* in a product, an acknowledgement (see the following) in the product *
19+
* documentation is required: *
20+
* Portions Copyright (c) 2019-2025 Griefer@Work *
21+
* 2. Altered source versions must be plainly marked as such, and must not be *
22+
* misrepresented as being the original software. *
23+
* 3. This notice may not be removed or altered from any source distribution. *
24+
*/
25+
#ifndef GUARD_LIBVIDEO_GFX_SWGFX_HL_BLIT_C
26+
#define GUARD_LIBVIDEO_GFX_SWGFX_HL_BLIT_C 1
27+
#define _KOS_SOURCE 1
28+
29+
/************************************************************************/
30+
/* HIGH-LEVEL, GENERIC SW-GFX OPERATOR IMPLS */
31+
/************************************************************************/
32+
33+
#include "api.h"
34+
/**/
35+
36+
#include <hybrid/compiler.h>
37+
38+
#include <assert.h>
39+
40+
#include <libvideo/gfx/gfx.h>
41+
42+
#include "gfx-empty.h"
43+
#include "gfx-utils.h"
44+
#include "swgfx.h"
45+
46+
DECL_BEGIN
47+
48+
static_assert(sizeof(struct blt_swdrv) <= (_VIDEO_BLITTER_N_DRIVER * sizeof(void (*)(void))),
49+
"sizeof(struct blt_swdrv) too large for '_VIDEO_BLITTER_N_DRIVER'");
50+
51+
/************************************************************************/
52+
/* BLITTER INITIALIZATION */
53+
/************************************************************************/
54+
55+
LOCAL ATTR_PURE WUNUSED ATTR_IN(1) ATTR_IN(2) bool FCC
56+
noblend_blit_compatible(struct video_codec const *dst,
57+
struct video_codec const *src) {
58+
if (dst == src)
59+
return true;
60+
61+
/* Certain codecs can still be blit onto each other without color conversion.
62+
* This is possible whenever all color channels present in "dst" are also
63+
* present at the same positions in "src".
64+
*
65+
* This is usually the case when "dst" lacks an alpha-channel and instead
66+
* features some unused padding in its place. */
67+
#ifndef __OPTIMIZE_SIZE__
68+
switch (dst->vc_codec) {
69+
case VIDEO_CODEC_RGBX8888:
70+
return src->vc_codec == VIDEO_CODEC_RGBA8888;
71+
case VIDEO_CODEC_XRGB8888:
72+
return src->vc_codec == VIDEO_CODEC_ARGB8888;
73+
case VIDEO_CODEC_XBGR8888:
74+
return src->vc_codec == VIDEO_CODEC_ABGR8888;
75+
case VIDEO_CODEC_BGRX8888:
76+
return src->vc_codec == VIDEO_CODEC_BGRA8888;
77+
case VIDEO_CODEC_RGBX4444:
78+
return src->vc_codec == VIDEO_CODEC_RGBA4444;
79+
case VIDEO_CODEC_XRGB4444:
80+
return src->vc_codec == VIDEO_CODEC_ARGB4444;
81+
case VIDEO_CODEC_XBGR4444:
82+
return src->vc_codec == VIDEO_CODEC_ABGR4444;
83+
case VIDEO_CODEC_BGRX4444:
84+
return src->vc_codec == VIDEO_CODEC_BGRA4444;
85+
case VIDEO_CODEC_RGBX5551:
86+
return src->vc_codec == VIDEO_CODEC_RGBA5551;
87+
case VIDEO_CODEC_XRGB1555:
88+
return src->vc_codec == VIDEO_CODEC_ARGB1555;
89+
case VIDEO_CODEC_XBGR1555:
90+
return src->vc_codec == VIDEO_CODEC_ABGR1555;
91+
case VIDEO_CODEC_BGRX5551:
92+
return src->vc_codec == VIDEO_CODEC_BGRA5551;
93+
default:
94+
break;
95+
}
96+
#endif /* !__OPTIMIZE_SIZE__ */
97+
if ((dst->vc_specs.vcs_flags & (VIDEO_CODEC_FLAG_PAL | VIDEO_CODEC_FLAG_LUM)) ==
98+
(src->vc_specs.vcs_flags & (VIDEO_CODEC_FLAG_PAL | VIDEO_CODEC_FLAG_LUM))) {
99+
if ((dst->vc_specs.vcs_rmask == 0 || dst->vc_specs.vcs_rmask == src->vc_specs.vcs_rmask) &&
100+
(dst->vc_specs.vcs_gmask == 0 || dst->vc_specs.vcs_gmask == src->vc_specs.vcs_gmask) &&
101+
(dst->vc_specs.vcs_bmask == 0 || dst->vc_specs.vcs_bmask == src->vc_specs.vcs_bmask) &&
102+
(dst->vc_specs.vcs_amask == 0 || dst->vc_specs.vcs_amask == src->vc_specs.vcs_amask))
103+
return true;
104+
}
105+
return false;
106+
}
107+
108+
INTERN ATTR_RETNONNULL ATTR_INOUT(1) struct video_blitter *FCC
109+
libvideo_swgfx_blitfrom(struct video_blitter *__restrict ctx) {
110+
struct video_gfx const *src_gfx = ctx->vbt_src;
111+
struct video_gfx const *dst_gfx = ctx->vbt_dst;
112+
struct video_buffer const *src_buffer = src_gfx->vx_buffer;
113+
struct video_buffer const *dst_buffer = dst_gfx->vx_buffer;
114+
struct blt_swdrv *drv = video_swblitter_getdrv(ctx);
115+
video_swblitter_setops(ctx);
116+
117+
/* Check for special case: source and target buffers are the same */
118+
if (video_gfx_getclipw(src_gfx) == 0 || video_gfx_getcliph(src_gfx) == 0) {
119+
ctx->vbt_ops = &libvideo_emptyblitter_ops;
120+
} else if (src_buffer == dst_buffer) {
121+
if (src_gfx->vx_flags & VIDEO_GFX_F_LINEAR) {
122+
drv->bsw_stretch = &libvideo_swblitter_samebuf__stretch_l;
123+
drv->bsw_stretch_imatrix = &libvideo_swblitter_samebuf__stretch_imatrix_l;
124+
} else {
125+
drv->bsw_stretch = &libvideo_swblitter_samebuf__stretch_n;
126+
drv->bsw_stretch_imatrix = &libvideo_swblitter_samebuf__stretch_imatrix_n;
127+
}
128+
if ((src_gfx->vx_flags & VIDEO_GFX_F_BLUR) == 0 &&
129+
VIDEO_COLOR_ISTRANSPARENT(src_gfx->vx_colorkey) &&
130+
GFX_BLENDMODE_GET_MODE(dst_gfx->vx_blend) == GFX_BLENDMODE_OVERRIDE) {
131+
drv->bsw_blit = &libvideo_swblitter_noblend_samebuf__blit;
132+
drv->bsw_blit_imatrix = &libvideo_swblitter_noblend_samebuf__blit_imatrix;
133+
} else {
134+
/* Need to use different impls here that essentially do a "memmove"-style blit,
135+
* rather than the usual "memcpy"-style one (since in this case, writing new
136+
* pixels in an incorrect order might clobber other pixels that have yet to
137+
* be read) */
138+
drv->bsw_blit = &libvideo_swblitter_samebuf__blit;
139+
drv->bsw_blit_imatrix = &libvideo_swblitter_samebuf__blit_imatrix;
140+
}
141+
} else if (GFX_BLENDMODE_GET_MODE(dst_gfx->vx_blend) == GFX_BLENDMODE_OVERRIDE) {
142+
if ((src_gfx->vx_flags & VIDEO_GFX_F_BLUR) != 0)
143+
goto set_generic_operators;
144+
if (!VIDEO_COLOR_ISTRANSPARENT(src_gfx->vx_colorkey))
145+
goto set_generic_operators;
146+
if (noblend_blit_compatible(dst_buffer->vb_format.vf_codec,
147+
src_buffer->vb_format.vf_codec) &&
148+
src_buffer->vb_format.vf_pal == dst_buffer->vb_format.vf_pal) {
149+
/* Special optimization when not doing any blending, and both GFX contexts
150+
* share the same codec: in this case, we can try to directly copy pixel
151+
* data, either through video locks, or by directly reading/writing pixels */
152+
drv->bsw_blit = &libvideo_swblitter_noblend_samefmt__blit;
153+
drv->bsw_blit_imatrix = &libvideo_swblitter_noblend_samefmt__blit_imatrix;
154+
if (src_gfx->vx_flags & VIDEO_GFX_F_LINEAR) {
155+
drv->bsw_stretch = &libvideo_swblitter_noblend_samefmt__stretch_l;
156+
drv->bsw_stretch_imatrix = &libvideo_swblitter_noblend_samefmt__stretch_imatrix_l;
157+
} else {
158+
drv->bsw_stretch = &libvideo_swblitter_noblend_samefmt__stretch_n;
159+
drv->bsw_stretch_imatrix = &libvideo_swblitter_noblend_samefmt__stretch_imatrix_n;
160+
}
161+
} else {
162+
/* Special optimization when not doing any blending, and both GFX contexts
163+
* share the same codec: in this case, we can try to directly copy pixel
164+
* data, either through video locks, or by directly reading/writing pixels */
165+
video_converter_init(libvideo_swblitter_generic__conv(ctx),
166+
&src_buffer->vb_format,
167+
&dst_buffer->vb_format);
168+
drv->bsw_blit = &libvideo_swblitter_noblend_difffmt__blit;
169+
drv->bsw_blit_imatrix = &libvideo_swblitter_noblend_difffmt__blit_imatrix;
170+
if (src_gfx->vx_flags & VIDEO_GFX_F_LINEAR) {
171+
drv->bsw_stretch = &libvideo_swblitter_noblend_difffmt__stretch_l;
172+
drv->bsw_stretch_imatrix = &libvideo_swblitter_noblend_difffmt__stretch_imatrix_l;
173+
} else {
174+
drv->bsw_stretch = &libvideo_swblitter_noblend_difffmt__stretch_n;
175+
drv->bsw_stretch_imatrix = &libvideo_swblitter_noblend_difffmt__stretch_imatrix_n;
176+
}
177+
}
178+
} else {
179+
set_generic_operators:
180+
drv->bsw_blit = &libvideo_swblitter_generic__blit;
181+
drv->bsw_blit_imatrix = &libvideo_swblitter_generic__blit_imatrix;
182+
if (src_gfx->vx_flags & VIDEO_GFX_F_LINEAR) {
183+
drv->bsw_stretch = &libvideo_swblitter_generic__stretch_l;
184+
drv->bsw_stretch_imatrix = &libvideo_swblitter_generic__stretch_imatrix_l;
185+
} else {
186+
drv->bsw_stretch = &libvideo_swblitter_generic__stretch_n;
187+
drv->bsw_stretch_imatrix = &libvideo_swblitter_generic__stretch_imatrix_n;
188+
}
189+
}
190+
return ctx;
191+
}
192+
193+
194+
INTERN ATTR_RETNONNULL ATTR_INOUT(1) struct video_blitter3 *FCC
195+
libvideo_swgfx_blitfrom3(struct video_blitter3 *__restrict ctx) {
196+
struct video_gfx const *src_gfx = ctx->vbt3_src;
197+
struct video_gfx const *rddst_gfx = ctx->vbt3_rddst;
198+
struct video_gfx const *wrdst_gfx = ctx->vbt3_wrdst;
199+
struct blt3_swdrv *drv = video_swblitter3_getdrv(ctx);
200+
video_swblitter3_setops(ctx);
201+
(void)wrdst_gfx;
202+
assert(video_gfx_getclipw(wrdst_gfx) != 0);
203+
assert(video_gfx_getcliph(wrdst_gfx) != 0);
204+
if (video_gfx_getclipw(src_gfx) == 0 || video_gfx_getcliph(src_gfx) == 0 ||
205+
video_gfx_getclipw(rddst_gfx) == 0 || video_gfx_getcliph(rddst_gfx) == 0) {
206+
ctx->vbt3_ops = &libvideo_emptyblitter3_ops;
207+
} else {
208+
drv->bsw3_blendmode = rddst_gfx->vx_blend;
209+
switch (__builtin_expect(GFX_BLENDMODE_GET_MODE(rddst_gfx->vx_blend),
210+
GFX_BLENDMODE_ALPHA)) {
211+
#define LINK_libvideo_swblt_generic__blend_FOO(name, mode) \
212+
case mode: \
213+
drv->bsw3_blend = &libvideo_swblitter3__blend_##name; \
214+
break;
215+
GFX_FOREACH_DEDICATED_BLENDMODE(LINK_libvideo_swblt_generic__blend_FOO)
216+
GFX_FOREACH_DEDICATED_BLENDMODE_FACTOR(LINK_libvideo_swblt_generic__blend_FOO)
217+
#undef LINK_libvideo_swblt_generic__blend_FOO
218+
default:
219+
drv->bsw3_blend = &libvideo_swblitter3__blend;
220+
break;
221+
}
222+
223+
/* TODO: Special handling when buffers overlap */
224+
/* TODO: More dedicated optimizations */
225+
226+
if likely(GFX_BLENDMODE_GET_MODE(wrdst_gfx->vx_blend) == GFX_BLENDMODE_OVERRIDE) {
227+
/* Special optimization for likely case where "wrdst_gfx" doesn't do any blending */
228+
drv->bsw3_blit = &libvideo_swblitter3__blit__blend1;
229+
drv->bsw3_blit_imatrix = &libvideo_swblitter3__blit_imatrix__blend1;
230+
if (src_gfx->vx_flags & VIDEO_GFX_F_LINEAR) {
231+
drv->bsw3_stretch = &libvideo_swblitter3__stretch__blend1_l;
232+
drv->bsw3_stretch_imatrix = &libvideo_swblitter3__stretch_imatrix__blend1_l;
233+
} else {
234+
drv->bsw3_stretch = &libvideo_swblitter3__stretch__blend1_n;
235+
drv->bsw3_stretch_imatrix = &libvideo_swblitter3__stretch_imatrix__blend1_n;
236+
}
237+
} else {
238+
drv->bsw3_blit = &libvideo_swblitter3__blit__generic;
239+
drv->bsw3_blit_imatrix = &libvideo_swblitter3__blit_imatrix__generic;
240+
if (src_gfx->vx_flags & VIDEO_GFX_F_LINEAR) {
241+
drv->bsw3_stretch = &libvideo_swblitter3__stretch__generic_l;
242+
drv->bsw3_stretch_imatrix = &libvideo_swblitter3__stretch_imatrix__generic_l;
243+
} else {
244+
drv->bsw3_stretch = &libvideo_swblitter3__stretch__generic_n;
245+
drv->bsw3_stretch_imatrix = &libvideo_swblitter3__stretch_imatrix__generic_n;
246+
}
247+
}
248+
}
249+
return ctx;
250+
}
251+
252+
DECL_END
253+
254+
#ifndef __INTELLISENSE__
255+
#define DEFINE_libvideo_swblitter_blit
256+
#include "swgfx/hl_blit-nowrap.c.inl"
257+
#define DEFINE_libvideo_swblitter_stretch
258+
#include "swgfx/hl_blit-nowrap.c.inl"
259+
#define DEFINE_libvideo_swblitter_blit_wrap
260+
#include "swgfx/hl_blit.c.inl"
261+
262+
#define DEFINE_libvideo_swblitter3_blit
263+
#include "swgfx/hl_blit-nowrap.c.inl"
264+
#define DEFINE_libvideo_swblitter3_stretch
265+
#include "swgfx/hl_blit-nowrap.c.inl"
266+
#define DEFINE_libvideo_swblitter3_blit_wrap
267+
#include "swgfx/hl_blit.c.inl"
268+
#endif /* !__INTELLISENSE__ */
269+
270+
#endif /* !GUARD_LIBVIDEO_GFX_SWGFX_HL_BLIT_C */
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ gcc_opt.append("-O3"); // Force _all_ optimizations because stuff in here is per
2222
* misrepresented as being the original software. *
2323
* 3. This notice may not be removed or altered from any source distribution. *
2424
*/
25-
#ifndef GUARD_LIBVIDEO_GFX_SWGFX_XYSWAP_C
26-
#define GUARD_LIBVIDEO_GFX_SWGFX_XYSWAP_C 1
25+
#ifndef GUARD_LIBVIDEO_GFX_SWGFX_HL_XYSWAP_C
26+
#define GUARD_LIBVIDEO_GFX_SWGFX_HL_XYSWAP_C 1
2727
#define _KOS_SOURCE 1
2828

2929
#include "api.h"
@@ -48,4 +48,4 @@ gcc_opt.append("-O3"); // Force _all_ optimizations because stuff in here is per
4848
#include "swgfx/hl_generic.c.inl"
4949
#endif /* !__INTELLISENSE__ */
5050

51-
#endif /* !GUARD_LIBVIDEO_GFX_SWGFX_XYSWAP_C */
51+
#endif /* !GUARD_LIBVIDEO_GFX_SWGFX_HL_XYSWAP_C */

0 commit comments

Comments
 (0)