Skip to content

Commit b191b97

Browse files
committed
Implement new region video_buffer
1 parent fa97ed0 commit b191b97

File tree

18 files changed

+2028
-127
lines changed

18 files changed

+2028
-127
lines changed

kos/include/libvideo/gfx/buffer.h

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,6 @@ struct video_buffer_ops {
381381
struct video_regionlock *__restrict __lock);
382382

383383

384-
/* Buffer revocation / sub-region operators */
385-
386384
/* Revoke access to non-anonymous pixel data (and maybe even anonymous) of this video buffer.
387385
* Access to pixel data of any sub-region created from `__self' (or recursively created form
388386
* one of those buffers) is also revoked.
@@ -528,6 +526,64 @@ video_buffer_wlockregion(struct video_buffer *__self, struct video_regionlock *_
528526
* by `video_buffer_rlockregion()' or `video_buffer_wlockregion()'. */
529527
extern __ATTR_INOUT(1) __ATTR_NONNULL((2)) void
530528
video_buffer_unlockregion(struct video_buffer *__self, struct video_regionlock *__lock);
529+
530+
531+
/* Revoke access to non-anonymous pixel data (and maybe even anonymous) of this video buffer.
532+
* Access to pixel data of any sub-region created from `__self' (or recursively created form
533+
* one of those buffers) is also revoked.
534+
*
535+
* All types of video buffers can have their access revoked, except for buffers returned by
536+
* `video_domain_newbuffer[_ex]()' (though sub-region buffers of those can be revoked, and
537+
* calling this function for one such buffer will do exactly that).
538+
*
539+
* @return: * : Always re-returns `__self' */
540+
extern __ATTR_RETNONNULL __ATTR_INOUT(1) struct video_buffer *
541+
__NOTHROW(video_buffer_revoke)(struct video_buffer *__restrict __self);
542+
543+
/* Create a new hard subregion-proxy of `__self'. The caller is responsible to ensure
544+
* that the given `__rect' does not exceed `__self->vb_xdim' / `__self->vb_ydim'. Note
545+
* that this function behaves slightly different from `video_buffer_region()', in that
546+
* the later accepts a signed rect, while also allowing said rect to be greater than
547+
* the dimensions of the original buffer.
548+
*
549+
* On the other hand, this function only works for creating **true** sub-rects, but
550+
* since this one is implemented by individual buffers, it is probably faster, too.
551+
*
552+
* Buffers returned by this function are guarantied to share pixel access with `__self',
553+
* and `video_buffer_revoke' is to `__self' will also revoke access for `return' (either
554+
* directly, by keeping a list of sub-region buffers in `__self', or indirectly, by having
555+
* every access to pixel-data in `return' check if `__self' has been revoked).
556+
*
557+
* NOTE: This function will never re-return `__self', even if `__rect' is the full
558+
* rect of `__self', and `__xor_flags == 0'. This is because doing also cause
559+
* `video_buffer_revoke' invoked on the returned buffer to revoke `__self'.
560+
*
561+
* @assume(__rect->vcr_xdim > 0);
562+
* @assume(__rect->vcr_ydim > 0);
563+
* @assume((__rect->vcr_xmin + __rect->vcr_xdim) > __rect->vcr_xmin);
564+
* @assume((__rect->vcr_ymin + __rect->vcr_ydim) > __rect->vcr_ymin);
565+
* @assume((__rect->vcr_xmin + __rect->vcr_xdim) <= __self->vb_xdim);
566+
* @assume((__rect->vcr_ymin + __rect->vcr_ydim) <= __self->vb_ydim);
567+
* @param: __self: Video buffer to create a sub-region of
568+
* @param: __rect: Sub-region rect of `__self' to-be returned
569+
* @param: __xor_flags: Flags to xor- toggle in GFX contexts created on `return'.
570+
* These flags are NOT applied to `__rect', but they still
571+
* allow you to create sub-region buffers that will appear
572+
* to be natively rotated in `struct video_gfx' contexts.
573+
* Only the following flags *should* be used here. All other
574+
* flags can still be used, but many not necessarily produce
575+
* expected results:
576+
* - VIDEO_GFX_F_XMIRROR
577+
* - VIDEO_GFX_F_YMIRROR
578+
* - VIDEO_GFX_F_XYSWAP
579+
* @return: * : The newly created sub-region buffer
580+
* @return: NULL: [errno=ENOMEM] Insufficient memory
581+
* @return: NULL: [errno=*] Failed to create sub-region for some other reason */
582+
extern __ATTR_WUNUSED __ATTR_INOUT(1) __ATTR_IN(2) __REF struct video_buffer *
583+
video_buffer_subregion(struct video_buffer *__restrict __self,
584+
struct video_crect const *__restrict __rect,
585+
gfx_flag_t __xor_flags);
586+
531587
#else /* __INTELLISENSE__ */
532588
#define video_buffer_getgfx(self, result, blendmode, flags, colorkey) \
533589
((result)->vx_colorkey = (colorkey), (result)->vx_flags = (flags), \
@@ -549,6 +605,9 @@ video_buffer_unlockregion(struct video_buffer *__self, struct video_regionlock *
549605
(*(self)->vb_ops->vi_wlockregion)(self, lock))
550606
#define video_buffer_unlockregion(self, lock) \
551607
(*(self)->vb_ops->vi_unlockregion)(self, lock)
608+
#define video_buffer_revoke(self) (*(self)->vb_ops->vi_revoke)(self)
609+
#define video_buffer_subregion(self, rect, xor_flags) \
610+
(*(self)->vb_ops->vi_subregion)(self, rect, xor_flags)
552611
#endif /* !__INTELLISENSE__ */
553612

554613

@@ -785,6 +844,58 @@ video_buffer_lockable(struct video_buffer *__restrict __self);
785844
#endif /* LIBVIDEO_GFX_WANT_PROTOTYPES */
786845

787846

847+
848+
/* Create a new region-relative-proxy of `__self', that interacts with the same
849+
* pixel data, both during GFX operations, as well when creating video locks.
850+
*
851+
* You can also use this function to create regions at negative offsets, or
852+
* ones that are larger than `__self'. In this case, the returned buffer will
853+
* not be lockable, except when using `video_buffer_r/wlockregion' for regions
854+
* that contain actual pixel data. Similarly, GFX operations for pixel data
855+
* outside the true pixel area (which is enforced by the I/O Rect of any GFX
856+
* created using the returned buffer), will yield "0" during read, and be a
857+
* no-op during write.
858+
*
859+
* Then returned buffer always behaves properly when it comes to being able to
860+
* be revoked, after which point it will never again make any access to pixel
861+
* data of `__self'.
862+
*
863+
* When the given `__rect' is actually a sub-region of `__self', then this
864+
* function will simply make use of `video_buffer_subregion()' and call the
865+
* dedicated video buffer operator for creating sub-regions.
866+
*
867+
* When the returned buffer isn't created as a true sub-region of `__self',
868+
* its `vb_domain' will be set to the return value of `video_ramdomain()'.
869+
*
870+
* @param: __self: Video buffer to create a region of
871+
* @param: __rect: region rect of `__self' to-be returned
872+
* @param: __xor_flags: Flags to xor- toggle in GFX contexts created on `return'.
873+
* These flags are NOT applied to `__rect', but they still
874+
* allow you to create region buffers that will appear to be
875+
* natively rotated in `struct video_gfx' contexts. Only the
876+
* following flags *should* be used here. All other flags can
877+
* still be used, but many not necessarily produce expected
878+
* results:
879+
* - VIDEO_GFX_F_XMIRROR
880+
* - VIDEO_GFX_F_YMIRROR
881+
* - VIDEO_GFX_F_XYSWAP
882+
* @return: * : The newly created region buffer
883+
* @return: NULL: [errno=ENOMEM] Insufficient memory
884+
* @return: NULL: [errno=*] Failed to create region for some other reason */
885+
typedef __ATTR_WUNUSED_T __ATTR_INOUT_T(1) __ATTR_IN_T(2) __REF struct video_buffer *
886+
(LIBVIDEO_GFX_CC *PVIDEO_BUFFER_REGION)(struct video_buffer *__restrict __self,
887+
struct video_rect const *__restrict __rect,
888+
gfx_flag_t __xor_flags);
889+
#ifdef LIBVIDEO_GFX_WANT_PROTOTYPES
890+
LIBVIDEO_GFX_DECL __ATTR_WUNUSED __ATTR_INOUT(1) __ATTR_IN(2) __REF struct video_buffer *LIBVIDEO_GFX_CC
891+
video_buffer_region(struct video_buffer *__restrict __self,
892+
struct video_rect const *__restrict __rect,
893+
gfx_flag_t __xor_flags);
894+
#endif /* LIBVIDEO_GFX_WANT_PROTOTYPES */
895+
896+
897+
898+
788899
/* Return a video buffer that will always (forcefully) re-return `__self'
789900
* whenever a GFX context is requested. Additionally, video locks will fail
790901
* when pixels represented by `__self' cannot represented as a video lock

kos/include/libvideo/gfx/gfx.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ __DECL_BEGIN
8383
/* Set of `VIDEO_GFX_F*' */
8484
typedef __UINT32_TYPE__ gfx_flag_t;
8585

86+
/* XXX: When "old_flags & VIDEO_GFX_F_XYSWAP", I believe we have to swap
87+
* "more_flags & VIDEO_GFX_F_XMIRROR" / "more_flags & VIDEO_GFX_F_YMIRROR"
88+
* before they are XOR'd with `old_flags' */
89+
#define gfx_flag_combine(old_flags, more_flags) \
90+
((old_flags) ^ (more_flags))
91+
8692
struct video_buffer;
8793
struct video_gfxhdr;
8894
struct video_gfx;

kos/include/libvideo/rect.h

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ struct video_rect {
7777

7878
/* Check if "a" and "b" intersect, and if so: store that intersection and return true */
7979
__LOCAL __ATTR_WUNUSED __ATTR_IN(1) __ATTR_IN(2) __ATTR_OUT(3) __BOOL
80-
video_rect_intersect(struct video_rect const *__restrict __a,
81-
struct video_rect const *__restrict __b,
82-
struct video_rect *__restrict __intersect) {
80+
video_rect_intersect(struct video_rect const *__a,
81+
struct video_rect const *__b,
82+
struct video_rect *__intersect) {
8383
video_offset_t __a_xend = video_rect_getxend(__a);
8484
video_offset_t __a_yend = video_rect_getyend(__a);
8585
video_offset_t __b_xend = video_rect_getxend(__b);
@@ -99,9 +99,9 @@ video_rect_intersect(struct video_rect const *__restrict __a,
9999

100100
/* Same as `video_rect_intersect()', but safely handles overflow in "__b" */
101101
__LOCAL __ATTR_WUNUSED __ATTR_IN(1) __ATTR_IN(2) __ATTR_OUT(3) __BOOL
102-
video_rect_intersect_overflow_in_b(struct video_rect const *__restrict __a,
103-
struct video_rect const *__restrict __b,
104-
struct video_rect *__restrict __intersect) {
102+
video_rect_intersect_overflow_in_b(struct video_rect const *__a,
103+
struct video_rect const *__b,
104+
struct video_rect *__intersect) {
105105
video_offset_t __b_xend, __b_yend, __intersect_xend, __intersect_yend;
106106
video_offset_t __a_xend = video_rect_getxend(__a);
107107
video_offset_t __a_yend = video_rect_getyend(__a);
@@ -122,6 +122,32 @@ video_rect_intersect_overflow_in_b(struct video_rect const *__restrict __a,
122122
}
123123

124124

125+
__LOCAL __ATTR_WUNUSED __ATTR_IN(1) __ATTR_IN(2) __ATTR_OUT(3) __BOOL
126+
video_rect_intersect_overflow(struct video_rect const *__a,
127+
struct video_rect const *__b,
128+
struct video_rect *__intersect) {
129+
video_offset_t __a_xend, __a_yend, __b_xend, __b_yend, __intersect_xend, __intersect_yend;
130+
if (__hybrid_overflow_sadd(video_rect_getxmin(__a), video_rect_getxdim(__a), &__a_xend))
131+
__a_xend = VIDEO_OFFSET_MAX;
132+
if (__hybrid_overflow_sadd(video_rect_getymin(__a), video_rect_getydim(__a), &__a_yend))
133+
__a_yend = VIDEO_OFFSET_MAX;
134+
if (__hybrid_overflow_sadd(video_rect_getxmin(__b), video_rect_getxdim(__b), &__b_xend))
135+
__b_xend = VIDEO_OFFSET_MAX;
136+
if (__hybrid_overflow_sadd(video_rect_getymin(__b), video_rect_getydim(__b), &__b_yend))
137+
__b_yend = VIDEO_OFFSET_MAX;
138+
__intersect_xend = __hybrid_min(__a_xend, __b_xend);
139+
__intersect_yend = __hybrid_min(__a_yend, __b_yend);
140+
video_rect_setxmin(__intersect, __hybrid_max(video_rect_getxmin(__a), video_rect_getxmin(__b)));
141+
video_rect_setymin(__intersect, __hybrid_max(video_rect_getymin(__a), video_rect_getymin(__b)));
142+
if (video_rect_getxmin(__intersect) < __intersect_xend && video_rect_getymin(__intersect) < __intersect_yend) {
143+
video_rect_setxend(__intersect, __intersect_xend);
144+
video_rect_setyend(__intersect, __intersect_yend);
145+
return 1;
146+
}
147+
return 0;
148+
}
149+
150+
125151
/* Update `__union' by adding `__addme' */
126152
__LOCAL __ATTR_INOUT(1) __ATTR_IN(2) void
127153
video_rect_union(struct video_rect *__restrict __union,

kos/src/libvideo/gfx/buffer.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,29 @@ NOTHROW(FCC libvideo_buffer_noop_unlock)(struct video_buffer *__restrict self,
8080
(self)->vi_wlockregion = &libvideo_buffer_notsup_wlockregion, \
8181
(self)->vi_unlockregion = &libvideo_buffer_noop_unlockregion)
8282

83+
#define DEFINE_VIDEO_BUFFER_TYPE(name, vi_destroy_, vi_initgfx_, vi_updategfx_, vi_rlock_, vi_wlock_, \
84+
vi_unlock_, vi_rlockregion_, vi_wlockregion_, vi_unlockregion_, \
85+
vi_revoke_, vi_subregion_) \
86+
INTERN struct video_buffer_ops name = {}; \
87+
INTERN ATTR_RETNONNULL WUNUSED struct video_buffer_ops const *CC _##name(void) { \
88+
if unlikely(!name.vi_destroy) { \
89+
name.vi_initgfx = vi_initgfx_; \
90+
name.vi_updategfx = vi_updategfx_; \
91+
name.vi_rlock = vi_rlock_; \
92+
name.vi_wlock = vi_wlock_; \
93+
name.vi_unlock = vi_unlock_; \
94+
name.vi_rlockregion = vi_rlockregion_; \
95+
name.vi_wlockregion = vi_wlockregion_; \
96+
name.vi_unlockregion = vi_unlockregion_; \
97+
name.vi_revoke = vi_revoke_; \
98+
name.vi_subregion = vi_subregion_; \
99+
COMPILER_WRITE_BARRIER(); \
100+
name.vi_destroy = &vi_destroy_; \
101+
COMPILER_WRITE_BARRIER(); \
102+
} \
103+
return &name; \
104+
}
105+
83106

84107
INTDEF WUNUSED ATTR_INOUT(1) ATTR_INOUT(2) int FCC
85108
libvideo_buffer_generic_rlockregion(struct video_buffer *__restrict self,

kos/src/libvideo/gfx/buffer/bitmask.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ libvideo_buffer_forbitmask(video_dim_t size_x, video_dim_t size_y,
260260
if likely(result) {
261261
result = bitmask_buffer_init(result, size_x, size_y, bm, bg_fg_colors);
262262
result->vb_refcnt = 1;
263-
result->vb_domain = libvideo_ramdomain();
263+
result->vb_domain = _libvideo_ramdomain();
264264
}
265265
return result;
266266
}

kos/src/libvideo/gfx/buffer/custom.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ libvideo_buffer_forcustom(video_dim_t size_x, video_dim_t size_y,
261261
if (!(codec->vc_specs.vcs_flags & VIDEO_CODEC_FLAG_PAL))
262262
palette = NULL;
263263
result->vb_ops = _custom_ops();
264-
result->vb_domain = libvideo_ramdomain();
264+
result->vb_domain = _libvideo_ramdomain();
265265
result->vb_format.vf_codec = codec;
266266
result->vb_format.vf_pal = palette;
267267
if (palette)

0 commit comments

Comments
 (0)