├── .gitignore ├── Makefile ├── README.md ├── decoder.c ├── device.c ├── h264.c ├── h265.c ├── handles.c ├── kernel-headers ├── README ├── drv_display.h ├── g2d_driver.h ├── sunxi_disp_ioctl.h └── sunxi_display2.h ├── mpeg12.c ├── mpeg4.c ├── presentation_queue.c ├── rgba.c ├── rgba.h ├── rgba_g2d.c ├── rgba_g2d.h ├── rgba_pixman.c ├── rgba_pixman.h ├── sunxi_disp.c ├── sunxi_disp.h ├── sunxi_disp1_5.c ├── sunxi_disp2.c ├── surface_bitmap.c ├── surface_output.c ├── surface_video.c ├── tiled_yuv.S ├── tiled_yuv.h ├── vdpau_private.h └── video_mixer.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | libvdpau_sunxi.so.1 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = libvdpau_sunxi.so.1 2 | SRC = device.c presentation_queue.c surface_output.c surface_video.c \ 3 | surface_bitmap.c video_mixer.c decoder.c handles.c \ 4 | h264.c mpeg12.c mpeg4.c rgba.c tiled_yuv.S h265.c sunxi_disp.c \ 5 | sunxi_disp2.c sunxi_disp1_5.c rgba_g2d.c rgba_pixman.c 6 | CFLAGS ?= -Wall -O3 7 | LDFLAGS ?= 8 | LIBS = -lrt -lm -lX11 -lpthread -lcedrus 9 | CC ?= gcc 10 | 11 | CFLAGS += $(shell pkg-config --cflags pixman-1) 12 | LIBS += $(shell pkg-config --libs pixman-1) 13 | 14 | DEP_CFLAGS = -MD -MP -MQ $@ 15 | LIB_CFLAGS = -fpic -fvisibility=hidden 16 | LIB_LDFLAGS = -shared -Wl,-soname,$(TARGET) 17 | 18 | OBJ = $(addsuffix .o,$(basename $(SRC))) 19 | DEP = $(addsuffix .d,$(basename $(SRC))) 20 | 21 | MODULEDIR = $(shell pkg-config --variable=moduledir vdpau) 22 | 23 | ifeq ($(MODULEDIR),) 24 | MODULEDIR=/usr/lib/vdpau 25 | endif 26 | 27 | .PHONY: clean all install uninstall 28 | 29 | all: $(TARGET) 30 | $(TARGET): $(OBJ) 31 | $(CC) $(LIB_LDFLAGS) $(LDFLAGS) $(OBJ) $(LIBS) -o $@ 32 | 33 | clean: 34 | rm -f $(OBJ) 35 | rm -f $(DEP) 36 | rm -f $(TARGET) 37 | 38 | install: $(TARGET) 39 | install -D $(TARGET) $(DESTDIR)$(MODULEDIR)/$(TARGET) 40 | ln -sf $(TARGET) $(DESTDIR)$(MODULEDIR)/$(basename $(TARGET)) 41 | 42 | uninstall: 43 | rm -f $(DESTDIR)$(MODULEDIR)/$(basename $(TARGET)) 44 | rm -f $(DESTDIR)$(MODULEDIR)/$(TARGET) 45 | 46 | %.o: %.c 47 | $(CC) $(DEP_CFLAGS) $(LIB_CFLAGS) $(CFLAGS) -c $< -o $@ 48 | 49 | %.o: %.S 50 | $(CC) -c $< -o $@ 51 | 52 | include $(wildcard $(DEP)) 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | libvdpau-sunxi is a [VDPAU] (ftp://download.nvidia.com/XFree86/vdpau/doxygen/html/index.html) backend driver 4 | for Allwinner based (sunxi) SoCs. 5 | 6 | It is based on the [reverse engineering effort] (http://linux-sunxi.org/Cedrus) of the [linux-sunxi] (http://linux-sunxi.org) community. 7 | It does neither depend on code, which was released by Allwinner, nor does it act like a wrapper around some precompiled binary libraries. 8 | libvdpau-sunxi is a clean implementation, that is based on reverse engineering. 9 | 10 | It currently supports decoding of MPEG1 and MPEG2, some limited MPEG4 types and H.264. On H3/A64 it also decodes H.265. 11 | It also supports all the basic features of the VDPAU API - including presentation. 12 | As this is **W**ork**I**n**P**rogress, not all features are implemented yet. 13 | Some of them probably will never get fully supported due to hardware specific limitations. 14 | 15 | # Requirements: 16 | 17 | * libvdpau >= 1.1 18 | * libcedrus (https://github.com/linux-sunxi/libcedrus) 19 | * pixman (http://www.pixman.org) 20 | 21 | # Installation: 22 | ``` 23 | $ make 24 | $ make install 25 | ``` 26 | 27 | # Usage: 28 | ``` 29 | $ export VDPAU_DRIVER=sunxi 30 | $ mpv --vo=vdpau --hwdec=vdpau --hwdec-codecs=all [filename] 31 | ``` 32 | 33 | Note: Make sure that you have write access to both `/dev/disp` and `/dev/cedar_dev` 34 | 35 | # OSD Support: 36 | 37 | OSD support is available either 38 | * via G2D mixer processor (hardware accelerated) on A10/A20 or 39 | * via pixman (CPU/Neon based) on H3/A33/A80/A64. 40 | 41 | To enable OSD support for e.g. subtitles or GUI, set VDPAU_OSD environment variable to 1: 42 | ``` 43 | $ export VDPAU_OSD=1 44 | ``` 45 | 46 | To disable G2D mixer processor usage (for debugging purposes and forcing pixman usage on A10/A20), set VDPAU_DISABLE_G2D environment variable to 1: 47 | ``` 48 | $ export VDPAU_DISABLE_G2D=1 49 | ``` 50 | 51 | If using G2D (A10/A20), make sure to have write access to `/dev/g2d`. 52 | 53 | # Limitations: 54 | 55 | * Output bypasses X video driver by opening own disp layers. You can't use Xv from fbturbo at the same time, and on H3 the video is always on top and can't be overlapped by other windows. 56 | * OSD partly breaks X11 integration due to hardware limitations. The video area can't be overlapped by other windows. For fullscreen use this is no problem. 57 | * There is no [OpenGL interoperation feature] (https://www.opengl.org/registry/specs/NV/vdpau_interop.txt) because we are on ARM and only have OpenGL/ES available. 58 | -------------------------------------------------------------------------------- /decoder.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include "vdpau_private.h" 23 | 24 | VdpStatus vdp_decoder_create(VdpDevice device, 25 | VdpDecoderProfile profile, 26 | uint32_t width, 27 | uint32_t height, 28 | uint32_t max_references, 29 | VdpDecoder *decoder) 30 | { 31 | device_ctx_t *dev = handle_get(device); 32 | if (!dev) 33 | return VDP_STATUS_INVALID_HANDLE; 34 | 35 | if (max_references > 16) 36 | return VDP_STATUS_ERROR; 37 | 38 | decoder_ctx_t *dec = handle_create(sizeof(*dec), decoder); 39 | if (!dec) 40 | goto err_ctx; 41 | 42 | dec->device = dev; 43 | dec->profile = profile; 44 | dec->width = width; 45 | dec->height = height; 46 | 47 | dec->data = cedrus_mem_alloc(dec->device->cedrus, VBV_SIZE); 48 | if (!(dec->data)) 49 | goto err_data; 50 | 51 | VdpStatus ret; 52 | switch (profile) 53 | { 54 | case VDP_DECODER_PROFILE_MPEG1: 55 | case VDP_DECODER_PROFILE_MPEG2_SIMPLE: 56 | case VDP_DECODER_PROFILE_MPEG2_MAIN: 57 | ret = new_decoder_mpeg12(dec); 58 | break; 59 | 60 | case VDP_DECODER_PROFILE_H264_BASELINE: 61 | case VDP_DECODER_PROFILE_H264_MAIN: 62 | case VDP_DECODER_PROFILE_H264_HIGH: 63 | case VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE: 64 | case VDP_DECODER_PROFILE_H264_CONSTRAINED_HIGH: 65 | ret = new_decoder_h264(dec); 66 | break; 67 | 68 | case VDP_DECODER_PROFILE_MPEG4_PART2_SP: 69 | case VDP_DECODER_PROFILE_MPEG4_PART2_ASP: 70 | ret = new_decoder_mpeg4(dec); 71 | break; 72 | 73 | case VDP_DECODER_PROFILE_HEVC_MAIN: 74 | if (cedrus_get_ve_version(dec->device->cedrus) >= 0x1680) 75 | ret = new_decoder_h265(dec); 76 | else 77 | ret = VDP_STATUS_INVALID_DECODER_PROFILE; 78 | break; 79 | 80 | default: 81 | ret = VDP_STATUS_INVALID_DECODER_PROFILE; 82 | break; 83 | } 84 | 85 | if (ret != VDP_STATUS_OK) 86 | goto err_decoder; 87 | 88 | return VDP_STATUS_OK; 89 | 90 | err_decoder: 91 | cedrus_mem_free(dec->data); 92 | err_data: 93 | handle_destroy(*decoder); 94 | err_ctx: 95 | return VDP_STATUS_RESOURCES; 96 | } 97 | 98 | VdpStatus vdp_decoder_destroy(VdpDecoder decoder) 99 | { 100 | decoder_ctx_t *dec = handle_get(decoder); 101 | if (!dec) 102 | return VDP_STATUS_INVALID_HANDLE; 103 | 104 | if (dec->private_free) 105 | dec->private_free(dec); 106 | 107 | cedrus_mem_free(dec->data); 108 | 109 | handle_destroy(decoder); 110 | 111 | return VDP_STATUS_OK; 112 | } 113 | 114 | VdpStatus vdp_decoder_get_parameters(VdpDecoder decoder, 115 | VdpDecoderProfile *profile, 116 | uint32_t *width, 117 | uint32_t *height) 118 | { 119 | decoder_ctx_t *dec = handle_get(decoder); 120 | if (!dec) 121 | return VDP_STATUS_INVALID_HANDLE; 122 | 123 | if (profile) 124 | *profile = dec->profile; 125 | 126 | if (width) 127 | *width = dec->width; 128 | 129 | if (height) 130 | *height = dec->height; 131 | 132 | return VDP_STATUS_OK; 133 | } 134 | 135 | VdpStatus vdp_decoder_render(VdpDecoder decoder, 136 | VdpVideoSurface target, 137 | VdpPictureInfo const *picture_info, 138 | uint32_t bitstream_buffer_count, 139 | VdpBitstreamBuffer const *bitstream_buffers) 140 | { 141 | decoder_ctx_t *dec = handle_get(decoder); 142 | if (!dec) 143 | return VDP_STATUS_INVALID_HANDLE; 144 | 145 | video_surface_ctx_t *vid = handle_get(target); 146 | if (!vid) 147 | return VDP_STATUS_INVALID_HANDLE; 148 | 149 | if (cedrus_get_ve_version(dec->device->cedrus) >= 0x1680) 150 | vid->source_format = VDP_YCBCR_FORMAT_YV12; 151 | else 152 | vid->source_format = INTERNAL_YCBCR_FORMAT; 153 | 154 | unsigned int i, pos = 0; 155 | 156 | for (i = 0; i < bitstream_buffer_count; i++) 157 | { 158 | memcpy(cedrus_mem_get_pointer(dec->data) + pos, bitstream_buffers[i].bitstream, bitstream_buffers[i].bitstream_bytes); 159 | pos += bitstream_buffers[i].bitstream_bytes; 160 | } 161 | cedrus_mem_flush_cache(dec->data); 162 | 163 | return dec->decode(dec, picture_info, pos, vid); 164 | } 165 | 166 | VdpStatus vdp_decoder_query_capabilities(VdpDevice device, 167 | VdpDecoderProfile profile, 168 | VdpBool *is_supported, 169 | uint32_t *max_level, 170 | uint32_t *max_macroblocks, 171 | uint32_t *max_width, 172 | uint32_t *max_height) 173 | { 174 | if (!is_supported || !max_level || !max_macroblocks || !max_width || !max_height) 175 | return VDP_STATUS_INVALID_POINTER; 176 | 177 | device_ctx_t *dev = handle_get(device); 178 | if (!dev) 179 | return VDP_STATUS_INVALID_HANDLE; 180 | 181 | *max_width = 3840; 182 | *max_height = 2160; 183 | *max_macroblocks = (*max_width * *max_height) / (16 * 16); 184 | 185 | switch (profile) 186 | { 187 | case VDP_DECODER_PROFILE_MPEG1: 188 | *max_level = VDP_DECODER_LEVEL_MPEG1_NA; 189 | *is_supported = VDP_TRUE; 190 | break; 191 | case VDP_DECODER_PROFILE_MPEG2_SIMPLE: 192 | case VDP_DECODER_PROFILE_MPEG2_MAIN: 193 | *max_level = VDP_DECODER_LEVEL_MPEG2_HL; 194 | *is_supported = VDP_TRUE; 195 | break; 196 | case VDP_DECODER_PROFILE_H264_BASELINE: 197 | case VDP_DECODER_PROFILE_H264_MAIN: 198 | case VDP_DECODER_PROFILE_H264_HIGH: 199 | case VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE: 200 | case VDP_DECODER_PROFILE_H264_CONSTRAINED_HIGH: 201 | *max_level = VDP_DECODER_LEVEL_H264_5_1; 202 | *is_supported = VDP_TRUE; 203 | break; 204 | case VDP_DECODER_PROFILE_MPEG4_PART2_SP: 205 | case VDP_DECODER_PROFILE_MPEG4_PART2_ASP: 206 | *max_level = VDP_DECODER_LEVEL_MPEG4_PART2_ASP_L5; 207 | *is_supported = VDP_TRUE; 208 | break; 209 | case VDP_DECODER_PROFILE_HEVC_MAIN: 210 | *max_level = VDP_DECODER_LEVEL_HEVC_5; 211 | if (cedrus_get_ve_version(dev->cedrus) >= 0x1680) 212 | *is_supported = VDP_TRUE; 213 | else 214 | *is_supported = VDP_FALSE; 215 | break; 216 | 217 | default: 218 | *is_supported = VDP_FALSE; 219 | break; 220 | } 221 | 222 | return VDP_STATUS_OK; 223 | } 224 | -------------------------------------------------------------------------------- /device.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "vdpau_private.h" 25 | 26 | VdpStatus vdp_imp_device_create_x11(Display *display, 27 | int screen, 28 | VdpDevice *device, 29 | VdpGetProcAddress **get_proc_address) 30 | { 31 | if (!display || !device || !get_proc_address) 32 | return VDP_STATUS_INVALID_POINTER; 33 | 34 | device_ctx_t *dev = handle_create(sizeof(*dev), device); 35 | if (!dev) 36 | return VDP_STATUS_RESOURCES; 37 | 38 | dev->display = XOpenDisplay(XDisplayString(display)); 39 | dev->screen = screen; 40 | 41 | dev->cedrus = cedrus_open(); 42 | if (!dev->cedrus) 43 | { 44 | XCloseDisplay(dev->display); 45 | handle_destroy(*device); 46 | return VDP_STATUS_ERROR; 47 | } 48 | 49 | VDPAU_DBG("VE version 0x%04x opened", cedrus_get_ve_version(dev->cedrus)); 50 | *get_proc_address = vdp_get_proc_address; 51 | 52 | char *env_vdpau_osd = getenv("VDPAU_OSD"); 53 | char *env_vdpau_g2d = getenv("VDPAU_DISABLE_G2D"); 54 | if (env_vdpau_osd && strncmp(env_vdpau_osd, "1", 1) == 0) 55 | dev->osd_enabled = 1; 56 | else 57 | { 58 | VDPAU_DBG("OSD disabled!"); 59 | return VDP_STATUS_OK; 60 | } 61 | 62 | if (!env_vdpau_g2d || strncmp(env_vdpau_g2d, "1", 1) !=0) 63 | { 64 | dev->g2d_fd = open("/dev/g2d", O_RDWR); 65 | if (dev->g2d_fd != -1) 66 | { 67 | dev->g2d_enabled = 1; 68 | VDPAU_DBG("OSD enabled, using G2D!"); 69 | } 70 | } 71 | 72 | if (!dev->g2d_enabled) 73 | VDPAU_DBG("OSD enabled, using pixman"); 74 | 75 | return VDP_STATUS_OK; 76 | } 77 | 78 | VdpStatus vdp_device_destroy(VdpDevice device) 79 | { 80 | device_ctx_t *dev = handle_get(device); 81 | if (!dev) 82 | return VDP_STATUS_INVALID_HANDLE; 83 | 84 | if (dev->g2d_enabled) 85 | close(dev->g2d_fd); 86 | cedrus_close(dev->cedrus); 87 | XCloseDisplay(dev->display); 88 | 89 | handle_destroy(device); 90 | 91 | return VDP_STATUS_OK; 92 | } 93 | 94 | VdpStatus vdp_preemption_callback_register(VdpDevice device, 95 | VdpPreemptionCallback callback, 96 | void *context) 97 | { 98 | if (!callback) 99 | return VDP_STATUS_INVALID_POINTER; 100 | 101 | device_ctx_t *dev = handle_get(device); 102 | if (!dev) 103 | return VDP_STATUS_INVALID_HANDLE; 104 | 105 | dev->preemption_callback = callback; 106 | dev->preemption_callback_context = context; 107 | 108 | return VDP_STATUS_OK; 109 | } 110 | 111 | static void *const functions[] = 112 | { 113 | [VDP_FUNC_ID_GET_ERROR_STRING] = vdp_get_error_string, 114 | [VDP_FUNC_ID_GET_PROC_ADDRESS] = vdp_get_proc_address, 115 | [VDP_FUNC_ID_GET_API_VERSION] = vdp_get_api_version, 116 | [VDP_FUNC_ID_GET_INFORMATION_STRING] = vdp_get_information_string, 117 | [VDP_FUNC_ID_DEVICE_DESTROY] = vdp_device_destroy, 118 | [VDP_FUNC_ID_GENERATE_CSC_MATRIX] = vdp_generate_csc_matrix, 119 | [VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES] = vdp_video_surface_query_capabilities, 120 | [VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES] = vdp_video_surface_query_get_put_bits_y_cb_cr_capabilities, 121 | [VDP_FUNC_ID_VIDEO_SURFACE_CREATE] = vdp_video_surface_create, 122 | [VDP_FUNC_ID_VIDEO_SURFACE_DESTROY] = vdp_video_surface_destroy, 123 | [VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS] = vdp_video_surface_get_parameters, 124 | [VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR] = vdp_video_surface_get_bits_y_cb_cr, 125 | [VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR] = vdp_video_surface_put_bits_y_cb_cr, 126 | [VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES] = vdp_output_surface_query_capabilities, 127 | [VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_GET_PUT_BITS_NATIVE_CAPABILITIES] = vdp_output_surface_query_get_put_bits_native_capabilities, 128 | [VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_INDEXED_CAPABILITIES] = vdp_output_surface_query_put_bits_indexed_capabilities, 129 | [VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_Y_CB_CR_CAPABILITIES] = vdp_output_surface_query_put_bits_y_cb_cr_capabilities, 130 | [VDP_FUNC_ID_OUTPUT_SURFACE_CREATE] = vdp_output_surface_create, 131 | [VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY] = vdp_output_surface_destroy, 132 | [VDP_FUNC_ID_OUTPUT_SURFACE_GET_PARAMETERS] = vdp_output_surface_get_parameters, 133 | [VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE] = vdp_output_surface_get_bits_native, 134 | [VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE] = vdp_output_surface_put_bits_native, 135 | [VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED] = vdp_output_surface_put_bits_indexed, 136 | [VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR] = vdp_output_surface_put_bits_y_cb_cr, 137 | [VDP_FUNC_ID_BITMAP_SURFACE_QUERY_CAPABILITIES] = vdp_bitmap_surface_query_capabilities, 138 | [VDP_FUNC_ID_BITMAP_SURFACE_CREATE] = vdp_bitmap_surface_create, 139 | [VDP_FUNC_ID_BITMAP_SURFACE_DESTROY] = vdp_bitmap_surface_destroy, 140 | [VDP_FUNC_ID_BITMAP_SURFACE_GET_PARAMETERS] = vdp_bitmap_surface_get_parameters, 141 | [VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE] = vdp_bitmap_surface_put_bits_native, 142 | [VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE] = vdp_output_surface_render_output_surface, 143 | [VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE] = vdp_output_surface_render_bitmap_surface, 144 | [VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_VIDEO_SURFACE_LUMA] = NULL, 145 | [VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES] = vdp_decoder_query_capabilities, 146 | [VDP_FUNC_ID_DECODER_CREATE] = vdp_decoder_create, 147 | [VDP_FUNC_ID_DECODER_DESTROY] = vdp_decoder_destroy, 148 | [VDP_FUNC_ID_DECODER_GET_PARAMETERS] = vdp_decoder_get_parameters, 149 | [VDP_FUNC_ID_DECODER_RENDER] = vdp_decoder_render, 150 | [VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT] = vdp_video_mixer_query_feature_support, 151 | [VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT] = vdp_video_mixer_query_parameter_support, 152 | [VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT] = vdp_video_mixer_query_attribute_support, 153 | [VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE] = vdp_video_mixer_query_parameter_value_range, 154 | [VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE] = vdp_video_mixer_query_attribute_value_range, 155 | [VDP_FUNC_ID_VIDEO_MIXER_CREATE] = vdp_video_mixer_create, 156 | [VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES] = vdp_video_mixer_set_feature_enables, 157 | [VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES] = vdp_video_mixer_set_attribute_values, 158 | [VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_SUPPORT] = vdp_video_mixer_get_feature_support, 159 | [VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_ENABLES] = vdp_video_mixer_get_feature_enables, 160 | [VDP_FUNC_ID_VIDEO_MIXER_GET_PARAMETER_VALUES] = vdp_video_mixer_get_parameter_values, 161 | [VDP_FUNC_ID_VIDEO_MIXER_GET_ATTRIBUTE_VALUES] = vdp_video_mixer_get_attribute_values, 162 | [VDP_FUNC_ID_VIDEO_MIXER_DESTROY] = vdp_video_mixer_destroy, 163 | [VDP_FUNC_ID_VIDEO_MIXER_RENDER] = vdp_video_mixer_render, 164 | [VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY] = vdp_presentation_queue_target_destroy, 165 | [VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE] = vdp_presentation_queue_create, 166 | [VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY] = vdp_presentation_queue_destroy, 167 | [VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR] = vdp_presentation_queue_set_background_color, 168 | [VDP_FUNC_ID_PRESENTATION_QUEUE_GET_BACKGROUND_COLOR] = vdp_presentation_queue_get_background_color, 169 | [VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME] = vdp_presentation_queue_get_time, 170 | [VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY] = vdp_presentation_queue_display, 171 | [VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE] = vdp_presentation_queue_block_until_surface_idle, 172 | [VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS] = vdp_presentation_queue_query_surface_status, 173 | [VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER] = vdp_preemption_callback_register, 174 | }; 175 | 176 | VdpStatus vdp_get_proc_address(VdpDevice device_handle, 177 | VdpFuncId function_id, 178 | void **function_pointer) 179 | { 180 | if (!function_pointer) 181 | return VDP_STATUS_INVALID_POINTER; 182 | 183 | device_ctx_t *device = handle_get(device_handle); 184 | if (!device) 185 | return VDP_STATUS_INVALID_HANDLE; 186 | 187 | if (function_id < ARRAY_SIZE(functions)) 188 | { 189 | *function_pointer = functions[function_id]; 190 | if (*function_pointer == NULL) 191 | return VDP_STATUS_INVALID_FUNC_ID; 192 | else 193 | return VDP_STATUS_OK; 194 | } 195 | else if (function_id == VDP_FUNC_ID_BASE_WINSYS) 196 | { 197 | *function_pointer = &vdp_presentation_queue_target_create_x11; 198 | 199 | return VDP_STATUS_OK; 200 | } 201 | 202 | return VDP_STATUS_INVALID_FUNC_ID; 203 | } 204 | 205 | char const *vdp_get_error_string(VdpStatus status) 206 | { 207 | switch (status) 208 | { 209 | case VDP_STATUS_OK: 210 | return "No error."; 211 | case VDP_STATUS_NO_IMPLEMENTATION: 212 | return "No backend implementation could be loaded."; 213 | case VDP_STATUS_DISPLAY_PREEMPTED: 214 | return "The display was preempted, or a fatal error occurred. The application must re-initialize VDPAU."; 215 | case VDP_STATUS_INVALID_HANDLE: 216 | return "An invalid handle value was provided."; 217 | case VDP_STATUS_INVALID_POINTER: 218 | return "An invalid pointer was provided."; 219 | case VDP_STATUS_INVALID_CHROMA_TYPE: 220 | return "An invalid/unsupported VdpChromaType value was supplied."; 221 | case VDP_STATUS_INVALID_Y_CB_CR_FORMAT: 222 | return "An invalid/unsupported VdpYCbCrFormat value was supplied."; 223 | case VDP_STATUS_INVALID_RGBA_FORMAT: 224 | return "An invalid/unsupported VdpRGBAFormat value was supplied."; 225 | case VDP_STATUS_INVALID_INDEXED_FORMAT: 226 | return "An invalid/unsupported VdpIndexedFormat value was supplied."; 227 | case VDP_STATUS_INVALID_COLOR_STANDARD: 228 | return "An invalid/unsupported VdpColorStandard value was supplied."; 229 | case VDP_STATUS_INVALID_COLOR_TABLE_FORMAT: 230 | return "An invalid/unsupported VdpColorTableFormat value was supplied."; 231 | case VDP_STATUS_INVALID_BLEND_FACTOR: 232 | return "An invalid/unsupported VdpOutputSurfaceRenderBlendFactor value was supplied."; 233 | case VDP_STATUS_INVALID_BLEND_EQUATION: 234 | return "An invalid/unsupported VdpOutputSurfaceRenderBlendEquation value was supplied."; 235 | case VDP_STATUS_INVALID_FLAG: 236 | return "An invalid/unsupported flag value/combination was supplied."; 237 | case VDP_STATUS_INVALID_DECODER_PROFILE: 238 | return "An invalid/unsupported VdpDecoderProfile value was supplied."; 239 | case VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE: 240 | return "An invalid/unsupported VdpVideoMixerFeature value was supplied."; 241 | case VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER: 242 | return "An invalid/unsupported VdpVideoMixerParameter value was supplied."; 243 | case VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE: 244 | return "An invalid/unsupported VdpVideoMixerAttribute value was supplied."; 245 | case VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE: 246 | return "An invalid/unsupported VdpVideoMixerPictureStructure value was supplied."; 247 | case VDP_STATUS_INVALID_FUNC_ID: 248 | return "An invalid/unsupported VdpFuncId value was supplied."; 249 | case VDP_STATUS_INVALID_SIZE: 250 | return "The size of a supplied object does not match the object it is being used with."; 251 | case VDP_STATUS_INVALID_VALUE: 252 | return "An invalid/unsupported value was supplied."; 253 | case VDP_STATUS_INVALID_STRUCT_VERSION: 254 | return "An invalid/unsupported structure version was specified in a versioned structure."; 255 | case VDP_STATUS_RESOURCES: 256 | return "The system does not have enough resources to complete the requested operation at this time."; 257 | case VDP_STATUS_HANDLE_DEVICE_MISMATCH: 258 | return "The set of handles supplied are not all related to the same VdpDevice."; 259 | case VDP_STATUS_ERROR: 260 | return "A catch-all error, used when no other error code applies."; 261 | default: 262 | return "Unknown Error"; 263 | } 264 | } 265 | 266 | VdpStatus vdp_get_api_version(uint32_t *api_version) 267 | { 268 | if (!api_version) 269 | return VDP_STATUS_INVALID_POINTER; 270 | 271 | *api_version = 1; 272 | return VDP_STATUS_OK; 273 | } 274 | 275 | VdpStatus vdp_get_information_string(char const **information_string) 276 | { 277 | if (!information_string) 278 | return VDP_STATUS_INVALID_POINTER; 279 | 280 | *information_string = "sunxi VDPAU Driver"; 281 | return VDP_STATUS_OK; 282 | } 283 | 284 | -------------------------------------------------------------------------------- /handles.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "vdpau_private.h" 24 | 25 | #define INITIAL_SIZE 16 26 | 27 | static struct 28 | { 29 | void **data; 30 | size_t size; 31 | pthread_rwlock_t lock; 32 | } ht = { .lock = PTHREAD_RWLOCK_INITIALIZER }; 33 | 34 | void *handle_create(size_t size, VdpHandle *handle) 35 | { 36 | *handle = VDP_INVALID_HANDLE; 37 | 38 | if (pthread_rwlock_wrlock(&ht.lock)) 39 | return NULL; 40 | 41 | unsigned int index; 42 | void *data = NULL; 43 | 44 | for (index = 0; index < ht.size; index++) 45 | if (ht.data[index] == NULL) 46 | break; 47 | 48 | if (index >= ht.size) 49 | { 50 | int new_size = ht.size ? ht.size * 2 : INITIAL_SIZE; 51 | void **new_data = realloc(ht.data, new_size * sizeof(void *)); 52 | if (!new_data) 53 | goto out; 54 | 55 | memset(new_data + ht.size, 0, (new_size - ht.size) * sizeof(void *)); 56 | ht.data = new_data; 57 | ht.size = new_size; 58 | } 59 | 60 | data = calloc(1, size); 61 | if (!data) 62 | goto out; 63 | 64 | ht.data[index] = data; 65 | *handle = index + 1; 66 | 67 | out: 68 | pthread_rwlock_unlock(&ht.lock); 69 | return data; 70 | } 71 | 72 | void *handle_get(VdpHandle handle) 73 | { 74 | if (handle == VDP_INVALID_HANDLE) 75 | return NULL; 76 | 77 | if (pthread_rwlock_rdlock(&ht.lock)) 78 | return NULL; 79 | 80 | unsigned int index = handle - 1; 81 | void *data = NULL; 82 | 83 | if (index < ht.size) 84 | data = ht.data[index]; 85 | 86 | pthread_rwlock_unlock(&ht.lock); 87 | return data; 88 | } 89 | 90 | void handle_destroy(VdpHandle handle) 91 | { 92 | if (pthread_rwlock_wrlock(&ht.lock)) 93 | return; 94 | 95 | unsigned int index = handle - 1; 96 | 97 | if (index < ht.size) 98 | { 99 | free(ht.data[index]); 100 | ht.data[index] = NULL; 101 | } 102 | 103 | pthread_rwlock_unlock(&ht.lock); 104 | } 105 | -------------------------------------------------------------------------------- /kernel-headers/README: -------------------------------------------------------------------------------- 1 | Various sunxi-specific kernel header files from sunxi kernel sources at 2 | https://github.com/linux-sunxi/linux-sunxi 3 | https://github.com/allwinner-zh/linux-3.4-sunxi 4 | -------------------------------------------------------------------------------- /kernel-headers/drv_display.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-sunxi/libvdpau-sunxi/ebdf7844efbb997a1e858600ae76c90985ea865d/kernel-headers/drv_display.h -------------------------------------------------------------------------------- /kernel-headers/g2d_driver.h: -------------------------------------------------------------------------------- 1 | /* g2d_driver.h 2 | * 3 | * Copyright (c) 2011 xxxx Electronics 4 | * 2011 Yupu Tang 5 | * 6 | * @ F23 G2D driver 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 21 | */ 22 | 23 | #ifndef __G2D_DRIVER_H 24 | #define __G2D_DRIVER_H 25 | 26 | #ifndef __G2D_BSP_DRV_H 27 | #define __G2D_BSP_DRV_H 28 | 29 | #define __s32 int 30 | #define __u32 unsigned int 31 | 32 | /* mixer data format */ 33 | typedef enum { 34 | /* share data format */ 35 | G2D_FMT_ARGB_AYUV8888 = (0x0), 36 | G2D_FMT_BGRA_VUYA8888 = (0x1), 37 | G2D_FMT_ABGR_AVUY8888 = (0x2), 38 | G2D_FMT_RGBA_YUVA8888 = (0x3), 39 | 40 | G2D_FMT_XRGB8888 = (0x4), 41 | G2D_FMT_BGRX8888 = (0x5), 42 | G2D_FMT_XBGR8888 = (0x6), 43 | G2D_FMT_RGBX8888 = (0x7), 44 | 45 | G2D_FMT_ARGB4444 = (0x8), 46 | G2D_FMT_ABGR4444 = (0x9), 47 | G2D_FMT_RGBA4444 = (0xA), 48 | G2D_FMT_BGRA4444 = (0xB), 49 | 50 | G2D_FMT_ARGB1555 = (0xC), 51 | G2D_FMT_ABGR1555 = (0xD), 52 | G2D_FMT_RGBA5551 = (0xE), 53 | G2D_FMT_BGRA5551 = (0xF), 54 | 55 | G2D_FMT_RGB565 = (0x10), 56 | G2D_FMT_BGR565 = (0x11), 57 | 58 | G2D_FMT_IYUV422 = (0x12), 59 | 60 | G2D_FMT_8BPP_MONO = (0x13), 61 | G2D_FMT_4BPP_MONO = (0x14), 62 | G2D_FMT_2BPP_MONO = (0x15), 63 | G2D_FMT_1BPP_MONO = (0x16), 64 | 65 | G2D_FMT_PYUV422UVC = (0x17), 66 | G2D_FMT_PYUV420UVC = (0x18), 67 | G2D_FMT_PYUV411UVC = (0x19), 68 | 69 | /* just for output format */ 70 | G2D_FMT_PYUV422 = (0x1A), 71 | G2D_FMT_PYUV420 = (0x1B), 72 | G2D_FMT_PYUV411 = (0x1C), 73 | 74 | /* just for input format */ 75 | G2D_FMT_8BPP_PALETTE = (0x1D), 76 | G2D_FMT_4BPP_PALETTE = (0x1E), 77 | G2D_FMT_2BPP_PALETTE = (0x1F), 78 | G2D_FMT_1BPP_PALETTE = (0x20), 79 | 80 | }g2d_data_fmt; 81 | 82 | /* pixel sequence in double word */ 83 | typedef enum { 84 | G2D_SEQ_NORMAL = 0x0, 85 | 86 | /* for interleaved yuv422 */ 87 | G2D_SEQ_VYUY = 0x1, /* pixel 0在低16位 */ 88 | G2D_SEQ_YVYU = 0x2, /* pixel 1在低16位 */ 89 | 90 | /* for uv_combined yuv420 */ 91 | G2D_SEQ_VUVU = 0x3, 92 | 93 | /* for 16bpp rgb */ 94 | G2D_SEQ_P10 = 0x4, /* pixel 0在低16位 */ 95 | G2D_SEQ_P01 = 0x5, /* pixel 1在低16位 */ 96 | 97 | /* planar format or 8bpp rgb */ 98 | G2D_SEQ_P3210 = 0x6, /* pixel 0在低8位 */ 99 | G2D_SEQ_P0123 = 0x7, /* pixel 3在低8位 */ 100 | 101 | /* for 4bpp rgb */ 102 | G2D_SEQ_P76543210 = 0x8, /* 7,6,5,4,3,2,1,0 */ 103 | G2D_SEQ_P67452301 = 0x9, /* 6,7,4,5,2,3,0,1 */ 104 | G2D_SEQ_P10325476 = 0xA, /* 1,0,3,2,5,4,7,6 */ 105 | G2D_SEQ_P01234567 = 0xB, /* 0,1,2,3,4,5,6,7 */ 106 | 107 | /* for 2bpp rgb */ 108 | G2D_SEQ_2BPP_BIG_BIG = 0xC, /* 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 */ 109 | G2D_SEQ_2BPP_BIG_LITTER = 0xD, /* 12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3 */ 110 | G2D_SEQ_2BPP_LITTER_BIG = 0xE, /* 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12 */ 111 | G2D_SEQ_2BPP_LITTER_LITTER = 0xF, /* 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 */ 112 | 113 | /* for 1bpp rgb */ 114 | G2D_SEQ_1BPP_BIG_BIG = 0x10, /* 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 */ 115 | G2D_SEQ_1BPP_BIG_LITTER = 0x11, /* 24,25,26,27,28,29,30,31,16,17,18,19,20,21,22,23,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7 */ 116 | G2D_SEQ_1BPP_LITTER_BIG = 0x12, /* 7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24 */ 117 | G2D_SEQ_1BPP_LITTER_LITTER = 0x13, /* 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 */ 118 | }g2d_pixel_seq; 119 | 120 | 121 | typedef enum { 122 | G2D_FIL_NONE = 0x00000000, 123 | G2D_FIL_PIXEL_ALPHA = 0x00000001, 124 | G2D_FIL_PLANE_ALPHA = 0x00000002, 125 | G2D_FIL_MULTI_ALPHA = 0x00000004, 126 | }g2d_fillrect_flags; 127 | 128 | typedef enum { 129 | 130 | G2D_BLT_NONE = 0x00000000, 131 | G2D_BLT_PIXEL_ALPHA = 0x00000001, 132 | G2D_BLT_PLANE_ALPHA = 0x00000002, 133 | G2D_BLT_MULTI_ALPHA = 0x00000004, 134 | G2D_BLT_SRC_COLORKEY = 0x00000008, 135 | G2D_BLT_DST_COLORKEY = 0x00000010, 136 | G2D_BLT_FLIP_HORIZONTAL = 0x00000020, 137 | G2D_BLT_FLIP_VERTICAL = 0x00000040, 138 | G2D_BLT_ROTATE90 = 0x00000080, 139 | G2D_BLT_ROTATE180 = 0x00000100, 140 | G2D_BLT_ROTATE270 = 0x00000200, 141 | G2D_BLT_MIRROR45 = 0x00000400, 142 | G2D_BLT_MIRROR135 = 0x00000800, 143 | }g2d_blt_flags; 144 | 145 | /* flip rectangle struct */ 146 | typedef struct { 147 | __s32 x; /* left top point coordinate x */ 148 | __s32 y; /* left top point coordinate y */ 149 | __u32 w; /* rectangle width */ 150 | __u32 h; /* rectangle height */ 151 | }g2d_rect; 152 | 153 | /* image struct */ 154 | typedef struct { 155 | __u32 addr[3]; /* base addr of image frame buffer in byte */ 156 | __u32 w; /* width of image frame buffer in pixel */ 157 | __u32 h; /* height of image frame buffer in pixel */ 158 | g2d_data_fmt format; /* pixel format of image frame buffer */ 159 | g2d_pixel_seq pixel_seq; /* pixel sequence of image frame buffer */ 160 | }g2d_image; 161 | 162 | typedef struct { 163 | g2d_fillrect_flags flag; 164 | g2d_image dst_image; 165 | g2d_rect dst_rect; 166 | 167 | __u32 color; /* fill color */ 168 | __u32 alpha; /* plane alpha value */ 169 | 170 | }g2d_fillrect; 171 | 172 | typedef struct { 173 | g2d_blt_flags flag; 174 | g2d_image src_image; 175 | g2d_rect src_rect; 176 | 177 | g2d_image dst_image; 178 | __s32 dst_x; /* left top point coordinate x of dst rect */ 179 | __s32 dst_y; /* left top point coordinate y of dst rect */ 180 | 181 | __u32 color; /* colorkey color */ 182 | __u32 alpha; /* plane alpha value */ 183 | 184 | }g2d_blt; 185 | 186 | typedef struct { 187 | g2d_blt_flags flag; 188 | g2d_image src_image; 189 | g2d_rect src_rect; 190 | 191 | g2d_image dst_image; 192 | g2d_rect dst_rect; 193 | 194 | __u32 color; /* colorkey color */ 195 | __u32 alpha; /* plane alpha value */ 196 | 197 | }g2d_stretchblt; 198 | 199 | typedef struct { 200 | __u32 flag; /* 光栅操作码 */ 201 | g2d_image dst_image; 202 | g2d_rect dst_rect; 203 | 204 | g2d_image src_image; 205 | __u32 src_x; 206 | __u32 src_y; 207 | 208 | g2d_image mask_image; 209 | __u32 mask_x; 210 | __u32 mask_y; 211 | 212 | }g2d_maskblt; 213 | 214 | typedef struct { 215 | __u32 *pbuffer; 216 | __u32 size; 217 | 218 | }g2d_palette; 219 | 220 | #endif /*__G2D_BSP_DRV_H*/ 221 | 222 | typedef enum 223 | { 224 | G2D_CMD_BITBLT = 0x50, 225 | G2D_CMD_FILLRECT = 0x51, 226 | G2D_CMD_STRETCHBLT = 0x52, 227 | G2D_CMD_PALETTE_TBL = 0x53, 228 | 229 | G2D_CMD_MEM_REQUEST = 0x59, 230 | G2D_CMD_MEM_RELEASE = 0x5A, 231 | G2D_CMD_MEM_GETADR = 0x5B, 232 | G2D_CMD_MEM_SELIDX = 0x5C, 233 | }g2d_cmd; 234 | 235 | #endif /* __G2D_DRIVER_H */ 236 | 237 | -------------------------------------------------------------------------------- /kernel-headers/sunxi_disp_ioctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007-2012 Allwinner Technology Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 | * MA 02111-1307 USA 18 | */ 19 | 20 | #ifndef __SUNXI_DISP_IOCTL_H__ 21 | #define __SUNXI_DISP_IOCTL_H__ 22 | 23 | #define __bool signed char 24 | #define __u32 uint32_t 25 | #define __u8 uint8_t 26 | #define __s32 int32_t 27 | #define __u16 uint16_t 28 | 29 | /* for tracking the ioctls API/ABI */ 30 | #define SUNXI_DISP_VERSION_MAJOR 1 31 | #define SUNXI_DISP_VERSION_MINOR 0 32 | 33 | #define SUNXI_DISP_VERSION ((SUNXI_DISP_VERSION_MAJOR << 16) | SUNXI_DISP_VERSION_MINOR) 34 | #define SUNXI_DISP_VERSION_MAJOR_GET(x) (((x) >> 16) & 0x7FFF) 35 | #define SUNXI_DISP_VERSION_MINOR_GET(x) ((x) & 0xFFFF) 36 | 37 | typedef struct { 38 | __u8 alpha; 39 | __u8 red; 40 | __u8 green; 41 | __u8 blue; 42 | } __disp_color_t; 43 | typedef struct { 44 | __s32 x; 45 | __s32 y; 46 | __u32 width; 47 | __u32 height; 48 | } __disp_rect_t; 49 | typedef struct { 50 | __u32 width; 51 | __u32 height; 52 | } __disp_rectsz_t; 53 | typedef struct { 54 | __s32 x; 55 | __s32 y; 56 | } __disp_pos_t; 57 | 58 | typedef enum { 59 | DISP_FORMAT_1BPP = 0x0, 60 | DISP_FORMAT_2BPP = 0x1, 61 | DISP_FORMAT_4BPP = 0x2, 62 | DISP_FORMAT_8BPP = 0x3, 63 | DISP_FORMAT_RGB655 = 0x4, 64 | DISP_FORMAT_RGB565 = 0x5, 65 | DISP_FORMAT_RGB556 = 0x6, 66 | DISP_FORMAT_ARGB1555 = 0x7, 67 | DISP_FORMAT_RGBA5551 = 0x8, 68 | DISP_FORMAT_ARGB888 = 0x9, /* alpha padding to 0xff */ 69 | DISP_FORMAT_ARGB8888 = 0xa, 70 | DISP_FORMAT_RGB888 = 0xb, 71 | DISP_FORMAT_ARGB4444 = 0xc, 72 | 73 | DISP_FORMAT_YUV444 = 0x10, 74 | DISP_FORMAT_YUV422 = 0x11, 75 | DISP_FORMAT_YUV420 = 0x12, 76 | DISP_FORMAT_YUV411 = 0x13, 77 | DISP_FORMAT_CSIRGB = 0x14, 78 | } __disp_pixel_fmt_t; 79 | 80 | typedef enum { 81 | /* interleaved,1 address */ 82 | DISP_MOD_INTERLEAVED = 0x1, 83 | /* 84 | * No macroblock plane mode, 3 address, RGB/YUV each channel were stored 85 | */ 86 | DISP_MOD_NON_MB_PLANAR = 0x0, 87 | /* No macroblock UV packaged mode, 2 address, Y and UV were stored */ 88 | DISP_MOD_NON_MB_UV_COMBINED = 0x2, 89 | /* Macroblock plane mode, 3 address,RGB/YUV each channel were stored */ 90 | DISP_MOD_MB_PLANAR = 0x4, 91 | /* Macroblock UV packaged mode, 2 address, Y and UV were stored */ 92 | DISP_MOD_MB_UV_COMBINED = 0x6, 93 | } __disp_pixel_mod_t; 94 | 95 | typedef enum { 96 | /* for interleave argb8888 */ 97 | DISP_SEQ_ARGB = 0x0, /* A at a high level */ 98 | DISP_SEQ_BGRA = 0x2, 99 | 100 | /* for interleaved yuv422 */ 101 | DISP_SEQ_UYVY = 0x3, 102 | DISP_SEQ_YUYV = 0x4, 103 | DISP_SEQ_VYUY = 0x5, 104 | DISP_SEQ_YVYU = 0x6, 105 | 106 | /* for interleaved yuv444 */ 107 | DISP_SEQ_AYUV = 0x7, 108 | DISP_SEQ_VUYA = 0x8, 109 | 110 | /* for uv_combined yuv420 */ 111 | DISP_SEQ_UVUV = 0x9, 112 | DISP_SEQ_VUVU = 0xa, 113 | 114 | /* for 16bpp rgb */ 115 | DISP_SEQ_P10 = 0xd, /* p1 high */ 116 | DISP_SEQ_P01 = 0xe, /* p0 high */ 117 | 118 | /* for planar format or 8bpp rgb */ 119 | DISP_SEQ_P3210 = 0xf, /* p3 high */ 120 | DISP_SEQ_P0123 = 0x10, /* p0 high */ 121 | 122 | /* for 4bpp rgb */ 123 | DISP_SEQ_P76543210 = 0x11, 124 | DISP_SEQ_P67452301 = 0x12, 125 | DISP_SEQ_P10325476 = 0x13, 126 | DISP_SEQ_P01234567 = 0x14, 127 | 128 | /* for 2bpp rgb */ 129 | /* 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 */ 130 | DISP_SEQ_2BPP_BIG_BIG = 0x15, 131 | /* 12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3 */ 132 | DISP_SEQ_2BPP_BIG_LITTER = 0x16, 133 | /* 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12 */ 134 | DISP_SEQ_2BPP_LITTER_BIG = 0x17, 135 | /* 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 */ 136 | DISP_SEQ_2BPP_LITTER_LITTER = 0x18, 137 | 138 | /* for 1bpp rgb */ 139 | /* 140 | * 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16, 141 | * 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 142 | */ 143 | DISP_SEQ_1BPP_BIG_BIG = 0x19, 144 | /* 145 | * 24,25,26,27,28,29,30,31,16,17,18,19,20,21,22,23, 146 | * 8, 9,10,11,12,13,14,15, 0, 1, 2, 3, 4, 5, 6, 7 147 | */ 148 | DISP_SEQ_1BPP_BIG_LITTER = 0x1a, 149 | /* 150 | * 7, 6, 5, 4, 3, 2, 1, 0,15,14,13,12,11,10, 9, 8, 151 | * 23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24 152 | */ 153 | DISP_SEQ_1BPP_LITTER_BIG = 0x1b, 154 | /* 155 | * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, 156 | * 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 157 | */ 158 | DISP_SEQ_1BPP_LITTER_LITTER = 0x1c, 159 | } __disp_pixel_seq_t; 160 | 161 | typedef enum { 162 | DISP_3D_SRC_MODE_TB = 0x0, /* top bottom */ 163 | DISP_3D_SRC_MODE_FP = 0x1, /* frame packing */ 164 | DISP_3D_SRC_MODE_SSF = 0x2, /* side by side full */ 165 | DISP_3D_SRC_MODE_SSH = 0x3, /* side by side half */ 166 | DISP_3D_SRC_MODE_LI = 0x4, /* line interleaved */ 167 | } __disp_3d_src_mode_t; 168 | 169 | typedef enum { 170 | DISP_3D_OUT_MODE_CI_1 = 0x5, /* column interlaved 1 */ 171 | DISP_3D_OUT_MODE_CI_2 = 0x6, /* column interlaved 2 */ 172 | DISP_3D_OUT_MODE_CI_3 = 0x7, /* column interlaved 3 */ 173 | DISP_3D_OUT_MODE_CI_4 = 0x8, /* column interlaved 4 */ 174 | DISP_3D_OUT_MODE_LIRGB = 0x9, /* line interleaved rgb */ 175 | 176 | DISP_3D_OUT_MODE_TB = 0x0, /* top bottom */ 177 | DISP_3D_OUT_MODE_FP = 0x1, /* frame packing */ 178 | DISP_3D_OUT_MODE_SSF = 0x2, /* side by side full */ 179 | DISP_3D_OUT_MODE_SSH = 0x3, /* side by side half */ 180 | DISP_3D_OUT_MODE_LI = 0x4, /* line interleaved */ 181 | DISP_3D_OUT_MODE_FA = 0xa, /* field alternative */ 182 | } __disp_3d_out_mode_t; 183 | 184 | typedef enum { 185 | DISP_BT601 = 0, 186 | DISP_BT709 = 1, 187 | DISP_YCC = 2, 188 | DISP_VXYCC = 3, 189 | } __disp_cs_mode_t; 190 | 191 | typedef enum { 192 | DISP_COLOR_RANGE_16_255 = 0, 193 | DISP_COLOR_RANGE_0_255 = 1, 194 | DISP_COLOR_RANGE_16_235 = 2, 195 | } __disp_color_range_t; 196 | 197 | typedef enum { 198 | DISP_OUTPUT_TYPE_NONE = 0, 199 | DISP_OUTPUT_TYPE_LCD = 1, 200 | DISP_OUTPUT_TYPE_TV = 2, 201 | DISP_OUTPUT_TYPE_HDMI = 4, 202 | DISP_OUTPUT_TYPE_VGA = 8, 203 | } __disp_output_type_t; 204 | 205 | typedef enum { 206 | DISP_TV_NONE = 0, 207 | DISP_TV_CVBS = 1, 208 | DISP_TV_YPBPR = 2, 209 | DISP_TV_SVIDEO = 4, 210 | } __disp_tv_output_t; 211 | 212 | typedef enum { 213 | DISP_TV_MOD_480I = 0, 214 | DISP_TV_MOD_576I = 1, 215 | DISP_TV_MOD_480P = 2, 216 | DISP_TV_MOD_576P = 3, 217 | DISP_TV_MOD_720P_50HZ = 4, 218 | DISP_TV_MOD_720P_60HZ = 5, 219 | DISP_TV_MOD_1080I_50HZ = 6, 220 | DISP_TV_MOD_1080I_60HZ = 7, 221 | DISP_TV_MOD_1080P_24HZ = 8, 222 | DISP_TV_MOD_1080P_50HZ = 9, 223 | DISP_TV_MOD_1080P_60HZ = 0xa, 224 | DISP_TV_MOD_1080P_24HZ_3D_FP = 0x17, 225 | DISP_TV_MOD_720P_50HZ_3D_FP = 0x18, 226 | DISP_TV_MOD_720P_60HZ_3D_FP = 0x19, 227 | DISP_TV_MOD_PAL = 0xb, 228 | DISP_TV_MOD_PAL_SVIDEO = 0xc, 229 | DISP_TV_MOD_NTSC = 0xe, 230 | DISP_TV_MOD_NTSC_SVIDEO = 0xf, 231 | DISP_TV_MOD_PAL_M = 0x11, 232 | DISP_TV_MOD_PAL_M_SVIDEO = 0x12, 233 | DISP_TV_MOD_PAL_NC = 0x14, 234 | DISP_TV_MOD_PAL_NC_SVIDEO = 0x15, 235 | 236 | DISP_TV_MOD_H1360_V768_60HZ = 0x1a, 237 | DISP_TV_MOD_H1280_V1024_60HZ = 0x1b, 238 | 239 | DISP_TV_MODE_NUM = 0x1c, 240 | 241 | /* Reserved, do not use in fex files */ 242 | DISP_TV_MODE_EDID = 0xff 243 | } __disp_tv_mode_t; 244 | 245 | typedef enum { 246 | DISP_TV_DAC_SRC_COMPOSITE = 0, 247 | DISP_TV_DAC_SRC_LUMA = 1, 248 | DISP_TV_DAC_SRC_CHROMA = 2, 249 | DISP_TV_DAC_SRC_Y = 4, 250 | DISP_TV_DAC_SRC_PB = 5, 251 | DISP_TV_DAC_SRC_PR = 6, 252 | DISP_TV_DAC_SRC_NONE = 7, 253 | } __disp_tv_dac_source; 254 | 255 | typedef enum { 256 | DISP_VGA_H1680_V1050 = 0, 257 | DISP_VGA_H1440_V900 = 1, 258 | DISP_VGA_H1360_V768 = 2, 259 | DISP_VGA_H1280_V1024 = 3, 260 | DISP_VGA_H1024_V768 = 4, 261 | DISP_VGA_H800_V600 = 5, 262 | DISP_VGA_H640_V480 = 6, 263 | DISP_VGA_H1440_V900_RB = 7, /* not support yet */ 264 | DISP_VGA_H1680_V1050_RB = 8, /* not support yet */ 265 | DISP_VGA_H1920_V1080_RB = 9, 266 | DISP_VGA_H1920_V1080 = 0xa, 267 | DISP_VGA_H1280_V720 = 0xb, 268 | DISP_VGA_MODE_NUM = 0xc, 269 | } __disp_vga_mode_t; 270 | 271 | typedef enum { 272 | DISP_LCDC_SRC_DE_CH1 = 0, 273 | DISP_LCDC_SRC_DE_CH2 = 1, 274 | DISP_LCDC_SRC_DMA = 2, 275 | DISP_LCDC_SRC_WHITE = 3, 276 | DISP_LCDC_SRC_BLACK = 4, 277 | DISP_LCDC_SRC_BLUT = 5, 278 | } __disp_lcdc_src_t; 279 | 280 | typedef enum { 281 | DISP_LAYER_WORK_MODE_NORMAL = 0, /* normal work mode */ 282 | DISP_LAYER_WORK_MODE_PALETTE = 1, /* palette work mode */ 283 | /* internal frame buffer work mode */ 284 | DISP_LAYER_WORK_MODE_INTER_BUF = 2, 285 | DISP_LAYER_WORK_MODE_GAMMA = 3, /* gamma correction work mode */ 286 | DISP_LAYER_WORK_MODE_SCALER = 4, /* scaler work mode */ 287 | } __disp_layer_work_mode_t; 288 | 289 | typedef enum { 290 | DISP_VIDEO_NATUAL = 0, 291 | DISP_VIDEO_SOFT = 1, 292 | DISP_VIDEO_VERYSOFT = 2, 293 | DISP_VIDEO_SHARP = 3, 294 | DISP_VIDEO_VERYSHARP = 4 295 | } __disp_video_smooth_t; 296 | 297 | typedef enum { 298 | DISP_HWC_MOD_H32_V32_8BPP = 0, 299 | DISP_HWC_MOD_H64_V64_2BPP = 1, 300 | DISP_HWC_MOD_H64_V32_4BPP = 2, 301 | DISP_HWC_MOD_H32_V64_4BPP = 3, 302 | } __disp_hwc_mode_t; 303 | 304 | typedef enum { 305 | DISP_EXIT_MODE_CLEAN_ALL = 0, 306 | DISP_EXIT_MODE_CLEAN_PARTLY = 1, /* only clean interrupt temply */ 307 | } __disp_exit_mode_t; 308 | 309 | typedef enum { /* only for debug!!! */ 310 | DISP_REG_SCALER0 = 0, 311 | DISP_REG_SCALER1 = 1, 312 | DISP_REG_IMAGE0 = 2, 313 | DISP_REG_IMAGE1 = 3, 314 | DISP_REG_LCDC0 = 4, 315 | DISP_REG_LCDC1 = 5, 316 | DISP_REG_TVEC0 = 6, 317 | DISP_REG_TVEC1 = 7, 318 | DISP_REG_CCMU = 8, 319 | DISP_REG_PIOC = 9, 320 | DISP_REG_PWM = 10, 321 | } __disp_reg_index_t; 322 | 323 | typedef struct { 324 | /* 325 | * The way these are treated today, these are physical addresses. Are 326 | * there any actual userspace applications out there that use this? 327 | * -- libv. 328 | */ 329 | /* 330 | * the contents of the frame buffer address for rgb type only addr[0] 331 | * valid 332 | */ 333 | __u32 addr[3]; 334 | __disp_rectsz_t size; /* unit is pixel */ 335 | __disp_pixel_fmt_t format; 336 | __disp_pixel_seq_t seq; 337 | __disp_pixel_mod_t mode; 338 | /* 339 | * blue red color swap flag, FALSE:RGB; TRUE:BGR,only used in rgb format 340 | */ 341 | __bool br_swap; 342 | __disp_cs_mode_t cs_mode; /* color space */ 343 | __bool b_trd_src; /* if 3d source, used for scaler mode layer */ 344 | /* source 3d mode, used for scaler mode layer */ 345 | __disp_3d_src_mode_t trd_mode; 346 | __u32 trd_right_addr[3]; /* used when in frame packing 3d mode */ 347 | } __disp_fb_t; 348 | 349 | typedef struct { 350 | __disp_layer_work_mode_t mode; /* layer work mode */ 351 | __bool b_from_screen; 352 | /* 353 | * layer pipe,0/1,if in scaler mode, scaler0 must be pipe0, 354 | * scaler1 must be pipe1 355 | */ 356 | __u8 pipe; 357 | /* 358 | * layer priority,can get layer prio,but never set layer prio. 359 | * From bottom to top, priority from low to high 360 | */ 361 | __u8 prio; 362 | __bool alpha_en; /* layer global alpha enable */ 363 | __u16 alpha_val; /* layer global alpha value */ 364 | __bool ck_enable; /* layer color key enable */ 365 | /* framebuffer source window,only care x,y if is not scaler mode */ 366 | __disp_rect_t src_win; 367 | __disp_rect_t scn_win; /* screen window */ 368 | __disp_fb_t fb; /* framebuffer */ 369 | __bool b_trd_out; /* if output 3d mode, used for scaler mode layer */ 370 | /* output 3d mode, used for scaler mode layer */ 371 | __disp_3d_out_mode_t out_trd_mode; 372 | } __disp_layer_info_t; 373 | 374 | typedef struct { 375 | __disp_color_t ck_max; 376 | __disp_color_t ck_min; 377 | /* 378 | * 0/1:always match; 379 | * 2:match if min<=color<=max; 380 | * 3:match if color>max or colormax or colormax or colormax or color 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "vdpau_private.h" 24 | 25 | static const uint8_t zigzag_scan[64] = 26 | { 27 | 0, 1, 5, 6, 14, 15, 27, 28, 28 | 2, 4, 7, 13, 16, 26, 29, 42, 29 | 3, 8, 12, 17, 25, 30, 41, 43, 30 | 9, 11, 18, 24, 31, 40, 44, 53, 31 | 10, 19, 23, 32, 39, 45, 52, 54, 32 | 20, 22, 33, 38, 46, 51, 55, 60, 33 | 21, 34, 37, 47, 50, 56, 59, 61, 34 | 35, 36, 48, 49, 57, 58, 62, 63 35 | }; 36 | 37 | static int mpeg_find_startcode(const uint8_t *data, int len) 38 | { 39 | int pos = 0; 40 | while (pos < len) 41 | { 42 | int zeros = 0; 43 | for ( ; pos < len; pos++) 44 | { 45 | if (data[pos] == 0x00) 46 | zeros++; 47 | else if (data[pos] == 0x01 && zeros >= 2) 48 | { 49 | pos++; 50 | break; 51 | } 52 | else 53 | zeros = 0; 54 | } 55 | 56 | uint8_t marker = data[pos++]; 57 | 58 | if (marker >= 0x01 && marker <= 0xaf) 59 | return pos - 4; 60 | } 61 | return 0; 62 | } 63 | 64 | static VdpStatus mpeg12_decode(decoder_ctx_t *decoder, 65 | VdpPictureInfo const *_info, 66 | const int len, 67 | video_surface_ctx_t *output) 68 | { 69 | VdpPictureInfoMPEG1Or2 const *info = (VdpPictureInfoMPEG1Or2 const *)_info; 70 | int start_offset = mpeg_find_startcode(cedrus_mem_get_pointer(decoder->data), len); 71 | 72 | VdpStatus ret = yuv_prepare(output); 73 | if (ret != VDP_STATUS_OK) 74 | return ret; 75 | 76 | int i; 77 | 78 | // activate MPEG engine 79 | void *ve_regs = cedrus_ve_get(decoder->device->cedrus, CEDRUS_ENGINE_MPEG, 0); 80 | 81 | // set quantisation tables 82 | for (i = 0; i < 64; i++) 83 | writel((uint32_t)(64 + zigzag_scan[i]) << 8 | info->intra_quantizer_matrix[i], ve_regs + VE_MPEG_IQ_MIN_INPUT); 84 | for (i = 0; i < 64; i++) 85 | writel((uint32_t)(zigzag_scan[i]) << 8 | info->non_intra_quantizer_matrix[i], ve_regs + VE_MPEG_IQ_MIN_INPUT); 86 | 87 | // set size 88 | uint16_t width = (decoder->width + 15) / 16; 89 | uint16_t height = (decoder->height + 15) / 16; 90 | writel((width << 8) | height, ve_regs + VE_MPEG_SIZE); 91 | writel(((width * 16) << 16) | (height * 16), ve_regs + VE_MPEG_FRAME_SIZE); 92 | 93 | // set picture header 94 | uint32_t pic_header = 0; 95 | pic_header |= ((info->picture_coding_type & 0xf) << 28); 96 | pic_header |= ((info->f_code[0][0] & 0xf) << 24); 97 | pic_header |= ((info->f_code[0][1] & 0xf) << 20); 98 | pic_header |= ((info->f_code[1][0] & 0xf) << 16); 99 | pic_header |= ((info->f_code[1][1] & 0xf) << 12); 100 | pic_header |= ((info->intra_dc_precision & 0x3) << 10); 101 | pic_header |= ((info->picture_structure & 0x3) << 8); 102 | pic_header |= ((info->top_field_first & 0x1) << 7); 103 | pic_header |= ((info->frame_pred_frame_dct & 0x1) << 6); 104 | pic_header |= ((info->concealment_motion_vectors & 0x1) << 5); 105 | pic_header |= ((info->q_scale_type & 0x1) << 4); 106 | pic_header |= ((info->intra_vlc_format & 0x1) << 3); 107 | pic_header |= ((info->alternate_scan & 0x1) << 2); 108 | pic_header |= ((info->full_pel_forward_vector & 0x1) << 1); 109 | pic_header |= ((info->full_pel_backward_vector & 0x1) << 0); 110 | if (decoder->profile == VDP_DECODER_PROFILE_MPEG1) 111 | pic_header |= 0x000003c0; 112 | writel(pic_header, ve_regs + VE_MPEG_PIC_HDR); 113 | 114 | // ?? 115 | writel(0x80000138 | (1 << 7), ve_regs + VE_MPEG_CTRL); 116 | if (cedrus_get_ve_version(decoder->device->cedrus) >= 0x1680) 117 | { 118 | writel((0x2 << 30) | (0x1 << 28) | (output->chroma_size / 2), ve_regs + VE_EXTRA_OUT_FMT_OFFSET); 119 | writel((0x2 << 4), ve_regs + 0x0ec); 120 | writel(output->chroma_size / 2, ve_regs + 0x0c4); 121 | writel((ALIGN(decoder->width / 2, 16) << 16) | ALIGN(decoder->width, 32), ve_regs + 0x0c8); 122 | } 123 | 124 | // set forward/backward predicion buffers 125 | if (info->forward_reference != VDP_INVALID_HANDLE) 126 | { 127 | video_surface_ctx_t *forward = handle_get(info->forward_reference); 128 | writel(cedrus_mem_get_bus_addr(forward->yuv->data), ve_regs + VE_MPEG_FWD_LUMA); 129 | writel(cedrus_mem_get_bus_addr(forward->yuv->data) + forward->luma_size, ve_regs + VE_MPEG_FWD_CHROMA); 130 | } 131 | if (info->backward_reference != VDP_INVALID_HANDLE) 132 | { 133 | video_surface_ctx_t *backward = handle_get(info->backward_reference); 134 | writel(cedrus_mem_get_bus_addr(backward->yuv->data), ve_regs + VE_MPEG_BACK_LUMA); 135 | writel(cedrus_mem_get_bus_addr(backward->yuv->data) + backward->luma_size, ve_regs + VE_MPEG_BACK_CHROMA); 136 | } 137 | 138 | // set output buffers (Luma / Croma) 139 | writel(cedrus_mem_get_bus_addr(output->yuv->data), ve_regs + VE_MPEG_REC_LUMA); 140 | writel(cedrus_mem_get_bus_addr(output->yuv->data) + output->luma_size, ve_regs + VE_MPEG_REC_CHROMA); 141 | writel(cedrus_mem_get_bus_addr(output->yuv->data), ve_regs + VE_MPEG_ROT_LUMA); 142 | writel(cedrus_mem_get_bus_addr(output->yuv->data) + output->luma_size, ve_regs + VE_MPEG_ROT_CHROMA); 143 | 144 | // set input offset in bits 145 | writel(start_offset * 8, ve_regs + VE_MPEG_VLD_OFFSET); 146 | 147 | // set input length in bits 148 | writel((len - start_offset) * 8, ve_regs + VE_MPEG_VLD_LEN); 149 | 150 | // input end 151 | uint32_t input_addr = cedrus_mem_get_bus_addr(decoder->data); 152 | writel(input_addr + VBV_SIZE - 1, ve_regs + VE_MPEG_VLD_END); 153 | 154 | // set input buffer 155 | writel((input_addr & 0x0ffffff0) | (input_addr >> 28) | (0x7 << 28), ve_regs + VE_MPEG_VLD_ADDR); 156 | 157 | // trigger 158 | writel((((decoder->profile == VDP_DECODER_PROFILE_MPEG1) ? 1 : 2) << 24) | 0x8000000f, ve_regs + VE_MPEG_TRIGGER); 159 | 160 | // wait for interrupt 161 | cedrus_ve_wait(decoder->device->cedrus, 1); 162 | 163 | // clean interrupt flag 164 | writel(0x0000c00f, ve_regs + VE_MPEG_STATUS); 165 | 166 | // stop MPEG engine 167 | cedrus_ve_put(decoder->device->cedrus); 168 | 169 | return VDP_STATUS_OK; 170 | } 171 | 172 | VdpStatus new_decoder_mpeg12(decoder_ctx_t *decoder) 173 | { 174 | decoder->decode = mpeg12_decode; 175 | return VDP_STATUS_OK; 176 | } 177 | -------------------------------------------------------------------------------- /mpeg4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "vdpau_private.h" 26 | 27 | typedef struct 28 | { 29 | const uint8_t *data; 30 | unsigned int length; 31 | unsigned int bitpos; 32 | } bitstream; 33 | 34 | static int find_startcode(bitstream *bs) 35 | { 36 | unsigned int pos, zeros = 0; 37 | for (pos = bs->bitpos / 8; pos < bs->length; pos++) 38 | { 39 | if (bs->data[pos] == 0x00) 40 | zeros++; 41 | else if (bs->data[pos] == 0x01 && zeros >= 2) 42 | { 43 | bs->bitpos = (pos + 1) * 8; 44 | return 1; 45 | } 46 | else 47 | zeros = 0; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | static uint32_t get_bits(bitstream *bs, int n) 54 | { 55 | uint32_t bits = 0; 56 | int remaining_bits = n; 57 | 58 | while (remaining_bits > 0) 59 | { 60 | int bits_in_current_byte = 8 - (bs->bitpos & 7); 61 | 62 | int trash_bits = 0; 63 | if (remaining_bits < bits_in_current_byte) 64 | trash_bits = bits_in_current_byte - remaining_bits; 65 | 66 | int useful_bits = bits_in_current_byte - trash_bits; 67 | 68 | bits = (bits << useful_bits) | (bs->data[bs->bitpos / 8] >> trash_bits); 69 | 70 | remaining_bits -= useful_bits; 71 | bs->bitpos += useful_bits; 72 | } 73 | 74 | return bits & ((1 << n) - 1); 75 | } 76 | 77 | typedef struct 78 | { 79 | cedrus_mem_t *mbh_buffer; 80 | cedrus_mem_t *dcac_buffer; 81 | cedrus_mem_t *ncf_buffer; 82 | } mpeg4_private_t; 83 | 84 | static void mpeg4_private_free(decoder_ctx_t *decoder) 85 | { 86 | mpeg4_private_t *decoder_p = (mpeg4_private_t *)decoder->private; 87 | cedrus_mem_free(decoder_p->mbh_buffer); 88 | cedrus_mem_free(decoder_p->dcac_buffer); 89 | cedrus_mem_free(decoder_p->ncf_buffer); 90 | free(decoder_p); 91 | } 92 | 93 | #define VOP_I 0 94 | #define VOP_P 1 95 | #define VOP_B 2 96 | #define VOP_S 3 97 | 98 | typedef struct 99 | { 100 | int vop_coding_type; 101 | int intra_dc_vlc_thr; 102 | int vop_quant; 103 | } vop_header; 104 | 105 | static int decode_vop_header(bitstream *bs, VdpPictureInfoMPEG4Part2 const *info, vop_header *h) 106 | { 107 | h->vop_coding_type = get_bits(bs, 2); 108 | 109 | // modulo_time_base 110 | while (get_bits(bs, 1) != 0); 111 | 112 | if (get_bits(bs, 1) != 1) 113 | VDPAU_DBG("vop header marker error"); 114 | 115 | // vop_time_increment 116 | get_bits(bs, 32 - __builtin_clz(info->vop_time_increment_resolution)); 117 | 118 | if (get_bits(bs, 1) != 1) 119 | VDPAU_DBG("vop header marker error"); 120 | 121 | // vop_coded 122 | if (!get_bits(bs, 1)) 123 | return 0; 124 | 125 | // rounding_type 126 | if (h->vop_coding_type == VOP_P) 127 | get_bits(bs, 1); 128 | 129 | h->intra_dc_vlc_thr = get_bits(bs, 3); 130 | 131 | // assume default size of 5 bits 132 | h->vop_quant = get_bits(bs, 5); 133 | 134 | // vop_fcode_forward 135 | if (h->vop_coding_type != VOP_I) 136 | get_bits(bs, 3); 137 | 138 | // vop_fcode_backward 139 | if (h->vop_coding_type == VOP_B) 140 | get_bits(bs, 3); 141 | 142 | return 1; 143 | } 144 | 145 | static VdpStatus mpeg4_decode(decoder_ctx_t *decoder, 146 | VdpPictureInfo const *_info, 147 | const int len, 148 | video_surface_ctx_t *output) 149 | { 150 | VdpPictureInfoMPEG4Part2 const *info = (VdpPictureInfoMPEG4Part2 const *)_info; 151 | mpeg4_private_t *decoder_p = (mpeg4_private_t *)decoder->private; 152 | 153 | if (!info->resync_marker_disable) 154 | { 155 | VDPAU_DBG("We can't decode VOPs with resync markers yet! Sorry"); 156 | return VDP_STATUS_ERROR; 157 | } 158 | 159 | VdpStatus ret = yuv_prepare(output); 160 | if (ret != VDP_STATUS_OK) 161 | return ret; 162 | 163 | bitstream bs = { .data = cedrus_mem_get_pointer(decoder->data), .length = len, .bitpos = 0 }; 164 | 165 | while (find_startcode(&bs)) 166 | { 167 | if (get_bits(&bs, 8) != 0xb6) 168 | continue; 169 | 170 | vop_header hdr; 171 | if (!decode_vop_header(&bs, info, &hdr)) 172 | continue; 173 | 174 | // activate MPEG engine 175 | void *ve_regs = cedrus_ve_get(decoder->device->cedrus, CEDRUS_ENGINE_MPEG, 0); 176 | 177 | // set buffers 178 | writel(cedrus_mem_get_bus_addr(decoder_p->mbh_buffer), ve_regs + VE_MPEG_MBH_ADDR); 179 | writel(cedrus_mem_get_bus_addr(decoder_p->dcac_buffer), ve_regs + VE_MPEG_DCAC_ADDR); 180 | writel(cedrus_mem_get_bus_addr(decoder_p->ncf_buffer), ve_regs + VE_MPEG_NCF_ADDR); 181 | 182 | // set output buffers 183 | writel(cedrus_mem_get_bus_addr(output->yuv->data), ve_regs + VE_MPEG_REC_LUMA); 184 | writel(cedrus_mem_get_bus_addr(output->yuv->data) + output->luma_size, ve_regs + VE_MPEG_REC_CHROMA); 185 | writel(cedrus_mem_get_bus_addr(output->yuv->data), ve_regs + VE_MPEG_ROT_LUMA); 186 | writel(cedrus_mem_get_bus_addr(output->yuv->data) + output->luma_size, ve_regs + VE_MPEG_ROT_CHROMA); 187 | 188 | // ?? 189 | writel(0x40620000, ve_regs + VE_MPEG_SDROT_CTRL); 190 | if (cedrus_get_ve_version(decoder->device->cedrus) >= 0x1680) 191 | { 192 | writel((0x2 << 30) | (0x1 << 28) | (output->chroma_size / 2), ve_regs + VE_EXTRA_OUT_FMT_OFFSET); 193 | writel((0x2 << 4), ve_regs + 0x0ec); 194 | writel(output->chroma_size / 2, ve_regs + 0x0c4); 195 | writel((ALIGN(decoder->width / 2, 16) << 16) | ALIGN(decoder->width, 32), ve_regs + 0x0c8); 196 | } 197 | 198 | // set vop header 199 | writel(((hdr.vop_coding_type == VOP_B ? 0x1 : 0x0) << 28) 200 | | (info->quant_type << 24) 201 | | (info->quarter_sample << 23) 202 | | (info->resync_marker_disable << 22) 203 | | (hdr.vop_coding_type << 18) 204 | | (info->rounding_control << 17) 205 | | (hdr.intra_dc_vlc_thr << 8) 206 | | (info->top_field_first << 7) 207 | | (info->alternate_vertical_scan_flag << 6) 208 | | ((hdr.vop_coding_type != VOP_I ? info->vop_fcode_forward : 0) << 3) 209 | | ((hdr.vop_coding_type == VOP_B ? info->vop_fcode_backward : 0) << 0) 210 | , ve_regs + VE_MPEG_VOP_HDR); 211 | 212 | // set size 213 | uint16_t width = (decoder->width + 15) / 16; 214 | uint16_t height = (decoder->height + 15) / 16; 215 | writel((((width + 1) & ~0x1) << 16) | (width << 8) | height, ve_regs + VE_MPEG_SIZE); 216 | writel(((width * 16) << 16) | (height * 16), ve_regs + VE_MPEG_FRAME_SIZE); 217 | 218 | // ?? 219 | writel(0x0, ve_regs + VE_MPEG_MBA); 220 | 221 | // enable interrupt, unknown control flags 222 | writel(0x80084118 | (1 << 7) | ((hdr.vop_coding_type == VOP_P ? 0x1 : 0x0) << 12), ve_regs + VE_MPEG_CTRL); 223 | 224 | // set quantization parameter 225 | writel(hdr.vop_quant, ve_regs + VE_MPEG_QP_INPUT); 226 | 227 | // set forward/backward predicion buffers 228 | if (info->forward_reference != VDP_INVALID_HANDLE) 229 | { 230 | video_surface_ctx_t *forward = handle_get(info->forward_reference); 231 | writel(cedrus_mem_get_bus_addr(forward->yuv->data), ve_regs + VE_MPEG_FWD_LUMA); 232 | writel(cedrus_mem_get_bus_addr(forward->yuv->data) + forward->luma_size, ve_regs + VE_MPEG_FWD_CHROMA); 233 | } 234 | if (info->backward_reference != VDP_INVALID_HANDLE) 235 | { 236 | video_surface_ctx_t *backward = handle_get(info->backward_reference); 237 | writel(cedrus_mem_get_bus_addr(backward->yuv->data), ve_regs + VE_MPEG_BACK_LUMA); 238 | writel(cedrus_mem_get_bus_addr(backward->yuv->data) + backward->luma_size, ve_regs + VE_MPEG_BACK_CHROMA); 239 | } 240 | 241 | // set trb/trd 242 | if (hdr.vop_coding_type == VOP_B) 243 | { 244 | writel((info->trb[0] << 16) | (info->trd[0] << 0), ve_regs + VE_MPEG_TRBTRD_FRAME); 245 | // unverified: 246 | writel((info->trb[1] << 16) | (info->trd[1] << 0), ve_regs + VE_MPEG_TRBTRD_FIELD); 247 | } 248 | 249 | // clear status 250 | writel(0xffffffff, ve_regs + VE_MPEG_STATUS); 251 | 252 | // set input offset in bits 253 | writel(bs.bitpos, ve_regs + VE_MPEG_VLD_OFFSET); 254 | 255 | // set input length in bits 256 | writel(len * 8 - bs.bitpos, ve_regs + VE_MPEG_VLD_LEN); 257 | 258 | // input end 259 | uint32_t input_addr = cedrus_mem_get_bus_addr(decoder->data); 260 | writel(input_addr + VBV_SIZE - 1, ve_regs + VE_MPEG_VLD_END); 261 | 262 | // set input buffer 263 | writel((input_addr & 0x0ffffff0) | (input_addr >> 28) | (0x7 << 28), ve_regs + VE_MPEG_VLD_ADDR); 264 | 265 | // trigger 266 | writel(0x8400000d | ((width * height) << 8), ve_regs + VE_MPEG_TRIGGER); 267 | 268 | cedrus_ve_wait(decoder->device->cedrus, 1); 269 | 270 | // clear status 271 | writel(readl(ve_regs + VE_MPEG_STATUS) | 0xf, ve_regs + VE_MPEG_STATUS); 272 | 273 | // stop MPEG engine 274 | cedrus_ve_put(decoder->device->cedrus); 275 | } 276 | 277 | return VDP_STATUS_OK; 278 | } 279 | 280 | VdpStatus new_decoder_mpeg4(decoder_ctx_t *decoder) 281 | { 282 | mpeg4_private_t *decoder_p = calloc(1, sizeof(mpeg4_private_t)); 283 | if (!decoder_p) 284 | goto err_priv; 285 | 286 | int width = ((decoder->width + 15) / 16); 287 | int height = ((decoder->height + 15) / 16); 288 | 289 | decoder_p->mbh_buffer = cedrus_mem_alloc(decoder->device->cedrus, height * 2048); 290 | if (!decoder_p->mbh_buffer) 291 | goto err_mbh; 292 | 293 | decoder_p->dcac_buffer = cedrus_mem_alloc(decoder->device->cedrus, width * height * 2); 294 | if (!decoder_p->dcac_buffer) 295 | goto err_dcac; 296 | 297 | decoder_p->ncf_buffer = cedrus_mem_alloc(decoder->device->cedrus, 4 * 1024); 298 | if (!decoder_p->ncf_buffer) 299 | goto err_ncf; 300 | 301 | decoder->decode = mpeg4_decode; 302 | decoder->private = decoder_p; 303 | decoder->private_free = mpeg4_private_free; 304 | 305 | return VDP_STATUS_OK; 306 | 307 | err_ncf: 308 | cedrus_mem_free(decoder_p->dcac_buffer); 309 | err_dcac: 310 | cedrus_mem_free(decoder_p->mbh_buffer); 311 | err_mbh: 312 | free(decoder_p); 313 | err_priv: 314 | return VDP_STATUS_RESOURCES; 315 | } 316 | -------------------------------------------------------------------------------- /presentation_queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include "vdpau_private.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "rgba.h" 28 | #include "sunxi_disp.h" 29 | 30 | static uint64_t get_time(void) 31 | { 32 | struct timespec tp; 33 | 34 | if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) 35 | return 0; 36 | 37 | return (uint64_t)tp.tv_sec * 1000000000ULL + (uint64_t)tp.tv_nsec; 38 | } 39 | 40 | VdpStatus vdp_presentation_queue_target_create_x11(VdpDevice device, 41 | Drawable drawable, 42 | VdpPresentationQueueTarget *target) 43 | { 44 | if (!target || !drawable) 45 | return VDP_STATUS_INVALID_POINTER; 46 | 47 | device_ctx_t *dev = handle_get(device); 48 | if (!dev) 49 | return VDP_STATUS_INVALID_HANDLE; 50 | 51 | queue_target_ctx_t *qt = handle_create(sizeof(*qt), target); 52 | if (!qt) 53 | return VDP_STATUS_RESOURCES; 54 | 55 | qt->drawable = drawable; 56 | XSetWindowBackground(dev->display, drawable, 0x000102); 57 | 58 | qt->disp = sunxi_disp_open(dev->osd_enabled); 59 | 60 | if (!qt->disp) 61 | qt->disp = sunxi_disp2_open(dev->osd_enabled); 62 | 63 | if (!qt->disp) 64 | qt->disp = sunxi_disp1_5_open(dev->osd_enabled); 65 | 66 | if (!qt->disp) 67 | return VDP_STATUS_ERROR; 68 | 69 | return VDP_STATUS_OK; 70 | } 71 | 72 | VdpStatus vdp_presentation_queue_target_destroy(VdpPresentationQueueTarget presentation_queue_target) 73 | { 74 | queue_target_ctx_t *qt = handle_get(presentation_queue_target); 75 | if (!qt) 76 | return VDP_STATUS_INVALID_HANDLE; 77 | 78 | qt->disp->close(qt->disp); 79 | 80 | handle_destroy(presentation_queue_target); 81 | 82 | return VDP_STATUS_OK; 83 | } 84 | 85 | VdpStatus vdp_presentation_queue_create(VdpDevice device, 86 | VdpPresentationQueueTarget presentation_queue_target, 87 | VdpPresentationQueue *presentation_queue) 88 | { 89 | if (!presentation_queue) 90 | return VDP_STATUS_INVALID_POINTER; 91 | 92 | device_ctx_t *dev = handle_get(device); 93 | if (!dev) 94 | return VDP_STATUS_INVALID_HANDLE; 95 | 96 | queue_target_ctx_t *qt = handle_get(presentation_queue_target); 97 | if (!qt) 98 | return VDP_STATUS_INVALID_HANDLE; 99 | 100 | queue_ctx_t *q = handle_create(sizeof(*q), presentation_queue); 101 | if (!q) 102 | return VDP_STATUS_RESOURCES; 103 | 104 | q->target = qt; 105 | q->device = dev; 106 | 107 | return VDP_STATUS_OK; 108 | } 109 | 110 | VdpStatus vdp_presentation_queue_destroy(VdpPresentationQueue presentation_queue) 111 | { 112 | queue_ctx_t *q = handle_get(presentation_queue); 113 | if (!q) 114 | return VDP_STATUS_INVALID_HANDLE; 115 | 116 | handle_destroy(presentation_queue); 117 | 118 | return VDP_STATUS_OK; 119 | } 120 | 121 | VdpStatus vdp_presentation_queue_set_background_color(VdpPresentationQueue presentation_queue, 122 | VdpColor *const background_color) 123 | { 124 | if (!background_color) 125 | return VDP_STATUS_INVALID_POINTER; 126 | 127 | queue_ctx_t *q = handle_get(presentation_queue); 128 | if (!q) 129 | return VDP_STATUS_INVALID_HANDLE; 130 | 131 | q->background.red = background_color->red; 132 | q->background.green = background_color->green; 133 | q->background.blue = background_color->blue; 134 | q->background.alpha = background_color->alpha; 135 | 136 | return VDP_STATUS_OK; 137 | } 138 | 139 | VdpStatus vdp_presentation_queue_get_background_color(VdpPresentationQueue presentation_queue, 140 | VdpColor *const background_color) 141 | { 142 | if (!background_color) 143 | return VDP_STATUS_INVALID_POINTER; 144 | 145 | queue_ctx_t *q = handle_get(presentation_queue); 146 | if (!q) 147 | return VDP_STATUS_INVALID_HANDLE; 148 | 149 | background_color->red = q->background.red; 150 | background_color->green = q->background.green; 151 | background_color->blue = q->background.blue; 152 | background_color->alpha = q->background.alpha; 153 | 154 | return VDP_STATUS_OK; 155 | } 156 | 157 | VdpStatus vdp_presentation_queue_get_time(VdpPresentationQueue presentation_queue, 158 | VdpTime *current_time) 159 | { 160 | queue_ctx_t *q = handle_get(presentation_queue); 161 | if (!q) 162 | return VDP_STATUS_INVALID_HANDLE; 163 | 164 | *current_time = get_time(); 165 | return VDP_STATUS_OK; 166 | } 167 | 168 | VdpStatus vdp_presentation_queue_display(VdpPresentationQueue presentation_queue, 169 | VdpOutputSurface surface, 170 | uint32_t clip_width, 171 | uint32_t clip_height, 172 | VdpTime earliest_presentation_time) 173 | { 174 | queue_ctx_t *q = handle_get(presentation_queue); 175 | if (!q) 176 | return VDP_STATUS_INVALID_HANDLE; 177 | 178 | output_surface_ctx_t *os = handle_get(surface); 179 | if (!os) 180 | return VDP_STATUS_INVALID_HANDLE; 181 | 182 | if (earliest_presentation_time != 0) 183 | VDPAU_DBG_ONCE("Presentation time not supported"); 184 | 185 | Window c; 186 | int x,y; 187 | XTranslateCoordinates(q->device->display, q->target->drawable, RootWindow(q->device->display, q->device->screen), 0, 0, &x, &y, &c); 188 | XClearWindow(q->device->display, q->target->drawable); 189 | 190 | if (os->vs) 191 | q->target->disp->set_video_layer(q->target->disp, x, y, clip_width, clip_height, os); 192 | else 193 | q->target->disp->close_video_layer(q->target->disp); 194 | 195 | if (!q->device->osd_enabled) 196 | return VDP_STATUS_OK; 197 | 198 | if (os->rgba.flags & RGBA_FLAG_NEEDS_CLEAR) 199 | rgba_clear(&os->rgba); 200 | 201 | if (os->rgba.flags & RGBA_FLAG_DIRTY) 202 | { 203 | rgba_flush(&os->rgba); 204 | 205 | q->target->disp->set_osd_layer(q->target->disp, x, y, clip_width, clip_height, os); 206 | } 207 | else 208 | { 209 | q->target->disp->close_osd_layer(q->target->disp); 210 | } 211 | 212 | return VDP_STATUS_OK; 213 | } 214 | 215 | VdpStatus vdp_presentation_queue_block_until_surface_idle(VdpPresentationQueue presentation_queue, 216 | VdpOutputSurface surface, 217 | VdpTime *first_presentation_time) 218 | { 219 | queue_ctx_t *q = handle_get(presentation_queue); 220 | if (!q) 221 | return VDP_STATUS_INVALID_HANDLE; 222 | 223 | output_surface_ctx_t *out = handle_get(surface); 224 | if (!out) 225 | return VDP_STATUS_INVALID_HANDLE; 226 | 227 | *first_presentation_time = get_time(); 228 | 229 | return VDP_STATUS_OK; 230 | } 231 | 232 | VdpStatus vdp_presentation_queue_query_surface_status(VdpPresentationQueue presentation_queue, 233 | VdpOutputSurface surface, 234 | VdpPresentationQueueStatus *status, 235 | VdpTime *first_presentation_time) 236 | { 237 | queue_ctx_t *q = handle_get(presentation_queue); 238 | if (!q) 239 | return VDP_STATUS_INVALID_HANDLE; 240 | 241 | output_surface_ctx_t *out = handle_get(surface); 242 | if (!out) 243 | return VDP_STATUS_INVALID_HANDLE; 244 | 245 | *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; 246 | *first_presentation_time = get_time(); 247 | 248 | return VDP_STATUS_OK; 249 | } 250 | -------------------------------------------------------------------------------- /rgba.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "vdpau_private.h" 24 | #include "rgba.h" 25 | #include "rgba_pixman.h" 26 | #include "rgba_g2d.h" 27 | 28 | static void dirty_add_rect(VdpRect *dirty, const VdpRect *rect) 29 | { 30 | dirty->x0 = min(dirty->x0, rect->x0); 31 | dirty->y0 = min(dirty->y0, rect->y0); 32 | dirty->x1 = max(dirty->x1, rect->x1); 33 | dirty->y1 = max(dirty->y1, rect->y1); 34 | } 35 | 36 | static int dirty_in_rect(const VdpRect *dirty, const VdpRect *rect) 37 | { 38 | return (dirty->x0 >= rect->x0) && (dirty->y0 >= rect->y0) && 39 | (dirty->x1 <= rect->x1) && (dirty->y1 <= rect->y1); 40 | } 41 | 42 | VdpStatus rgba_create(rgba_surface_t *rgba, 43 | device_ctx_t *device, 44 | uint32_t width, 45 | uint32_t height, 46 | VdpRGBAFormat format) 47 | { 48 | if (format != VDP_RGBA_FORMAT_B8G8R8A8 && format != VDP_RGBA_FORMAT_R8G8B8A8) 49 | return VDP_STATUS_INVALID_RGBA_FORMAT; 50 | 51 | if (width < 1 || width > 8192 || height < 1 || height > 8192) 52 | return VDP_STATUS_INVALID_SIZE; 53 | 54 | rgba->device = device; 55 | rgba->width = width; 56 | rgba->height = height; 57 | rgba->format = format; 58 | 59 | if (device->osd_enabled) 60 | { 61 | rgba->data = cedrus_mem_alloc(device->cedrus, width * height * 4); 62 | if (!rgba->data) 63 | return VDP_STATUS_RESOURCES; 64 | 65 | if(!device->g2d_enabled) 66 | vdp_pixman_ref(rgba); 67 | 68 | rgba->dirty.x0 = width; 69 | rgba->dirty.y0 = height; 70 | rgba->dirty.x1 = 0; 71 | rgba->dirty.y1 = 0; 72 | rgba_fill(rgba, NULL, 0x00000000); 73 | } 74 | 75 | return VDP_STATUS_OK; 76 | } 77 | 78 | void rgba_destroy(rgba_surface_t *rgba) 79 | { 80 | if (rgba->device->osd_enabled) 81 | { 82 | if(!rgba->device->g2d_enabled) 83 | vdp_pixman_unref(rgba); 84 | 85 | cedrus_mem_free(rgba->data); 86 | } 87 | } 88 | 89 | VdpStatus rgba_put_bits_native(rgba_surface_t *rgba, 90 | void const *const *source_data, 91 | uint32_t const *source_pitches, 92 | VdpRect const *destination_rect) 93 | { 94 | if (!rgba->device->osd_enabled) 95 | return VDP_STATUS_OK; 96 | 97 | VdpRect d_rect = {0, 0, rgba->width, rgba->height}; 98 | if (destination_rect) 99 | d_rect = *destination_rect; 100 | 101 | if ((rgba->flags & RGBA_FLAG_NEEDS_CLEAR) && !dirty_in_rect(&rgba->dirty, &d_rect)) 102 | rgba_clear(rgba); 103 | 104 | if (0 == d_rect.x0 && rgba->width == d_rect.x1 && source_pitches[0] == d_rect.x1 * 4) { 105 | // full width 106 | const int bytes_to_copy = 107 | (d_rect.x1 - d_rect.x0) * (d_rect.y1 - d_rect.y0) * 4; 108 | memcpy(cedrus_mem_get_pointer(rgba->data) + d_rect.y0 * rgba->width * 4, 109 | source_data[0], bytes_to_copy); 110 | } else { 111 | const unsigned int bytes_in_line = (d_rect.x1-d_rect.x0) * 4; 112 | unsigned int y; 113 | for (y = d_rect.y0; y < d_rect.y1; y ++) { 114 | memcpy(cedrus_mem_get_pointer(rgba->data) + (y * rgba->width + d_rect.x0) * 4, 115 | source_data[0] + (y - d_rect.y0) * source_pitches[0], 116 | bytes_in_line); 117 | } 118 | } 119 | 120 | rgba->flags &= ~RGBA_FLAG_NEEDS_CLEAR; 121 | rgba->flags |= RGBA_FLAG_DIRTY | RGBA_FLAG_NEEDS_FLUSH; 122 | dirty_add_rect(&rgba->dirty, &d_rect); 123 | 124 | return VDP_STATUS_OK; 125 | } 126 | 127 | VdpStatus rgba_put_bits_indexed(rgba_surface_t *rgba, 128 | VdpIndexedFormat source_indexed_format, 129 | void const *const *source_data, 130 | uint32_t const *source_pitch, 131 | VdpRect const *destination_rect, 132 | VdpColorTableFormat color_table_format, 133 | void const *color_table) 134 | { 135 | if (color_table_format != VDP_COLOR_TABLE_FORMAT_B8G8R8X8) 136 | return VDP_STATUS_INVALID_COLOR_TABLE_FORMAT; 137 | 138 | if (!rgba->device->osd_enabled) 139 | return VDP_STATUS_OK; 140 | 141 | int x, y; 142 | const uint32_t *colormap = color_table; 143 | const uint8_t *src_ptr = source_data[0]; 144 | uint32_t *dst_ptr = cedrus_mem_get_pointer(rgba->data); 145 | 146 | VdpRect d_rect = {0, 0, rgba->width, rgba->height}; 147 | if (destination_rect) 148 | d_rect = *destination_rect; 149 | 150 | if ((rgba->flags & RGBA_FLAG_NEEDS_CLEAR) && !dirty_in_rect(&rgba->dirty, &d_rect)) 151 | rgba_clear(rgba); 152 | 153 | dst_ptr += d_rect.y0 * rgba->width; 154 | dst_ptr += d_rect.x0; 155 | 156 | for (y = 0; y < d_rect.y1 - d_rect.y0; y++) 157 | { 158 | for (x = 0; x < d_rect.x1 - d_rect.x0; x++) 159 | { 160 | uint8_t i, a; 161 | switch (source_indexed_format) 162 | { 163 | case VDP_INDEXED_FORMAT_I8A8: 164 | i = src_ptr[x * 2]; 165 | a = src_ptr[x * 2 + 1]; 166 | break; 167 | case VDP_INDEXED_FORMAT_A8I8: 168 | a = src_ptr[x * 2]; 169 | i = src_ptr[x * 2 + 1]; 170 | break; 171 | default: 172 | return VDP_STATUS_INVALID_INDEXED_FORMAT; 173 | } 174 | dst_ptr[x] = (colormap[i] & 0x00ffffff) | (a << 24); 175 | } 176 | src_ptr += source_pitch[0]; 177 | dst_ptr += rgba->width; 178 | } 179 | 180 | rgba->flags &= ~RGBA_FLAG_NEEDS_CLEAR; 181 | rgba->flags |= RGBA_FLAG_DIRTY | RGBA_FLAG_NEEDS_FLUSH; 182 | dirty_add_rect(&rgba->dirty, &d_rect); 183 | 184 | return VDP_STATUS_OK; 185 | } 186 | 187 | VdpStatus rgba_render_surface(rgba_surface_t *dest, 188 | VdpRect const *destination_rect, 189 | rgba_surface_t *src, 190 | VdpRect const *source_rect, 191 | VdpColor const *colors, 192 | VdpOutputSurfaceRenderBlendState const *blend_state, 193 | uint32_t flags) 194 | { 195 | if (!dest->device->osd_enabled) 196 | return VDP_STATUS_OK; 197 | 198 | if (colors || flags) 199 | VDPAU_DBG_ONCE("%s: colors and flags not implemented!", __func__); 200 | 201 | // set up source/destination rects using defaults where required 202 | VdpRect s_rect = {0, 0, 0, 0}; 203 | VdpRect d_rect = {0, 0, dest->width, dest->height}; 204 | s_rect.x1 = src ? src->width : 1; 205 | s_rect.y1 = src ? src->height : 1; 206 | 207 | if (source_rect) 208 | s_rect = *source_rect; 209 | if (destination_rect) 210 | d_rect = *destination_rect; 211 | 212 | // ignore zero-sized surfaces (also workaround for g2d driver bug) 213 | if (s_rect.x0 == s_rect.x1 || s_rect.y0 == s_rect.y1 || 214 | d_rect.x0 == d_rect.x1 || d_rect.y0 == d_rect.y1) 215 | return VDP_STATUS_OK; 216 | 217 | if ((dest->flags & RGBA_FLAG_NEEDS_CLEAR) && !dirty_in_rect(&dest->dirty, &d_rect)) 218 | rgba_clear(dest); 219 | 220 | if (!src) 221 | rgba_fill(dest, &d_rect, 0xffffffff); 222 | else 223 | rgba_blit(dest, &d_rect, src, &s_rect); 224 | 225 | dest->flags &= ~RGBA_FLAG_NEEDS_CLEAR; 226 | dest->flags |= RGBA_FLAG_DIRTY; 227 | dirty_add_rect(&dest->dirty, &d_rect); 228 | 229 | return VDP_STATUS_OK; 230 | } 231 | 232 | void rgba_clear(rgba_surface_t *rgba) 233 | { 234 | if (!(rgba->flags & RGBA_FLAG_DIRTY)) 235 | return; 236 | 237 | rgba_fill(rgba, &rgba->dirty, 0x00000000); 238 | rgba->flags &= ~(RGBA_FLAG_DIRTY | RGBA_FLAG_NEEDS_CLEAR); 239 | rgba->dirty.x0 = rgba->width; 240 | rgba->dirty.y0 = rgba->height; 241 | rgba->dirty.x1 = 0; 242 | rgba->dirty.y1 = 0; 243 | } 244 | 245 | void rgba_fill(rgba_surface_t *dest, const VdpRect *dest_rect, uint32_t color) 246 | { 247 | if (dest->device->osd_enabled) 248 | { 249 | if(dest->device->g2d_enabled) 250 | { 251 | rgba_flush(dest); 252 | g2d_fill(dest, dest_rect, color); 253 | } 254 | else 255 | { 256 | vdp_pixman_fill(dest, dest_rect, color); 257 | dest->flags |= RGBA_FLAG_NEEDS_FLUSH; 258 | } 259 | } 260 | } 261 | 262 | void rgba_blit(rgba_surface_t *dest, const VdpRect *dest_rect, rgba_surface_t *src, const VdpRect *src_rect) 263 | { 264 | if (dest->device->osd_enabled) 265 | { 266 | if(dest->device->g2d_enabled) 267 | { 268 | rgba_flush(dest); 269 | rgba_flush(src); 270 | g2d_blit(dest, dest_rect, src, src_rect); 271 | } 272 | else 273 | { 274 | vdp_pixman_blit(dest, dest_rect, src, src_rect); 275 | dest->flags |= RGBA_FLAG_NEEDS_FLUSH; 276 | } 277 | } 278 | } 279 | 280 | void rgba_flush(rgba_surface_t *rgba) 281 | { 282 | if (rgba->flags & RGBA_FLAG_NEEDS_FLUSH) 283 | { 284 | cedrus_mem_flush_cache(rgba->data); 285 | rgba->flags &= ~RGBA_FLAG_NEEDS_FLUSH; 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /rgba.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #ifndef __RGBA_H__ 21 | #define __RGBA_H__ 22 | 23 | #include "vdpau_private.h" 24 | 25 | VdpStatus rgba_create(rgba_surface_t *rgba, 26 | device_ctx_t *device, 27 | uint32_t width, 28 | uint32_t height, 29 | VdpRGBAFormat format); 30 | 31 | void rgba_destroy(rgba_surface_t *rgba); 32 | 33 | VdpStatus rgba_put_bits_native(rgba_surface_t *rgba, 34 | void const *const *source_data, 35 | uint32_t const *source_pitches, 36 | VdpRect const *destination_rect); 37 | 38 | VdpStatus rgba_put_bits_indexed(rgba_surface_t *rgba, 39 | VdpIndexedFormat source_indexed_format, 40 | void const *const *source_data, 41 | uint32_t const *source_pitch, 42 | VdpRect const *destination_rect, 43 | VdpColorTableFormat color_table_format, 44 | void const *color_table); 45 | 46 | VdpStatus rgba_render_surface(rgba_surface_t *dest, 47 | VdpRect const *destination_rect, 48 | rgba_surface_t *src, 49 | VdpRect const *source_rect, 50 | VdpColor const *colors, 51 | VdpOutputSurfaceRenderBlendState const *blend_state, 52 | uint32_t flags); 53 | 54 | void rgba_clear(rgba_surface_t *rgba); 55 | void rgba_fill(rgba_surface_t *dest, const VdpRect *dest_rect, uint32_t color); 56 | void rgba_blit(rgba_surface_t *dest, const VdpRect *dest_rect, rgba_surface_t *src, const VdpRect *src_rect); 57 | 58 | void rgba_flush(rgba_surface_t *rgba); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /rgba_g2d.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Jens Kuske 3 | * Copyright (c) 2016 Andreas Baierl 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library 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 GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include "vdpau_private.h" 25 | #include "kernel-headers/g2d_driver.h" 26 | 27 | void g2d_fill(rgba_surface_t *dest, const VdpRect *dest_rect, uint32_t color) 28 | { 29 | g2d_fillrect args; 30 | 31 | args.flag = G2D_FIL_PIXEL_ALPHA; 32 | args.dst_image.addr[0] = cedrus_mem_get_phys_addr(dest->data); 33 | args.dst_image.w = dest->width; 34 | args.dst_image.h = dest->height; 35 | args.dst_image.format = G2D_FMT_ARGB_AYUV8888; 36 | args.dst_image.pixel_seq = G2D_SEQ_NORMAL; 37 | if (dest_rect) 38 | { 39 | args.dst_rect.x = dest_rect->x0; 40 | args.dst_rect.y = dest_rect->y0; 41 | args.dst_rect.w = dest_rect->x1 - dest_rect->x0; 42 | args.dst_rect.h = dest_rect->y1 - dest_rect->y0; 43 | } 44 | else 45 | { 46 | args.dst_rect.x = 0; 47 | args.dst_rect.y = 0; 48 | args.dst_rect.w = dest->width; 49 | args.dst_rect.h = dest->height; 50 | } 51 | args.color = color & 0xffffff ; 52 | args.alpha = color >> 24; 53 | 54 | ioctl(dest->device->g2d_fd, G2D_CMD_FILLRECT, &args); 55 | } 56 | 57 | void g2d_blit(rgba_surface_t *dest, const VdpRect *dest_rect, rgba_surface_t *src, const VdpRect *src_rect) 58 | { 59 | g2d_blt args; 60 | 61 | args.flag = (dest->flags & RGBA_FLAG_NEEDS_CLEAR) ? G2D_BLT_NONE : G2D_BLT_PIXEL_ALPHA; 62 | args.src_image.addr[0] = cedrus_mem_get_phys_addr(src->data); 63 | args.src_image.w = src->width; 64 | args.src_image.h = src->height; 65 | args.src_image.format = G2D_FMT_ARGB_AYUV8888; 66 | args.src_image.pixel_seq = G2D_SEQ_NORMAL; 67 | args.src_rect.x = src_rect->x0; 68 | args.src_rect.y = src_rect->y0; 69 | args.src_rect.w = src_rect->x1 - src_rect->x0; 70 | args.src_rect.h = src_rect->y1 - src_rect->y0; 71 | args.dst_image.addr[0] = cedrus_mem_get_phys_addr(dest->data); 72 | args.dst_image.w = dest->width; 73 | args.dst_image.h = dest->height; 74 | args.dst_image.format = G2D_FMT_ARGB_AYUV8888; 75 | args.dst_image.pixel_seq = G2D_SEQ_NORMAL; 76 | args.dst_x = dest_rect->x0; 77 | args.dst_y = dest_rect->y0; 78 | args.color = 0; 79 | args.alpha = 0; 80 | 81 | ioctl(dest->device->g2d_fd, G2D_CMD_BITBLT, &args); 82 | } 83 | -------------------------------------------------------------------------------- /rgba_g2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #ifndef __RGBA_G2D_H__ 21 | #define __RGBA_G2D_H__ 22 | 23 | void g2d_fill(rgba_surface_t *dest, const VdpRect *dest_rect, uint32_t color); 24 | void g2d_blit(rgba_surface_t *dest, const VdpRect *dest_rect, rgba_surface_t *src, const VdpRect *src_rect); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /rgba_pixman.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Andreas Baierl 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "vdpau_private.h" 24 | #include "rgba_pixman.h" 25 | #include "pixman.h" 26 | 27 | static pixman_color_t uint32_to_pcolor(uint32_t color) 28 | { 29 | pixman_color_t pcolor; 30 | 31 | /* Fetch 8bit values */ 32 | uint16_t alpha = color >> 24; 33 | uint16_t red = color >> 16 & 0xff; 34 | uint16_t green = color >> 8 & 0xff; 35 | uint16_t blue = color & 0xff; 36 | 37 | /* Premultiply with alpha value. Pixman only deals with premultiplied alpha. */ 38 | red = red * alpha / 255; 39 | green = green * alpha / 255; 40 | blue = blue * alpha / 255; 41 | 42 | /* Convert 8bit -> 16bit for pixman */ 43 | pcolor.alpha = ((alpha & 0xFF) << 8) | (alpha & 0xFF); 44 | pcolor.red = ((red & 0xFF) << 8) | (red & 0xFF); 45 | pcolor.green = ((green & 0xFF) << 8) | (green & 0xFF); 46 | pcolor.blue = ((blue & 0xFF) << 8) | (blue & 0xFF); 47 | 48 | return pcolor; 49 | } 50 | 51 | VdpStatus vdp_pixman_ref(rgba_surface_t *rgba) 52 | { 53 | rgba->pimage = pixman_image_create_bits(PIXMAN_a8r8g8b8, 54 | rgba->width, rgba->height, 55 | cedrus_mem_get_pointer(rgba->data), 56 | (rgba->width * 4)); 57 | 58 | return VDP_STATUS_OK; 59 | } 60 | 61 | VdpStatus vdp_pixman_unref(rgba_surface_t *rgba) 62 | { 63 | pixman_image_unref(rgba->pimage); 64 | 65 | return VDP_STATUS_OK; 66 | } 67 | 68 | VdpStatus vdp_pixman_blit(rgba_surface_t *rgba_dst, const VdpRect *dst_rect, 69 | rgba_surface_t *rgba_src, const VdpRect *src_rect) 70 | { 71 | pixman_image_t *dst; 72 | pixman_image_t *src; 73 | pixman_transform_t transform; 74 | double fscale_x, fscale_y; 75 | int pixman_operator; 76 | 77 | dst = rgba_dst->pimage; 78 | src = rgba_src->pimage; 79 | 80 | if ((dst_rect->x1 - dst_rect->x0) == 0 || 81 | (src_rect->x1 - src_rect->x0) == 0 || 82 | (dst_rect->y1 - dst_rect->y0) == 0 || 83 | (src_rect->y1 - src_rect->y0) == 0 ) 84 | goto zero_size_blit; 85 | 86 | /* Transform src_rct to dest_rct size */ 87 | fscale_x = (double)(dst_rect->x1 - dst_rect->x0) / (double)(src_rect->x1 - src_rect->x0); 88 | fscale_y = (double)(dst_rect->y1 - dst_rect->y0) / (double)(src_rect->y1 - src_rect->y0); 89 | pixman_transform_init_identity(&transform); 90 | pixman_transform_scale(&transform, NULL, 91 | pixman_double_to_fixed(fscale_x), 92 | pixman_double_to_fixed(fscale_y)); 93 | pixman_image_set_transform(src, &transform); 94 | 95 | /* Composite to the dest_img */ 96 | pixman_operator = (rgba_dst->flags & RGBA_FLAG_NEEDS_CLEAR) ? PIXMAN_OP_SRC : PIXMAN_OP_OVER; 97 | pixman_image_composite32( 98 | pixman_operator, src, NULL, dst, 99 | (src_rect->x0 * fscale_x), (src_rect->y0 * fscale_y), 100 | 0, 0, 101 | dst_rect->x0, dst_rect->y0, 102 | (dst_rect->x1 - dst_rect->x0), (dst_rect->y1 - dst_rect->y0)); 103 | 104 | return VDP_STATUS_OK; 105 | 106 | zero_size_blit: 107 | VDPAU_DBG("Zero size blit requested!"); 108 | return VDP_STATUS_ERROR; 109 | } 110 | 111 | VdpStatus vdp_pixman_fill(rgba_surface_t *rgba_dst, const VdpRect *dst_rect, 112 | uint32_t color) 113 | { 114 | 115 | /* Define default values if dst_rect == NULL) */ 116 | VdpRect rect = { 117 | .x0 = 0, 118 | .y0 = 0, 119 | .x1 = rgba_dst->width, 120 | .y1 = rgba_dst->height 121 | }; 122 | 123 | if (dst_rect) 124 | { 125 | rect.x0 = dst_rect->x0; 126 | rect.y0 = dst_rect->y0; 127 | rect.x1 = dst_rect->x1; 128 | rect.y1 = dst_rect->y1; 129 | } 130 | 131 | /* Check for zerosized rect */ 132 | if ((rect.x1 - rect.x0) == 0 || 133 | (rect.y1 - rect.y0) == 0) 134 | goto zero_size_fill; 135 | 136 | pixman_color_t pcolor = uint32_to_pcolor(color); 137 | pixman_image_t *src = pixman_image_create_solid_fill(&pcolor); 138 | 139 | pixman_image_t *dst = rgba_dst->pimage; 140 | 141 | /* Composite to the dest_img */ 142 | pixman_image_composite32( 143 | PIXMAN_OP_SRC, src, NULL, dst, 144 | 0, 0, 0, 0, 145 | rect.x0, rect.y0, 146 | (rect.x1 - rect.x0), (rect.y1 - rect.y0)); 147 | 148 | pixman_image_unref(src); 149 | 150 | return VDP_STATUS_OK; 151 | 152 | zero_size_fill: 153 | VDPAU_DBG("Zero size fill requested!"); 154 | return VDP_STATUS_ERROR; 155 | } 156 | -------------------------------------------------------------------------------- /rgba_pixman.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Andreas Baierl 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #ifndef __RGBA_PIXMAN_H__ 21 | #define __RGBA_PIXMAN_H__ 22 | 23 | VdpStatus vdp_pixman_ref(rgba_surface_t *rgba); 24 | VdpStatus vdp_pixman_unref(rgba_surface_t *rgba); 25 | VdpStatus vdp_pixman_blit(rgba_surface_t *dst, const VdpRect *dst_rect, 26 | rgba_surface_t *src, const VdpRect *src_rect); 27 | VdpStatus vdp_pixman_fill(rgba_surface_t *dst, const VdpRect *dst_rect, 28 | uint32_t color); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /sunxi_disp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "kernel-headers/sunxi_disp_ioctl.h" 26 | #include "vdpau_private.h" 27 | #include "sunxi_disp.h" 28 | 29 | struct sunxi_disp_private 30 | { 31 | struct sunxi_disp pub; 32 | 33 | int fd; 34 | int video_layer; 35 | int osd_layer; 36 | __disp_layer_info_t video_info; 37 | __disp_layer_info_t osd_info; 38 | }; 39 | 40 | static void sunxi_disp_close(struct sunxi_disp *sunxi_disp); 41 | static int sunxi_disp_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 42 | static void sunxi_disp_close_video_layer(struct sunxi_disp *sunxi_disp); 43 | static int sunxi_disp_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 44 | static void sunxi_disp_close_osd_layer(struct sunxi_disp *sunxi_disp); 45 | 46 | struct sunxi_disp *sunxi_disp_open(int osd_enabled) 47 | { 48 | struct sunxi_disp_private *disp = calloc(1, sizeof(*disp)); 49 | 50 | disp->fd = open("/dev/disp", O_RDWR); 51 | if (disp->fd == -1) 52 | goto err_open; 53 | 54 | int tmp = SUNXI_DISP_VERSION; 55 | if (ioctl(disp->fd, DISP_CMD_VERSION, &tmp) < 0) 56 | goto err_version; 57 | 58 | uint32_t args[4] = { 0, DISP_LAYER_WORK_MODE_SCALER, 0, 0 }; 59 | disp->video_layer = ioctl(disp->fd, DISP_CMD_LAYER_REQUEST, args); 60 | if (disp->video_layer == 0) 61 | goto err_video_layer; 62 | 63 | args[1] = disp->video_layer; 64 | ioctl(disp->fd, osd_enabled ? DISP_CMD_LAYER_TOP : DISP_CMD_LAYER_BOTTOM, args); 65 | 66 | if (osd_enabled) 67 | { 68 | args[1] = DISP_LAYER_WORK_MODE_NORMAL; 69 | disp->osd_layer = ioctl(disp->fd, DISP_CMD_LAYER_REQUEST, args); 70 | if (disp->osd_layer == 0) 71 | goto err_osd_layer; 72 | 73 | args[1] = disp->osd_layer; 74 | ioctl(disp->fd, DISP_CMD_LAYER_TOP, args); 75 | 76 | disp->osd_info.pipe = 1; 77 | disp->osd_info.mode = DISP_LAYER_WORK_MODE_NORMAL; 78 | disp->osd_info.fb.mode = DISP_MOD_INTERLEAVED; 79 | disp->osd_info.fb.format = DISP_FORMAT_ARGB8888; 80 | disp->osd_info.fb.seq = DISP_SEQ_ARGB; 81 | disp->osd_info.fb.cs_mode = DISP_BT601; 82 | } 83 | else 84 | { 85 | disp->video_info.pipe = 1; 86 | disp->video_info.ck_enable = 1; 87 | 88 | __disp_colorkey_t ck; 89 | ck.ck_max.red = ck.ck_min.red = 0; 90 | ck.ck_max.green = ck.ck_min.green = 1; 91 | ck.ck_max.blue = ck.ck_min.blue = 2; 92 | ck.red_match_rule = 2; 93 | ck.green_match_rule = 2; 94 | ck.blue_match_rule = 2; 95 | 96 | args[1] = (unsigned long)(&ck); 97 | ioctl(disp->fd, DISP_CMD_SET_COLORKEY, args); 98 | } 99 | 100 | disp->video_info.mode = DISP_LAYER_WORK_MODE_SCALER; 101 | disp->video_info.fb.cs_mode = DISP_BT601; 102 | disp->video_info.fb.br_swap = 0; 103 | 104 | disp->pub.close = sunxi_disp_close; 105 | disp->pub.set_video_layer = sunxi_disp_set_video_layer; 106 | disp->pub.close_video_layer = sunxi_disp_close_video_layer; 107 | disp->pub.set_osd_layer = sunxi_disp_set_osd_layer; 108 | disp->pub.close_osd_layer = sunxi_disp_close_osd_layer; 109 | 110 | return (struct sunxi_disp *)disp; 111 | 112 | err_osd_layer: 113 | args[1] = disp->osd_layer; 114 | ioctl(disp->fd, DISP_CMD_LAYER_RELEASE, args); 115 | err_video_layer: 116 | err_version: 117 | close(disp->fd); 118 | err_open: 119 | free(disp); 120 | return NULL; 121 | } 122 | 123 | static void sunxi_disp_close(struct sunxi_disp *sunxi_disp) 124 | { 125 | struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp; 126 | 127 | uint32_t args[4] = { 0, disp->video_layer, 0, 0 }; 128 | ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args); 129 | ioctl(disp->fd, DISP_CMD_LAYER_RELEASE, args); 130 | 131 | if (disp->osd_layer) 132 | { 133 | args[1] = disp->osd_layer; 134 | ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args); 135 | ioctl(disp->fd, DISP_CMD_LAYER_RELEASE, args); 136 | } 137 | 138 | close(disp->fd); 139 | free(sunxi_disp); 140 | } 141 | 142 | static int sunxi_disp_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface) 143 | { 144 | struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp; 145 | 146 | switch (surface->vs->source_format) { 147 | case VDP_YCBCR_FORMAT_YUYV: 148 | disp->video_info.fb.mode = DISP_MOD_INTERLEAVED; 149 | disp->video_info.fb.format = DISP_FORMAT_YUV422; 150 | disp->video_info.fb.seq = DISP_SEQ_YUYV; 151 | break; 152 | case VDP_YCBCR_FORMAT_UYVY: 153 | disp->video_info.fb.mode = DISP_MOD_INTERLEAVED; 154 | disp->video_info.fb.format = DISP_FORMAT_YUV422; 155 | disp->video_info.fb.seq = DISP_SEQ_UYVY; 156 | break; 157 | case VDP_YCBCR_FORMAT_NV12: 158 | disp->video_info.fb.mode = DISP_MOD_NON_MB_UV_COMBINED; 159 | disp->video_info.fb.format = DISP_FORMAT_YUV420; 160 | disp->video_info.fb.seq = DISP_SEQ_UVUV; 161 | break; 162 | case VDP_YCBCR_FORMAT_YV12: 163 | disp->video_info.fb.mode = DISP_MOD_NON_MB_PLANAR; 164 | disp->video_info.fb.format = DISP_FORMAT_YUV420; 165 | disp->video_info.fb.seq = DISP_SEQ_UVUV; 166 | break; 167 | default: 168 | case INTERNAL_YCBCR_FORMAT: 169 | disp->video_info.fb.mode = DISP_MOD_MB_UV_COMBINED; 170 | disp->video_info.fb.format = DISP_FORMAT_YUV420; 171 | disp->video_info.fb.seq = DISP_SEQ_UVUV; 172 | break; 173 | } 174 | 175 | disp->video_info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->yuv->data); 176 | disp->video_info.fb.addr[1] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size; 177 | disp->video_info.fb.addr[2] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size + surface->vs->chroma_size / 2; 178 | 179 | disp->video_info.fb.size.width = surface->vs->width; 180 | disp->video_info.fb.size.height = surface->vs->height; 181 | disp->video_info.src_win.x = surface->video_src_rect.x0; 182 | disp->video_info.src_win.y = surface->video_src_rect.y0; 183 | disp->video_info.src_win.width = surface->video_src_rect.x1 - surface->video_src_rect.x0; 184 | disp->video_info.src_win.height = surface->video_src_rect.y1 - surface->video_src_rect.y0; 185 | disp->video_info.scn_win.x = x + surface->video_dst_rect.x0; 186 | disp->video_info.scn_win.y = y + surface->video_dst_rect.y0; 187 | disp->video_info.scn_win.width = surface->video_dst_rect.x1 - surface->video_dst_rect.x0; 188 | disp->video_info.scn_win.height = surface->video_dst_rect.y1 - surface->video_dst_rect.y0; 189 | 190 | if (disp->video_info.scn_win.y < 0) 191 | { 192 | int scn_clip = -(disp->video_info.scn_win.y); 193 | int src_clip = scn_clip * disp->video_info.src_win.height / disp->video_info.scn_win.height; 194 | disp->video_info.src_win.y += src_clip; 195 | disp->video_info.src_win.height -= src_clip; 196 | disp->video_info.scn_win.y = 0; 197 | disp->video_info.scn_win.height -= scn_clip; 198 | } 199 | 200 | uint32_t args[4] = { 0, disp->video_layer, (unsigned long)(&disp->video_info), 0 }; 201 | ioctl(disp->fd, DISP_CMD_LAYER_SET_PARA, args); 202 | 203 | ioctl(disp->fd, DISP_CMD_LAYER_OPEN, args); 204 | 205 | // Note: might be more reliable (but slower and problematic when there 206 | // are driver issues and the GET functions return wrong values) to query the 207 | // old values instead of relying on our internal csc_change. 208 | // Since the driver calculates a matrix out of these values after each 209 | // set doing this unconditionally is costly. 210 | if (surface->csc_change) 211 | { 212 | ioctl(disp->fd, DISP_CMD_LAYER_ENHANCE_OFF, args); 213 | args[2] = 0xff * surface->brightness + 0x20; 214 | ioctl(disp->fd, DISP_CMD_LAYER_SET_BRIGHT, args); 215 | args[2] = 0x20 * surface->contrast; 216 | ioctl(disp->fd, DISP_CMD_LAYER_SET_CONTRAST, args); 217 | args[2] = 0x20 * surface->saturation; 218 | ioctl(disp->fd, DISP_CMD_LAYER_SET_SATURATION, args); 219 | // hue scale is randomly chosen, no idea how it maps exactly 220 | args[2] = (32 / 3.14) * surface->hue + 0x20; 221 | ioctl(disp->fd, DISP_CMD_LAYER_SET_HUE, args); 222 | ioctl(disp->fd, DISP_CMD_LAYER_ENHANCE_ON, args); 223 | surface->csc_change = 0; 224 | } 225 | 226 | return 0; 227 | } 228 | 229 | static void sunxi_disp_close_video_layer(struct sunxi_disp *sunxi_disp) 230 | { 231 | struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp; 232 | 233 | uint32_t args[4] = { 0, disp->video_layer, 0, 0 }; 234 | ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args); 235 | } 236 | 237 | static int sunxi_disp_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface) 238 | { 239 | struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp; 240 | 241 | switch (surface->rgba.format) 242 | { 243 | case VDP_RGBA_FORMAT_R8G8B8A8: 244 | disp->osd_info.fb.br_swap = 1; 245 | break; 246 | case VDP_RGBA_FORMAT_B8G8R8A8: 247 | default: 248 | disp->osd_info.fb.br_swap = 0; 249 | break; 250 | } 251 | 252 | disp->osd_info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->rgba.data); 253 | disp->osd_info.fb.size.width = surface->rgba.width; 254 | disp->osd_info.fb.size.height = surface->rgba.height; 255 | disp->osd_info.src_win.x = surface->rgba.dirty.x0; 256 | disp->osd_info.src_win.y = surface->rgba.dirty.y0; 257 | disp->osd_info.src_win.width = surface->rgba.dirty.x1 - surface->rgba.dirty.x0; 258 | disp->osd_info.src_win.height = surface->rgba.dirty.y1 - surface->rgba.dirty.y0; 259 | disp->osd_info.scn_win.x = x + surface->rgba.dirty.x0; 260 | disp->osd_info.scn_win.y = y + surface->rgba.dirty.y0; 261 | disp->osd_info.scn_win.width = min_nz(width, surface->rgba.dirty.x1) - surface->rgba.dirty.x0; 262 | disp->osd_info.scn_win.height = min_nz(height, surface->rgba.dirty.y1) - surface->rgba.dirty.y0; 263 | 264 | uint32_t args[4] = { 0, disp->osd_layer, (unsigned long)(&disp->osd_info), 0 }; 265 | ioctl(disp->fd, DISP_CMD_LAYER_SET_PARA, args); 266 | 267 | ioctl(disp->fd, DISP_CMD_LAYER_OPEN, args); 268 | 269 | return 0; 270 | } 271 | 272 | static void sunxi_disp_close_osd_layer(struct sunxi_disp *sunxi_disp) 273 | { 274 | struct sunxi_disp_private *disp = (struct sunxi_disp_private *)sunxi_disp; 275 | 276 | uint32_t args[4] = { 0, disp->osd_layer, 0, 0 }; 277 | ioctl(disp->fd, DISP_CMD_LAYER_CLOSE, args); 278 | } 279 | -------------------------------------------------------------------------------- /sunxi_disp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #ifndef SUNXI_DISP_H_ 21 | #define SUNXI_DISP_H_ 22 | 23 | typedef struct output_surface_ctx_struct output_surface_ctx_t; 24 | 25 | struct sunxi_disp 26 | { 27 | void (*close)(struct sunxi_disp *sunxi_disp); 28 | int (*set_video_layer)(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 29 | void (*close_video_layer)(struct sunxi_disp *sunxi_disp); 30 | int (*set_osd_layer)(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 31 | void (*close_osd_layer)(struct sunxi_disp *sunxi_disp); 32 | }; 33 | 34 | struct sunxi_disp *sunxi_disp_open(int osd_enabled); 35 | struct sunxi_disp *sunxi_disp2_open(int osd_enabled); 36 | struct sunxi_disp *sunxi_disp1_5_open(int osd_enabled); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /sunxi_disp1_5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2016 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "kernel-headers/drv_display.h" 27 | #include "vdpau_private.h" 28 | #include "sunxi_disp.h" 29 | 30 | struct sunxi_disp1_5_private 31 | { 32 | struct sunxi_disp pub; 33 | 34 | int fd; 35 | disp_layer_info video_info; 36 | int video_layer; 37 | disp_layer_info osd_info; 38 | int osd_layer; 39 | unsigned int screen_width; 40 | }; 41 | 42 | static void sunxi_disp1_5_close(struct sunxi_disp *sunxi_disp); 43 | static int sunxi_disp1_5_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 44 | static void sunxi_disp1_5_close_video_layer(struct sunxi_disp *sunxi_disp); 45 | static int sunxi_disp1_5_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 46 | static void sunxi_disp1_5_close_osd_layer(struct sunxi_disp *sunxi_disp); 47 | 48 | struct sunxi_disp *sunxi_disp1_5_open(int osd_enabled) 49 | { 50 | struct sunxi_disp1_5_private *disp = calloc(1, sizeof(*disp)); 51 | 52 | disp->fd = open("/dev/disp", O_RDWR); 53 | if (disp->fd == -1) 54 | goto err_open; 55 | 56 | unsigned long args[4] = { 0, 0, (unsigned long) &disp->video_info }; 57 | 58 | disp->video_layer = 1; 59 | args[1] = disp->video_layer; 60 | 61 | disp->video_info.mode = DISP_LAYER_WORK_MODE_SCALER; 62 | disp->video_info.alpha_mode = 1; 63 | disp->video_info.alpha_value = 255; 64 | disp->video_info.pipe = 1; 65 | disp->video_info.ck_enable = 0; 66 | disp->video_info.b_trd_out = 0; 67 | disp->video_info.zorder = 1; 68 | 69 | if (ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args)) 70 | goto err_video_layer; 71 | 72 | if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args)) 73 | goto err_video_layer; 74 | 75 | if (osd_enabled) 76 | { 77 | disp->osd_layer = 2; 78 | args[1] = disp->osd_layer; 79 | args[2] = (unsigned long)&disp->osd_info; 80 | 81 | disp->osd_info.mode = DISP_LAYER_WORK_MODE_NORMAL; 82 | disp->osd_info.alpha_mode = 0; 83 | disp->osd_info.alpha_value = 255; 84 | disp->osd_info.pipe = 0; 85 | disp->osd_info.ck_enable = 0; 86 | disp->osd_info.b_trd_out = 0; 87 | disp->osd_info.zorder = 2; 88 | 89 | if (ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args)) 90 | goto err_video_layer; 91 | 92 | if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args)) 93 | goto err_video_layer; 94 | } 95 | 96 | disp->screen_width = ioctl(disp->fd, DISP_CMD_GET_SCN_WIDTH, args); 97 | 98 | disp->pub.close = sunxi_disp1_5_close; 99 | disp->pub.set_video_layer = sunxi_disp1_5_set_video_layer; 100 | disp->pub.close_video_layer = sunxi_disp1_5_close_video_layer; 101 | disp->pub.set_osd_layer = sunxi_disp1_5_set_osd_layer; 102 | disp->pub.close_osd_layer = sunxi_disp1_5_close_osd_layer; 103 | 104 | return (struct sunxi_disp *)disp; 105 | 106 | err_video_layer: 107 | close(disp->fd); 108 | err_open: 109 | free(disp); 110 | return NULL; 111 | } 112 | 113 | static void sunxi_disp1_5_close(struct sunxi_disp *sunxi_disp) 114 | { 115 | struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp; 116 | 117 | unsigned long args[4] = { 0, disp->video_layer }; 118 | 119 | ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args); 120 | 121 | if (disp->osd_layer) 122 | { 123 | args[1] = disp->osd_layer; 124 | ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args); 125 | } 126 | 127 | close(disp->fd); 128 | free(sunxi_disp); 129 | } 130 | 131 | static int sunxi_disp1_5_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface) 132 | { 133 | struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp; 134 | 135 | disp_window src = { .x = surface->video_src_rect.x0, .y = surface->video_src_rect.y0, 136 | .width = surface->video_src_rect.x1 - surface->video_src_rect.x0, 137 | .height = surface->video_src_rect.y1 - surface->video_src_rect.y0 }; 138 | disp_window scn = { .x = x + surface->video_dst_rect.x0, .y = y + surface->video_dst_rect.y0, 139 | .width = surface->video_dst_rect.x1 - surface->video_dst_rect.x0, 140 | .height = surface->video_dst_rect.y1 - surface->video_dst_rect.y0 }; 141 | 142 | if (scn.y < 0) 143 | { 144 | int scn_clip = -scn.y; 145 | int src_clip = scn_clip * src.height / scn.height; 146 | scn.y = 0; 147 | scn.height -= scn_clip; 148 | src.y += src_clip; 149 | src.height -= src_clip; 150 | } 151 | if (scn.x < 0) 152 | { 153 | int scn_clip = -scn.x; 154 | int src_clip = scn_clip * src.width / scn.width; 155 | scn.x = 0; 156 | scn.width -= scn_clip; 157 | src.x += src_clip; 158 | src.width -= src_clip; 159 | } 160 | if (scn.x + scn.width > disp->screen_width) 161 | { 162 | int scn_clip = scn.x + scn.width - disp->screen_width; 163 | int src_clip = scn_clip * src.width / scn.width; 164 | scn.width -= scn_clip; 165 | src.width -= src_clip; 166 | } 167 | 168 | unsigned long args[4] = { 0, disp->video_layer, (unsigned long)(&disp->video_info) }; 169 | switch (surface->vs->source_format) 170 | { 171 | case VDP_YCBCR_FORMAT_YUYV: 172 | disp->video_info.fb.format = DISP_FORMAT_YUV422_I_YUYV; 173 | break; 174 | case VDP_YCBCR_FORMAT_UYVY: 175 | disp->video_info.fb.format = DISP_FORMAT_YUV422_I_UYVY; 176 | break; 177 | case VDP_YCBCR_FORMAT_NV12: 178 | disp->video_info.fb.format = DISP_FORMAT_YUV420_SP_UVUV; 179 | break; 180 | case INTERNAL_YCBCR_FORMAT: 181 | disp->video_info.fb.format = DISP_FORMAT_YUV420_SP_TILE_UVUV; 182 | break; 183 | case VDP_YCBCR_FORMAT_YV12: 184 | default: 185 | disp->video_info.fb.format = DISP_FORMAT_YUV420_P; 186 | break; 187 | } 188 | 189 | disp->video_info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->yuv->data); 190 | disp->video_info.fb.addr[1] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size; 191 | disp->video_info.fb.addr[2] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size + surface->vs->chroma_size / 2; 192 | 193 | disp->video_info.fb.size.width = surface->vs->width; 194 | disp->video_info.fb.size.height = surface->vs->height; 195 | disp->video_info.fb.src_win = src; 196 | disp->video_info.screen_win = scn; 197 | disp->video_info.fb.pre_multiply = 1; 198 | 199 | if (ioctl(disp->fd, DISP_CMD_LAYER_ENABLE, args)) 200 | return -EINVAL; 201 | 202 | if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args)) 203 | return -EINVAL; 204 | 205 | return 0; 206 | } 207 | 208 | static void sunxi_disp1_5_close_video_layer(struct sunxi_disp *sunxi_disp) 209 | { 210 | struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp; 211 | 212 | unsigned long args[4] = { 0, disp->video_layer }; 213 | 214 | ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args); 215 | } 216 | 217 | static int sunxi_disp1_5_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface) 218 | { 219 | struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp; 220 | 221 | unsigned long args[4] = { 0, disp->osd_layer, (unsigned long)(&disp->osd_info) }; 222 | 223 | disp_window src = { .x = surface->rgba.dirty.x0, .y = surface->rgba.dirty.y0, 224 | .width = surface->rgba.dirty.x1 - surface->rgba.dirty.x0, 225 | .height = surface->rgba.dirty.y1 - surface->rgba.dirty.y0 }; 226 | disp_window scn = { .x = x + surface->rgba.dirty.x0, .y = y + surface->rgba.dirty.y0, 227 | .width = min_nz(width, surface->rgba.dirty.x1) - surface->rgba.dirty.x0, 228 | .height = min_nz(height, surface->rgba.dirty.y1) - surface->rgba.dirty.y0 }; 229 | 230 | switch (surface->rgba.format) 231 | { 232 | case VDP_RGBA_FORMAT_R8G8B8A8: 233 | disp->osd_info.fb.format = DISP_FORMAT_ABGR_8888; 234 | break; 235 | case VDP_RGBA_FORMAT_B8G8R8A8: 236 | default: 237 | disp->osd_info.fb.format = DISP_FORMAT_ARGB_8888; 238 | break; 239 | } 240 | 241 | disp->osd_info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->rgba.data); 242 | disp->osd_info.fb.size.width = surface->rgba.width; 243 | disp->osd_info.fb.size.height = surface->rgba.height; 244 | disp->osd_info.fb.src_win = src; 245 | disp->osd_info.screen_win = scn; 246 | 247 | if (ioctl(disp->fd, DISP_CMD_LAYER_ENABLE, args)) 248 | return -EINVAL; 249 | 250 | if (ioctl(disp->fd, DISP_CMD_LAYER_SET_INFO, args)) 251 | return -EINVAL; 252 | 253 | return 0; 254 | } 255 | 256 | static void sunxi_disp1_5_close_osd_layer(struct sunxi_disp *sunxi_disp) 257 | { 258 | struct sunxi_disp1_5_private *disp = (struct sunxi_disp1_5_private *)sunxi_disp; 259 | 260 | unsigned long args[4] = { 0, disp->osd_layer }; 261 | 262 | ioctl(disp->fd, DISP_CMD_LAYER_DISABLE, args); 263 | } 264 | -------------------------------------------------------------------------------- /sunxi_disp2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015-2016 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "kernel-headers/sunxi_display2.h" 27 | #include "vdpau_private.h" 28 | #include "sunxi_disp.h" 29 | 30 | struct sunxi_disp2_private 31 | { 32 | struct sunxi_disp pub; 33 | 34 | int fd; 35 | disp_layer_config video_config; 36 | unsigned int screen_width; 37 | disp_layer_config osd_config; 38 | }; 39 | 40 | static void sunxi_disp2_close(struct sunxi_disp *sunxi_disp); 41 | static int sunxi_disp2_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 42 | static void sunxi_disp2_close_video_layer(struct sunxi_disp *sunxi_disp); 43 | static int sunxi_disp2_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface); 44 | static void sunxi_disp2_close_osd_layer(struct sunxi_disp *sunxi_disp); 45 | 46 | struct sunxi_disp *sunxi_disp2_open(int osd_enabled) 47 | { 48 | struct sunxi_disp2_private *disp = calloc(1, sizeof(*disp)); 49 | 50 | disp->fd = open("/dev/disp", O_RDWR); 51 | if (disp->fd == -1) 52 | goto err_open; 53 | 54 | unsigned long args[4] = { 0, (unsigned long)(&disp->video_config), 1, 0 }; 55 | 56 | disp->video_config.info.mode = LAYER_MODE_BUFFER; 57 | disp->video_config.info.alpha_mode = 1; 58 | disp->video_config.info.alpha_value = 255; 59 | 60 | disp->video_config.enable = 0; 61 | disp->video_config.channel = 0; 62 | disp->video_config.layer_id = 0; 63 | disp->video_config.info.zorder = 1; 64 | 65 | if (ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args)) 66 | goto err_video_layer; 67 | 68 | if (osd_enabled) 69 | { 70 | disp->osd_config.info.mode = LAYER_MODE_BUFFER; 71 | disp->osd_config.info.alpha_mode = 0; 72 | disp->osd_config.info.alpha_value = 255; 73 | 74 | disp->osd_config.enable = 0; 75 | disp->osd_config.channel = 2; 76 | disp->osd_config.layer_id = 0; 77 | disp->osd_config.info.zorder = 2; 78 | 79 | args[1] = (unsigned long)(&disp->osd_config); 80 | if (ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args)) 81 | goto err_video_layer; 82 | } 83 | 84 | disp->screen_width = ioctl(disp->fd, DISP_GET_SCN_WIDTH, args); 85 | 86 | disp->pub.close = sunxi_disp2_close; 87 | disp->pub.set_video_layer = sunxi_disp2_set_video_layer; 88 | disp->pub.close_video_layer = sunxi_disp2_close_video_layer; 89 | disp->pub.set_osd_layer = sunxi_disp2_set_osd_layer; 90 | disp->pub.close_osd_layer = sunxi_disp2_close_osd_layer; 91 | 92 | return (struct sunxi_disp *)disp; 93 | 94 | err_video_layer: 95 | close(disp->fd); 96 | err_open: 97 | free(disp); 98 | return NULL; 99 | } 100 | 101 | static void sunxi_disp2_close(struct sunxi_disp *sunxi_disp) 102 | { 103 | struct sunxi_disp2_private *disp = (struct sunxi_disp2_private *)sunxi_disp; 104 | 105 | unsigned long args[4] = { 0, (unsigned long)(&disp->video_config), 1, 0 }; 106 | 107 | disp->video_config.enable = 0; 108 | ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args); 109 | 110 | if (disp->osd_config.enable) 111 | { 112 | disp->osd_config.enable = 0; 113 | args[1] = (unsigned long)(&disp->osd_config); 114 | ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args); 115 | } 116 | 117 | close(disp->fd); 118 | free(sunxi_disp); 119 | } 120 | 121 | static void clip(disp_rect *src, disp_rect *scn, unsigned int screen_width) 122 | { 123 | if (scn->y < 0) 124 | { 125 | int scn_clip = -scn->y; 126 | int src_clip = scn_clip * src->height / scn->height; 127 | scn->y = 0; 128 | scn->height -= scn_clip; 129 | src->y += src_clip; 130 | src->height -= src_clip; 131 | } 132 | if (scn->x < 0) 133 | { 134 | int scn_clip = -scn->x; 135 | int src_clip = scn_clip * src->width / scn->width; 136 | scn->x = 0; 137 | scn->width -= scn_clip; 138 | src->x += src_clip; 139 | src->width -= src_clip; 140 | } 141 | if (scn->x + scn->width > screen_width) 142 | { 143 | int scn_clip = scn->x + scn->width - screen_width; 144 | int src_clip = scn_clip * src->width / scn->width; 145 | scn->width -= scn_clip; 146 | src->width -= src_clip; 147 | } 148 | } 149 | 150 | static int sunxi_disp2_set_video_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface) 151 | { 152 | struct sunxi_disp2_private *disp = (struct sunxi_disp2_private *)sunxi_disp; 153 | 154 | disp_rect src = { .x = surface->video_src_rect.x0, .y = surface->video_src_rect.y0, 155 | .width = surface->video_src_rect.x1 - surface->video_src_rect.x0, 156 | .height = surface->video_src_rect.y1 - surface->video_src_rect.y0 }; 157 | disp_rect scn = { .x = x + surface->video_dst_rect.x0, .y = y + surface->video_dst_rect.y0, 158 | .width = surface->video_dst_rect.x1 - surface->video_dst_rect.x0, 159 | .height = surface->video_dst_rect.y1 - surface->video_dst_rect.y0 }; 160 | 161 | clip (&src, &scn, disp->screen_width); 162 | 163 | unsigned long args[4] = { 0, (unsigned long)(&disp->video_config), 1, 0 }; 164 | switch (surface->vs->source_format) 165 | { 166 | case VDP_YCBCR_FORMAT_YUYV: 167 | disp->video_config.info.fb.format = DISP_FORMAT_YUV422_I_YUYV; 168 | break; 169 | case VDP_YCBCR_FORMAT_UYVY: 170 | disp->video_config.info.fb.format = DISP_FORMAT_YUV422_I_UYVY; 171 | break; 172 | case VDP_YCBCR_FORMAT_NV12: 173 | disp->video_config.info.fb.format = DISP_FORMAT_YUV420_SP_UVUV; 174 | break; 175 | case VDP_YCBCR_FORMAT_YV12: 176 | default: 177 | case INTERNAL_YCBCR_FORMAT: 178 | disp->video_config.info.fb.format = DISP_FORMAT_YUV420_P; 179 | break; 180 | } 181 | 182 | disp->video_config.info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->yuv->data); 183 | disp->video_config.info.fb.addr[1] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size; 184 | disp->video_config.info.fb.addr[2] = cedrus_mem_get_phys_addr(surface->yuv->data) + surface->vs->luma_size + surface->vs->chroma_size / 2; 185 | 186 | disp->video_config.info.fb.size[0].width = surface->vs->width; 187 | disp->video_config.info.fb.size[0].height = surface->vs->height; 188 | disp->video_config.info.fb.align[0] = 32; 189 | disp->video_config.info.fb.size[1].width = surface->vs->width / 2; 190 | disp->video_config.info.fb.size[1].height = surface->vs->height / 2; 191 | disp->video_config.info.fb.align[1] = 16; 192 | disp->video_config.info.fb.size[2].width = surface->vs->width / 2; 193 | disp->video_config.info.fb.size[2].height = surface->vs->height / 2; 194 | disp->video_config.info.fb.align[2] = 16; 195 | disp->video_config.info.fb.crop.x = (unsigned long long)(src.x) << 32; 196 | disp->video_config.info.fb.crop.y = (unsigned long long)(src.y) << 32; 197 | disp->video_config.info.fb.crop.width = (unsigned long long)(src.width) << 32; 198 | disp->video_config.info.fb.crop.height = (unsigned long long)(src.height) << 32; 199 | disp->video_config.info.screen_win = scn; 200 | disp->video_config.enable = 1; 201 | 202 | if (ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args)) 203 | return -EINVAL; 204 | 205 | return 0; 206 | } 207 | 208 | static void sunxi_disp2_close_video_layer(struct sunxi_disp *sunxi_disp) 209 | { 210 | struct sunxi_disp2_private *disp = (struct sunxi_disp2_private *)sunxi_disp; 211 | 212 | unsigned long args[4] = { 0, (unsigned long)(&disp->video_config), 1, 0 }; 213 | 214 | disp->video_config.enable = 0; 215 | 216 | ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args); 217 | } 218 | 219 | static int sunxi_disp2_set_osd_layer(struct sunxi_disp *sunxi_disp, int x, int y, int width, int height, output_surface_ctx_t *surface) 220 | { 221 | struct sunxi_disp2_private *disp = (struct sunxi_disp2_private *)sunxi_disp; 222 | 223 | unsigned long args[4] = { 0, (unsigned long)(&disp->osd_config), 1, 0 }; 224 | 225 | disp_rect src = { .x = surface->rgba.dirty.x0, .y = surface->rgba.dirty.y0, 226 | .width = surface->rgba.dirty.x1 - surface->rgba.dirty.x0, 227 | .height = surface->rgba.dirty.y1 - surface->rgba.dirty.y0 }; 228 | disp_rect scn = { .x = x + surface->rgba.dirty.x0, .y = y + surface->rgba.dirty.y0, 229 | .width = min_nz(width, surface->rgba.dirty.x1) - surface->rgba.dirty.x0, 230 | .height = min_nz(height, surface->rgba.dirty.y1) - surface->rgba.dirty.y0 }; 231 | 232 | clip (&src, &scn, disp->screen_width); 233 | 234 | switch (surface->rgba.format) 235 | { 236 | case VDP_RGBA_FORMAT_R8G8B8A8: 237 | disp->osd_config.info.fb.format = DISP_FORMAT_ABGR_8888; 238 | break; 239 | case VDP_RGBA_FORMAT_B8G8R8A8: 240 | default: 241 | disp->osd_config.info.fb.format = DISP_FORMAT_ARGB_8888; 242 | break; 243 | } 244 | 245 | disp->osd_config.info.fb.addr[0] = cedrus_mem_get_phys_addr(surface->rgba.data); 246 | disp->osd_config.info.fb.size[0].width = surface->rgba.width; 247 | disp->osd_config.info.fb.size[0].height = surface->rgba.height; 248 | disp->osd_config.info.fb.align[0] = 1; 249 | disp->osd_config.info.fb.crop.x = (unsigned long long)(src.x) << 32; 250 | disp->osd_config.info.fb.crop.y = (unsigned long long)(src.y) << 32; 251 | disp->osd_config.info.fb.crop.width = (unsigned long long)(src.width) << 32; 252 | disp->osd_config.info.fb.crop.height = (unsigned long long)(src.height) << 32; 253 | disp->osd_config.info.screen_win = scn; 254 | disp->osd_config.enable = 1; 255 | 256 | if (ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args)) 257 | return -EINVAL; 258 | 259 | return 0; 260 | } 261 | 262 | static void sunxi_disp2_close_osd_layer(struct sunxi_disp *sunxi_disp) 263 | { 264 | struct sunxi_disp2_private *disp = (struct sunxi_disp2_private *)sunxi_disp; 265 | 266 | unsigned long args[4] = { 0, (unsigned long)(&disp->osd_config), 1, 0 }; 267 | 268 | disp->osd_config.enable = 0; 269 | 270 | ioctl(disp->fd, DISP_LAYER_SET_CONFIG, args); 271 | } 272 | -------------------------------------------------------------------------------- /surface_bitmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include "vdpau_private.h" 21 | #include "rgba.h" 22 | 23 | VdpStatus vdp_bitmap_surface_create(VdpDevice device, 24 | VdpRGBAFormat rgba_format, 25 | uint32_t width, 26 | uint32_t height, 27 | VdpBool frequently_accessed, 28 | VdpBitmapSurface *surface) 29 | { 30 | int ret = VDP_STATUS_OK; 31 | 32 | if (!surface) 33 | return VDP_STATUS_INVALID_POINTER; 34 | 35 | device_ctx_t *dev = handle_get(device); 36 | if (!dev) 37 | return VDP_STATUS_INVALID_HANDLE; 38 | 39 | bitmap_surface_ctx_t *out = handle_create(sizeof(*out), surface); 40 | if (!out) 41 | return VDP_STATUS_RESOURCES; 42 | 43 | out->frequently_accessed = frequently_accessed; 44 | 45 | ret = rgba_create(&out->rgba, dev, width, height, rgba_format); 46 | if (ret != VDP_STATUS_OK) 47 | { 48 | handle_destroy(*surface); 49 | return ret; 50 | } 51 | 52 | return VDP_STATUS_OK; 53 | } 54 | 55 | VdpStatus vdp_bitmap_surface_destroy(VdpBitmapSurface surface) 56 | { 57 | bitmap_surface_ctx_t *out = handle_get(surface); 58 | if (!out) 59 | return VDP_STATUS_INVALID_HANDLE; 60 | 61 | rgba_destroy(&out->rgba); 62 | 63 | handle_destroy(surface); 64 | 65 | return VDP_STATUS_OK; 66 | } 67 | 68 | VdpStatus vdp_bitmap_surface_get_parameters(VdpBitmapSurface surface, 69 | VdpRGBAFormat *rgba_format, 70 | uint32_t *width, 71 | uint32_t *height, 72 | VdpBool *frequently_accessed) 73 | { 74 | bitmap_surface_ctx_t *out = handle_get(surface); 75 | if (!out) 76 | return VDP_STATUS_INVALID_HANDLE; 77 | 78 | if (rgba_format) 79 | *rgba_format = out->rgba.format; 80 | 81 | if (width) 82 | *width = out->rgba.width; 83 | 84 | if (height) 85 | *height = out->rgba.height; 86 | 87 | if (frequently_accessed) 88 | *frequently_accessed = out->frequently_accessed; 89 | 90 | return VDP_STATUS_OK; 91 | } 92 | 93 | VdpStatus vdp_bitmap_surface_put_bits_native(VdpBitmapSurface surface, 94 | void const *const *source_data, 95 | uint32_t const *source_pitches, 96 | VdpRect const *destination_rect) 97 | { 98 | bitmap_surface_ctx_t *out = handle_get(surface); 99 | if (!out) 100 | return VDP_STATUS_INVALID_HANDLE; 101 | 102 | rgba_put_bits_native(&out->rgba, source_data, source_pitches, destination_rect); 103 | 104 | return VDP_STATUS_OK; 105 | } 106 | 107 | VdpStatus vdp_bitmap_surface_query_capabilities(VdpDevice device, 108 | VdpRGBAFormat surface_rgba_format, 109 | VdpBool *is_supported, 110 | uint32_t *max_width, 111 | uint32_t *max_height) 112 | { 113 | if (!is_supported || !max_width || !max_height) 114 | return VDP_STATUS_INVALID_POINTER; 115 | 116 | device_ctx_t *dev = handle_get(device); 117 | if (!dev) 118 | return VDP_STATUS_INVALID_HANDLE; 119 | 120 | *is_supported = (surface_rgba_format == VDP_RGBA_FORMAT_R8G8B8A8 || surface_rgba_format == VDP_RGBA_FORMAT_B8G8R8A8); 121 | *max_width = 8192; 122 | *max_height = 8192; 123 | 124 | return VDP_STATUS_OK; 125 | } 126 | -------------------------------------------------------------------------------- /surface_output.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include "vdpau_private.h" 21 | #include "rgba.h" 22 | 23 | VdpStatus vdp_output_surface_create(VdpDevice device, 24 | VdpRGBAFormat rgba_format, 25 | uint32_t width, 26 | uint32_t height, 27 | VdpOutputSurface *surface) 28 | { 29 | int ret = VDP_STATUS_OK; 30 | 31 | if (!surface) 32 | return VDP_STATUS_INVALID_POINTER; 33 | 34 | device_ctx_t *dev = handle_get(device); 35 | if (!dev) 36 | return VDP_STATUS_INVALID_HANDLE; 37 | 38 | output_surface_ctx_t *out = handle_create(sizeof(*out), surface); 39 | if (!out) 40 | return VDP_STATUS_RESOURCES; 41 | 42 | out->contrast = 1.0; 43 | out->saturation = 1.0; 44 | 45 | ret = rgba_create(&out->rgba, dev, width, height, rgba_format); 46 | if (ret != VDP_STATUS_OK) 47 | { 48 | handle_destroy(*surface); 49 | return ret; 50 | } 51 | 52 | return VDP_STATUS_OK; 53 | } 54 | 55 | VdpStatus vdp_output_surface_destroy(VdpOutputSurface surface) 56 | { 57 | output_surface_ctx_t *out = handle_get(surface); 58 | if (!out) 59 | return VDP_STATUS_INVALID_HANDLE; 60 | 61 | rgba_destroy(&out->rgba); 62 | 63 | if (out->yuv) 64 | yuv_unref(out->yuv); 65 | 66 | handle_destroy(surface); 67 | 68 | return VDP_STATUS_OK; 69 | } 70 | 71 | VdpStatus vdp_output_surface_get_parameters(VdpOutputSurface surface, 72 | VdpRGBAFormat *rgba_format, 73 | uint32_t *width, 74 | uint32_t *height) 75 | { 76 | output_surface_ctx_t *out = handle_get(surface); 77 | if (!out) 78 | return VDP_STATUS_INVALID_HANDLE; 79 | 80 | if (rgba_format) 81 | *rgba_format = out->rgba.format; 82 | 83 | if (width) 84 | *width = out->rgba.width; 85 | 86 | if (height) 87 | *height = out->rgba.height; 88 | 89 | return VDP_STATUS_OK; 90 | } 91 | 92 | VdpStatus vdp_output_surface_get_bits_native(VdpOutputSurface surface, 93 | VdpRect const *source_rect, 94 | void *const *destination_data, 95 | uint32_t const *destination_pitches) 96 | { 97 | output_surface_ctx_t *out = handle_get(surface); 98 | if (!out) 99 | return VDP_STATUS_INVALID_HANDLE; 100 | 101 | 102 | 103 | return VDP_STATUS_ERROR; 104 | } 105 | 106 | VdpStatus vdp_output_surface_put_bits_native(VdpOutputSurface surface, 107 | void const *const *source_data, 108 | uint32_t const *source_pitches, 109 | VdpRect const *destination_rect) 110 | { 111 | output_surface_ctx_t *out = handle_get(surface); 112 | if (!out) 113 | return VDP_STATUS_INVALID_HANDLE; 114 | 115 | return rgba_put_bits_native(&out->rgba, source_data, source_pitches, destination_rect); 116 | } 117 | 118 | VdpStatus vdp_output_surface_put_bits_indexed(VdpOutputSurface surface, 119 | VdpIndexedFormat source_indexed_format, 120 | void const *const *source_data, 121 | uint32_t const *source_pitch, 122 | VdpRect const *destination_rect, 123 | VdpColorTableFormat color_table_format, 124 | void const *color_table) 125 | { 126 | output_surface_ctx_t *out = handle_get(surface); 127 | if (!out) 128 | return VDP_STATUS_INVALID_HANDLE; 129 | 130 | return rgba_put_bits_indexed(&out->rgba, source_indexed_format, source_data, source_pitch, 131 | destination_rect, color_table_format, color_table); 132 | } 133 | 134 | VdpStatus vdp_output_surface_put_bits_y_cb_cr(VdpOutputSurface surface, 135 | VdpYCbCrFormat source_ycbcr_format, 136 | void const *const *source_data, 137 | uint32_t const *source_pitches, 138 | VdpRect const *destination_rect, 139 | VdpCSCMatrix const *csc_matrix) 140 | { 141 | output_surface_ctx_t *out = handle_get(surface); 142 | if (!out) 143 | return VDP_STATUS_INVALID_HANDLE; 144 | 145 | return VDP_STATUS_ERROR; 146 | } 147 | 148 | VdpStatus vdp_output_surface_render_output_surface(VdpOutputSurface destination_surface, 149 | VdpRect const *destination_rect, 150 | VdpOutputSurface source_surface, 151 | VdpRect const *source_rect, 152 | VdpColor const *colors, 153 | VdpOutputSurfaceRenderBlendState const *blend_state, 154 | uint32_t flags) 155 | { 156 | output_surface_ctx_t *out = handle_get(destination_surface); 157 | if (!out) 158 | return VDP_STATUS_INVALID_HANDLE; 159 | 160 | output_surface_ctx_t *in = handle_get(source_surface); 161 | 162 | return rgba_render_surface(&out->rgba, destination_rect, in ? &in->rgba : NULL, source_rect, 163 | colors, blend_state, flags); 164 | } 165 | 166 | VdpStatus vdp_output_surface_render_bitmap_surface(VdpOutputSurface destination_surface, 167 | VdpRect const *destination_rect, 168 | VdpBitmapSurface source_surface, 169 | VdpRect const *source_rect, 170 | VdpColor const *colors, 171 | VdpOutputSurfaceRenderBlendState const *blend_state, 172 | uint32_t flags) 173 | { 174 | output_surface_ctx_t *out = handle_get(destination_surface); 175 | if (!out) 176 | return VDP_STATUS_INVALID_HANDLE; 177 | 178 | bitmap_surface_ctx_t *in = handle_get(source_surface); 179 | 180 | return rgba_render_surface(&out->rgba, destination_rect, in ? &in->rgba : NULL, source_rect, 181 | colors, blend_state, flags); 182 | } 183 | 184 | VdpStatus vdp_output_surface_query_capabilities(VdpDevice device, 185 | VdpRGBAFormat surface_rgba_format, 186 | VdpBool *is_supported, 187 | uint32_t *max_width, 188 | uint32_t *max_height) 189 | { 190 | if (!is_supported || !max_width || !max_height) 191 | return VDP_STATUS_INVALID_POINTER; 192 | 193 | device_ctx_t *dev = handle_get(device); 194 | if (!dev) 195 | return VDP_STATUS_INVALID_HANDLE; 196 | 197 | *is_supported = (surface_rgba_format == VDP_RGBA_FORMAT_R8G8B8A8 || surface_rgba_format == VDP_RGBA_FORMAT_B8G8R8A8); 198 | *max_width = 8192; 199 | *max_height = 8192; 200 | 201 | return VDP_STATUS_OK; 202 | } 203 | 204 | VdpStatus vdp_output_surface_query_get_put_bits_native_capabilities(VdpDevice device, 205 | VdpRGBAFormat surface_rgba_format, 206 | VdpBool *is_supported) 207 | { 208 | if (!is_supported) 209 | return VDP_STATUS_INVALID_POINTER; 210 | 211 | device_ctx_t *dev = handle_get(device); 212 | if (!dev) 213 | return VDP_STATUS_INVALID_HANDLE; 214 | 215 | *is_supported = VDP_FALSE; 216 | 217 | return VDP_STATUS_OK; 218 | } 219 | 220 | VdpStatus vdp_output_surface_query_put_bits_indexed_capabilities(VdpDevice device, 221 | VdpRGBAFormat surface_rgba_format, 222 | VdpIndexedFormat bits_indexed_format, 223 | VdpColorTableFormat color_table_format, 224 | VdpBool *is_supported) 225 | { 226 | if (!is_supported) 227 | return VDP_STATUS_INVALID_POINTER; 228 | 229 | device_ctx_t *dev = handle_get(device); 230 | if (!dev) 231 | return VDP_STATUS_INVALID_HANDLE; 232 | 233 | *is_supported = VDP_FALSE; 234 | 235 | return VDP_STATUS_OK; 236 | } 237 | 238 | VdpStatus vdp_output_surface_query_put_bits_y_cb_cr_capabilities(VdpDevice device, 239 | VdpRGBAFormat surface_rgba_format, 240 | VdpYCbCrFormat bits_ycbcr_format, 241 | VdpBool *is_supported) 242 | { 243 | if (!is_supported) 244 | return VDP_STATUS_INVALID_POINTER; 245 | 246 | device_ctx_t *dev = handle_get(device); 247 | if (!dev) 248 | return VDP_STATUS_INVALID_HANDLE; 249 | 250 | *is_supported = VDP_FALSE; 251 | 252 | return VDP_STATUS_OK; 253 | } 254 | -------------------------------------------------------------------------------- /surface_video.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include "vdpau_private.h" 23 | #include "tiled_yuv.h" 24 | 25 | void yuv_unref(yuv_data_t *yuv) 26 | { 27 | yuv->ref_count--; 28 | 29 | if (yuv->ref_count == 0) 30 | { 31 | cedrus_mem_free(yuv->data); 32 | free(yuv); 33 | } 34 | } 35 | 36 | yuv_data_t *yuv_ref(yuv_data_t *yuv) 37 | { 38 | yuv->ref_count++; 39 | return yuv; 40 | } 41 | 42 | static VdpStatus yuv_new(video_surface_ctx_t *video_surface) 43 | { 44 | video_surface->yuv = calloc(1, sizeof(yuv_data_t)); 45 | if (!video_surface->yuv) 46 | return VDP_STATUS_RESOURCES; 47 | 48 | video_surface->yuv->ref_count = 1; 49 | video_surface->yuv->data = cedrus_mem_alloc(video_surface->device->cedrus, video_surface->luma_size + video_surface->chroma_size); 50 | 51 | if (!(video_surface->yuv->data)) 52 | { 53 | free(video_surface->yuv); 54 | return VDP_STATUS_RESOURCES; 55 | } 56 | 57 | return VDP_STATUS_OK; 58 | } 59 | 60 | VdpStatus yuv_prepare(video_surface_ctx_t *video_surface) 61 | { 62 | if (video_surface->yuv->ref_count > 1) 63 | { 64 | video_surface->yuv->ref_count--; 65 | return yuv_new(video_surface); 66 | } 67 | 68 | return VDP_STATUS_OK; 69 | } 70 | 71 | VdpStatus vdp_video_surface_create(VdpDevice device, 72 | VdpChromaType chroma_type, 73 | uint32_t width, 74 | uint32_t height, 75 | VdpVideoSurface *surface) 76 | { 77 | if (!surface) 78 | return VDP_STATUS_INVALID_POINTER; 79 | 80 | if (width < 1 || width > 8192 || height < 1 || height > 8192) 81 | return VDP_STATUS_INVALID_SIZE; 82 | 83 | device_ctx_t *dev = handle_get(device); 84 | if (!dev) 85 | return VDP_STATUS_INVALID_HANDLE; 86 | 87 | video_surface_ctx_t *vs = handle_create(sizeof(*vs), surface); 88 | if (!vs) 89 | return VDP_STATUS_RESOURCES; 90 | 91 | vs->device = dev; 92 | vs->width = width; 93 | vs->height = height; 94 | vs->chroma_type = chroma_type; 95 | 96 | vs->luma_size = ALIGN(width, 32) * ALIGN(height, 32); 97 | switch (chroma_type) 98 | { 99 | case VDP_CHROMA_TYPE_444: 100 | vs->chroma_size = vs->luma_size * 2; 101 | break; 102 | case VDP_CHROMA_TYPE_422: 103 | vs->chroma_size = vs->luma_size; 104 | break; 105 | case VDP_CHROMA_TYPE_420: 106 | vs->chroma_size = ALIGN(vs->width, 32) * ALIGN(vs->height / 2, 32); 107 | break; 108 | default: 109 | handle_destroy(*surface); 110 | return VDP_STATUS_INVALID_CHROMA_TYPE; 111 | } 112 | 113 | VdpStatus ret = yuv_new(vs); 114 | if (ret != VDP_STATUS_OK) 115 | { 116 | handle_destroy(*surface); 117 | return ret; 118 | } 119 | 120 | return VDP_STATUS_OK; 121 | } 122 | 123 | VdpStatus vdp_video_surface_destroy(VdpVideoSurface surface) 124 | { 125 | video_surface_ctx_t *vs = handle_get(surface); 126 | if (!vs) 127 | return VDP_STATUS_INVALID_HANDLE; 128 | 129 | if (vs->decoder_private_free) 130 | vs->decoder_private_free(vs); 131 | 132 | yuv_unref(vs->yuv); 133 | 134 | handle_destroy(surface); 135 | 136 | return VDP_STATUS_OK; 137 | } 138 | 139 | VdpStatus vdp_video_surface_get_parameters(VdpVideoSurface surface, 140 | VdpChromaType *chroma_type, 141 | uint32_t *width, 142 | uint32_t *height) 143 | { 144 | video_surface_ctx_t *vid = handle_get(surface); 145 | if (!vid) 146 | return VDP_STATUS_INVALID_HANDLE; 147 | 148 | if (chroma_type) 149 | *chroma_type = vid->chroma_type; 150 | 151 | if (width) 152 | *width = vid->width; 153 | 154 | if (height) 155 | *height = vid->height; 156 | 157 | return VDP_STATUS_OK; 158 | } 159 | 160 | VdpStatus vdp_video_surface_get_bits_y_cb_cr(VdpVideoSurface surface, 161 | VdpYCbCrFormat destination_ycbcr_format, 162 | void *const *destination_data, 163 | uint32_t const *destination_pitches) 164 | { 165 | video_surface_ctx_t *vs = handle_get(surface); 166 | if (!vs) 167 | return VDP_STATUS_INVALID_HANDLE; 168 | 169 | if (vs->chroma_type != VDP_CHROMA_TYPE_420) 170 | return VDP_STATUS_INVALID_CHROMA_TYPE; 171 | 172 | if (destination_pitches[0] < vs->width || destination_pitches[1] < vs->width / 2) 173 | return VDP_STATUS_ERROR; 174 | 175 | if (vs->source_format == VDP_YCBCR_FORMAT_YV12 && destination_ycbcr_format == VDP_YCBCR_FORMAT_YV12) 176 | { 177 | int i; 178 | const uint8_t *src; 179 | uint8_t *dst; 180 | 181 | src = cedrus_mem_get_pointer(vs->yuv->data); 182 | dst = destination_data[0]; 183 | for (i = 0; i < vs->height; i++) 184 | { 185 | memcpy(dst, src, vs->width); 186 | src += ALIGN(vs->width, 32); 187 | dst += destination_pitches[0]; 188 | } 189 | src = cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size; 190 | dst = destination_data[2]; 191 | for (i = 0; i < vs->height / 2; i++) 192 | { 193 | memcpy(dst, src, vs->width / 2); 194 | src += ALIGN(vs->width / 2, 16); 195 | dst += destination_pitches[2]; 196 | } 197 | src = cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size + vs->chroma_size / 2; 198 | dst = destination_data[1]; 199 | for (i = 0; i < vs->height / 2; i++) 200 | { 201 | memcpy(dst, src, vs->width / 2); 202 | src += ALIGN(vs->width / 2, 16); 203 | dst += destination_pitches[1]; 204 | } 205 | return VDP_STATUS_OK; 206 | } 207 | #ifndef __aarch64__ 208 | else if (vs->source_format == INTERNAL_YCBCR_FORMAT && destination_ycbcr_format == VDP_YCBCR_FORMAT_NV12) 209 | { 210 | tiled_to_planar(cedrus_mem_get_pointer(vs->yuv->data), destination_data[0], destination_pitches[0], vs->width, vs->height); 211 | tiled_to_planar(cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size, destination_data[1], destination_pitches[1], vs->width, vs->height / 2); 212 | return VDP_STATUS_OK; 213 | } 214 | else if (vs->source_format == INTERNAL_YCBCR_FORMAT && destination_ycbcr_format == VDP_YCBCR_FORMAT_YV12) 215 | { 216 | if (destination_pitches[2] != destination_pitches[1]) 217 | return VDP_STATUS_ERROR; 218 | tiled_to_planar(cedrus_mem_get_pointer(vs->yuv->data), destination_data[0], destination_pitches[0], vs->width, vs->height); 219 | tiled_deinterleave_to_planar(cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size, destination_data[2], destination_data[1], destination_pitches[1], vs->width, vs->height / 2); 220 | return VDP_STATUS_OK; 221 | } 222 | #endif 223 | 224 | return VDP_STATUS_INVALID_Y_CB_CR_FORMAT; 225 | } 226 | 227 | VdpStatus vdp_video_surface_put_bits_y_cb_cr(VdpVideoSurface surface, 228 | VdpYCbCrFormat source_ycbcr_format, 229 | void const *const *source_data, 230 | uint32_t const *source_pitches) 231 | { 232 | int i; 233 | const uint8_t *src; 234 | uint8_t *dst; 235 | video_surface_ctx_t *vs = handle_get(surface); 236 | if (!vs) 237 | return VDP_STATUS_INVALID_HANDLE; 238 | 239 | VdpStatus ret = yuv_prepare(vs); 240 | if (ret != VDP_STATUS_OK) 241 | return ret; 242 | 243 | vs->source_format = source_ycbcr_format; 244 | 245 | switch (source_ycbcr_format) 246 | { 247 | case VDP_YCBCR_FORMAT_YUYV: 248 | case VDP_YCBCR_FORMAT_UYVY: 249 | if (vs->chroma_type != VDP_CHROMA_TYPE_422) 250 | return VDP_STATUS_INVALID_CHROMA_TYPE; 251 | src = source_data[0]; 252 | dst = cedrus_mem_get_pointer(vs->yuv->data); 253 | for (i = 0; i < vs->height; i++) { 254 | memcpy(dst, src, 2*vs->width); 255 | src += source_pitches[0]; 256 | dst += 2*vs->width; 257 | } 258 | break; 259 | case VDP_YCBCR_FORMAT_Y8U8V8A8: 260 | case VDP_YCBCR_FORMAT_V8U8Y8A8: 261 | 262 | break; 263 | 264 | case VDP_YCBCR_FORMAT_NV12: 265 | if (vs->chroma_type != VDP_CHROMA_TYPE_420) 266 | return VDP_STATUS_INVALID_CHROMA_TYPE; 267 | src = source_data[0]; 268 | dst = cedrus_mem_get_pointer(vs->yuv->data); 269 | for (i = 0; i < vs->height; i++) { 270 | memcpy(dst, src, vs->width); 271 | src += source_pitches[0]; 272 | dst += vs->width; 273 | } 274 | src = source_data[1]; 275 | dst = cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size; 276 | for (i = 0; i < vs->height / 2; i++) { 277 | memcpy(dst, src, vs->width); 278 | src += source_pitches[1]; 279 | dst += vs->width; 280 | } 281 | break; 282 | 283 | case VDP_YCBCR_FORMAT_YV12: 284 | if (vs->chroma_type != VDP_CHROMA_TYPE_420) 285 | return VDP_STATUS_INVALID_CHROMA_TYPE; 286 | src = source_data[0]; 287 | dst = cedrus_mem_get_pointer(vs->yuv->data); 288 | for (i = 0; i < vs->height; i++) { 289 | memcpy(dst, src, vs->width); 290 | src += source_pitches[0]; 291 | dst += vs->width; 292 | } 293 | src = source_data[2]; 294 | dst = cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size; 295 | for (i = 0; i < vs->height / 2; i++) { 296 | memcpy(dst, src, vs->width / 2); 297 | src += source_pitches[1]; 298 | dst += vs->width / 2; 299 | } 300 | src = source_data[1]; 301 | dst = cedrus_mem_get_pointer(vs->yuv->data) + vs->luma_size + vs->chroma_size / 2; 302 | for (i = 0; i < vs->height / 2; i++) { 303 | memcpy(dst, src, vs->width / 2); 304 | src += source_pitches[2]; 305 | dst += vs->width / 2; 306 | } 307 | break; 308 | } 309 | 310 | cedrus_mem_flush_cache(vs->yuv->data); 311 | 312 | return VDP_STATUS_OK; 313 | } 314 | 315 | VdpStatus vdp_video_surface_query_capabilities(VdpDevice device, 316 | VdpChromaType surface_chroma_type, 317 | VdpBool *is_supported, 318 | uint32_t *max_width, 319 | uint32_t *max_height) 320 | { 321 | if (!is_supported || !max_width || !max_height) 322 | return VDP_STATUS_INVALID_POINTER; 323 | 324 | device_ctx_t *dev = handle_get(device); 325 | if (!dev) 326 | return VDP_STATUS_INVALID_HANDLE; 327 | 328 | *is_supported = surface_chroma_type == VDP_CHROMA_TYPE_420; 329 | *max_width = 8192; 330 | *max_height = 8192; 331 | 332 | return VDP_STATUS_OK; 333 | } 334 | 335 | VdpStatus vdp_video_surface_query_get_put_bits_y_cb_cr_capabilities(VdpDevice device, 336 | VdpChromaType surface_chroma_type, 337 | VdpYCbCrFormat bits_ycbcr_format, 338 | VdpBool *is_supported) 339 | { 340 | if (!is_supported) 341 | return VDP_STATUS_INVALID_POINTER; 342 | 343 | device_ctx_t *dev = handle_get(device); 344 | if (!dev) 345 | return VDP_STATUS_INVALID_HANDLE; 346 | 347 | if (surface_chroma_type == VDP_CHROMA_TYPE_420) 348 | *is_supported = (bits_ycbcr_format == VDP_YCBCR_FORMAT_NV12) || 349 | (bits_ycbcr_format == VDP_YCBCR_FORMAT_YV12); 350 | else 351 | *is_supported = VDP_FALSE; 352 | 353 | return VDP_STATUS_OK; 354 | } 355 | -------------------------------------------------------------------------------- /tiled_yuv.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #if defined(__linux__) && defined(__ELF__) 21 | .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ 22 | #endif 23 | 24 | #ifndef __aarch64__ 25 | 26 | .text 27 | .syntax unified 28 | .arch armv7-a 29 | .fpu neon 30 | .thumb 31 | 32 | .macro thumb_function fname 33 | .global \fname 34 | #ifdef __ELF__ 35 | .hidden \fname 36 | .type \fname, %function 37 | #endif 38 | .thumb_func 39 | \fname: 40 | .endm 41 | 42 | .macro end_function fname 43 | #ifdef __ELF__ 44 | .size \fname, .-\fname 45 | #endif 46 | .endm 47 | 48 | SRC .req r0 49 | DST .req r1 50 | PITCH .req r2 51 | CNT .req r3 52 | TLINE .req r4 53 | HEIGHT .req r5 54 | REST .req r6 55 | NTILES .req r7 56 | TMPSRC .req r8 57 | DST2 .req r9 58 | TSIZE .req r12 59 | NEXTLIN .req lr 60 | 61 | thumb_function tiled_to_planar 62 | push {r4, r5, r6, r7, r8, lr} 63 | ldr HEIGHT, [sp, #24] 64 | add NEXTLIN, r3, #31 65 | lsrs NTILES, r3, #5 66 | bic NEXTLIN, NEXTLIN, #31 67 | and REST, r3, #31 68 | lsl NEXTLIN, NEXTLIN, #5 69 | subs PITCH, r2, r3 70 | movs TLINE, #32 71 | rsb NEXTLIN, NEXTLIN, #32 72 | mov TSIZE, #1024 73 | 74 | /* y loop */ 75 | 1: cbz NTILES, 3f 76 | mov CNT, NTILES 77 | 78 | /* x loop complete tiles */ 79 | 2: pld [SRC, TSIZE] 80 | vld1.8 {d0 - d3}, [SRC :256], TSIZE 81 | subs CNT, #1 82 | vst1.8 {d0 - d3}, [DST]! 83 | bne 2b 84 | 85 | 3: cbnz REST, 4f 86 | 87 | /* fix up dest pointer if pitch != width */ 88 | 7: add DST, PITCH 89 | 90 | /* fix up src pointer at end of line */ 91 | subs TLINE, #1 92 | itee ne 93 | addne SRC, NEXTLIN 94 | subeq SRC, #992 95 | moveq TLINE, #32 96 | 97 | subs HEIGHT, #1 98 | bne 1b 99 | pop {r4, r5, r6, r7, r8, pc} 100 | 101 | /* partly copy last tile of line */ 102 | 4: mov TMPSRC, SRC 103 | tst REST, #16 104 | beq 5f 105 | vld1.8 {d0 - d1}, [TMPSRC :128]! 106 | vst1.8 {d0 - d1}, [DST]! 107 | 5: add SRC, TSIZE 108 | ands CNT, REST, #15 109 | beq 7b 110 | 6: vld1.8 {d0[0]}, [TMPSRC]! 111 | subs CNT, #1 112 | vst1.8 {d0[0]}, [DST]! 113 | bne 6b 114 | b 7b 115 | end_function tiled_to_planar 116 | 117 | thumb_function tiled_deinterleave_to_planar 118 | push {r4, r5, r6, r7, r8, r9, lr} 119 | mov DST2, r2 120 | ldr HEIGHT, [sp, #32] 121 | ldr r4, [sp, #28] 122 | add NEXTLIN, r4, #31 123 | lsrs NTILES, r4, #5 124 | bic NEXTLIN, NEXTLIN, #31 125 | ubfx REST, r4, #1, #4 126 | lsl NEXTLIN, NEXTLIN, #5 127 | sub PITCH, r3, r4, lsr #1 128 | movs TLINE, #32 129 | rsb NEXTLIN, NEXTLIN, #32 130 | mov TSIZE, #1024 131 | 132 | /* y loop */ 133 | 1: cbz NTILES, 3f 134 | mov CNT, NTILES 135 | 136 | /* x loop complete tiles */ 137 | 2: pld [SRC, TSIZE] 138 | vld2.8 {d0 - d3}, [SRC :256], TSIZE 139 | subs CNT, #1 140 | vst1.8 {d0 - d1}, [DST]! 141 | vst1.8 {d2 - d3}, [DST2]! 142 | bne 2b 143 | 144 | 3: cbnz REST, 4f 145 | 146 | /* fix up dest pointer if pitch != width */ 147 | 7: add DST, PITCH 148 | add DST2, PITCH 149 | 150 | /* fix up src pointer at end of line */ 151 | subs TLINE, #1 152 | itee ne 153 | addne SRC, NEXTLIN 154 | subeq SRC, #992 155 | moveq TLINE, #32 156 | 157 | subs HEIGHT, #1 158 | bne 1b 159 | pop {r4, r5, r6, r7, r8, r9, pc} 160 | 161 | /* partly copy last tile of line */ 162 | 4: mov TMPSRC, SRC 163 | tst REST, #8 164 | beq 5f 165 | vld2.8 {d0 - d1}, [TMPSRC :128]! 166 | vst1.8 {d0}, [DST]! 167 | vst1.8 {d1}, [DST2]! 168 | 5: add SRC, TSIZE 169 | ands CNT, REST, #7 170 | beq 7b 171 | 6: vld2.8 {d0[0], d1[0]}, [TMPSRC]! 172 | subs CNT, #1 173 | vst1.8 {d0[0]}, [DST]! 174 | vst1.8 {d1[0]}, [DST2]! 175 | bne 6b 176 | b 7b 177 | end_function tiled_deinterleave_to_planar 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /tiled_yuv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #ifndef __TILED_YUV_H__ 21 | #define __TILED_YUV_H__ 22 | 23 | void tiled_to_planar(void *src, void *dst, unsigned int dst_pitch, 24 | unsigned int width, unsigned int height); 25 | 26 | void tiled_deinterleave_to_planar(void *src, void *dst1, void *dst2, 27 | unsigned int dst_pitch, 28 | unsigned int width, unsigned int height); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /vdpau_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #ifndef __VDPAU_PRIVATE_H__ 21 | #define __VDPAU_PRIVATE_H__ 22 | 23 | #define DEBUG 24 | #define MAX_HANDLES 64 25 | #define VBV_SIZE (1 * 1024 * 1024) 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "sunxi_disp.h" 33 | #include "pixman.h" 34 | 35 | #define INTERNAL_YCBCR_FORMAT (VdpYCbCrFormat)0xffff 36 | 37 | typedef struct 38 | { 39 | cedrus_t *cedrus; 40 | Display *display; 41 | int screen; 42 | VdpPreemptionCallback *preemption_callback; 43 | void *preemption_callback_context; 44 | int fd; 45 | int g2d_fd; 46 | int osd_enabled; 47 | int g2d_enabled; 48 | } device_ctx_t; 49 | 50 | typedef struct 51 | { 52 | int ref_count; 53 | cedrus_mem_t *data; 54 | } yuv_data_t; 55 | 56 | typedef struct video_surface_ctx_struct 57 | { 58 | device_ctx_t *device; 59 | uint32_t width, height; 60 | VdpChromaType chroma_type; 61 | VdpYCbCrFormat source_format; 62 | yuv_data_t *yuv; 63 | int luma_size, chroma_size; 64 | void *decoder_private; 65 | void (*decoder_private_free)(struct video_surface_ctx_struct *surface); 66 | } video_surface_ctx_t; 67 | 68 | typedef struct decoder_ctx_struct 69 | { 70 | uint32_t width, height; 71 | VdpDecoderProfile profile; 72 | cedrus_mem_t *data; 73 | device_ctx_t *device; 74 | VdpStatus (*decode)(struct decoder_ctx_struct *decoder, VdpPictureInfo const *info, const int len, video_surface_ctx_t *output); 75 | void *private; 76 | void (*private_free)(struct decoder_ctx_struct *decoder); 77 | } decoder_ctx_t; 78 | 79 | typedef struct 80 | { 81 | Drawable drawable; 82 | struct sunxi_disp *disp; 83 | } queue_target_ctx_t; 84 | 85 | typedef struct 86 | { 87 | queue_target_ctx_t *target; 88 | VdpColor background; 89 | device_ctx_t *device; 90 | } queue_ctx_t; 91 | 92 | typedef struct 93 | { 94 | device_ctx_t *device; 95 | int csc_change; 96 | float brightness; 97 | float contrast; 98 | float saturation; 99 | float hue; 100 | } mixer_ctx_t; 101 | 102 | #define RGBA_FLAG_DIRTY (1 << 0) 103 | #define RGBA_FLAG_NEEDS_FLUSH (1 << 1) 104 | #define RGBA_FLAG_NEEDS_CLEAR (1 << 2) 105 | 106 | typedef struct 107 | { 108 | device_ctx_t *device; 109 | VdpRGBAFormat format; 110 | uint32_t width, height; 111 | cedrus_mem_t *data; 112 | VdpRect dirty; 113 | uint32_t flags; 114 | pixman_image_t *pimage; 115 | } rgba_surface_t; 116 | 117 | typedef struct output_surface_ctx_struct 118 | { 119 | rgba_surface_t rgba; 120 | video_surface_ctx_t *vs; 121 | yuv_data_t *yuv; 122 | VdpRect video_src_rect, video_dst_rect; 123 | int csc_change; 124 | float brightness; 125 | float contrast; 126 | float saturation; 127 | float hue; 128 | } output_surface_ctx_t; 129 | 130 | typedef struct 131 | { 132 | rgba_surface_t rgba; 133 | VdpBool frequently_accessed; 134 | } bitmap_surface_ctx_t; 135 | 136 | #ifndef ARRAY_SIZE 137 | #define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) 138 | #endif 139 | 140 | #define max(a, b) \ 141 | ({ __typeof__ (a) _a = (a); \ 142 | __typeof__ (b) _b = (b); \ 143 | _a > _b ? _a : _b; }) 144 | 145 | #define min(a, b) \ 146 | ({ __typeof__ (a) _a = (a); \ 147 | __typeof__ (b) _b = (b); \ 148 | _a < _b ? _a : _b; }) 149 | 150 | #define min_nz(a, b) \ 151 | ({ __typeof__ (a) _a = (a); \ 152 | __typeof__ (b) _b = (b); \ 153 | _a < _b ? (_a == 0 ? _b : _a) : (_b == 0 ? _a : _b); }) 154 | 155 | #define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) 156 | 157 | #define ceil_log2(n) ((n) <= 1 ? 0 : 32 - __builtin_clz((n) - 1)) 158 | 159 | #define ALIGN(x, a) (((x) + ((typeof(x))(a) - 1)) & ~((typeof(x))(a) - 1)) 160 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 161 | 162 | 163 | #ifdef DEBUG 164 | #include 165 | #define VDPAU_DBG(format, ...) fprintf(stderr, "[VDPAU SUNXI] " format "\n", ##__VA_ARGS__) 166 | #define VDPAU_DBG_ONCE(format, ...) do { static uint8_t __once; if (!__once) { fprintf(stderr, "[VDPAU SUNXI] " format "\n", ##__VA_ARGS__); __once = 1; } } while(0) 167 | #else 168 | #define VDPAU_DBG(format, ...) 169 | #define VDPAU_DBG_ONCE(format, ...) 170 | #endif 171 | 172 | #define EXPORT __attribute__ ((visibility ("default"))) 173 | 174 | VdpStatus new_decoder_mpeg12(decoder_ctx_t *decoder); 175 | VdpStatus new_decoder_h264(decoder_ctx_t *decoder); 176 | VdpStatus new_decoder_mpeg4(decoder_ctx_t *decoder); 177 | VdpStatus new_decoder_h265(decoder_ctx_t *decoder); 178 | 179 | void yuv_unref(yuv_data_t *yuv); 180 | yuv_data_t *yuv_ref(yuv_data_t *yuv); 181 | VdpStatus yuv_prepare(video_surface_ctx_t *video_surface); 182 | 183 | typedef uint32_t VdpHandle; 184 | 185 | void *handle_create(size_t size, VdpHandle *handle); 186 | void *handle_get(VdpHandle handle); 187 | void handle_destroy(VdpHandle handle); 188 | 189 | EXPORT VdpDeviceCreateX11 vdp_imp_device_create_x11; 190 | VdpDeviceDestroy vdp_device_destroy; 191 | VdpPreemptionCallbackRegister vdp_preemption_callback_register; 192 | 193 | VdpGetProcAddress vdp_get_proc_address; 194 | 195 | VdpGetErrorString vdp_get_error_string; 196 | VdpGetApiVersion vdp_get_api_version; 197 | VdpGetInformationString vdp_get_information_string; 198 | 199 | VdpPresentationQueueTargetCreateX11 vdp_presentation_queue_target_create_x11; 200 | VdpPresentationQueueTargetDestroy vdp_presentation_queue_target_destroy; 201 | VdpPresentationQueueCreate vdp_presentation_queue_create; 202 | VdpPresentationQueueDestroy vdp_presentation_queue_destroy; 203 | VdpPresentationQueueSetBackgroundColor vdp_presentation_queue_set_background_color; 204 | VdpPresentationQueueGetBackgroundColor vdp_presentation_queue_get_background_color; 205 | VdpPresentationQueueGetTime vdp_presentation_queue_get_time; 206 | VdpPresentationQueueDisplay vdp_presentation_queue_display; 207 | VdpPresentationQueueBlockUntilSurfaceIdle vdp_presentation_queue_block_until_surface_idle; 208 | VdpPresentationQueueQuerySurfaceStatus vdp_presentation_queue_query_surface_status; 209 | 210 | VdpVideoSurfaceCreate vdp_video_surface_create; 211 | VdpVideoSurfaceDestroy vdp_video_surface_destroy; 212 | VdpVideoSurfaceGetParameters vdp_video_surface_get_parameters; 213 | VdpVideoSurfaceGetBitsYCbCr vdp_video_surface_get_bits_y_cb_cr; 214 | VdpVideoSurfacePutBitsYCbCr vdp_video_surface_put_bits_y_cb_cr; 215 | VdpVideoSurfaceQueryCapabilities vdp_video_surface_query_capabilities; 216 | VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities vdp_video_surface_query_get_put_bits_y_cb_cr_capabilities; 217 | 218 | VdpOutputSurfaceCreate vdp_output_surface_create; 219 | VdpOutputSurfaceDestroy vdp_output_surface_destroy; 220 | VdpOutputSurfaceGetParameters vdp_output_surface_get_parameters; 221 | VdpOutputSurfaceGetBitsNative vdp_output_surface_get_bits_native; 222 | VdpOutputSurfacePutBitsNative vdp_output_surface_put_bits_native; 223 | VdpOutputSurfacePutBitsIndexed vdp_output_surface_put_bits_indexed; 224 | VdpOutputSurfacePutBitsYCbCr vdp_output_surface_put_bits_y_cb_cr; 225 | VdpOutputSurfaceRenderOutputSurface vdp_output_surface_render_output_surface; 226 | VdpOutputSurfaceRenderBitmapSurface vdp_output_surface_render_bitmap_surface; 227 | VdpOutputSurfaceQueryCapabilities vdp_output_surface_query_capabilities; 228 | VdpOutputSurfaceQueryGetPutBitsNativeCapabilities vdp_output_surface_query_get_put_bits_native_capabilities; 229 | VdpOutputSurfaceQueryPutBitsIndexedCapabilities vdp_output_surface_query_put_bits_indexed_capabilities; 230 | VdpOutputSurfaceQueryPutBitsYCbCrCapabilities vdp_output_surface_query_put_bits_y_cb_cr_capabilities; 231 | 232 | VdpVideoMixerCreate vdp_video_mixer_create; 233 | VdpVideoMixerDestroy vdp_video_mixer_destroy; 234 | VdpVideoMixerRender vdp_video_mixer_render; 235 | VdpVideoMixerGetFeatureSupport vdp_video_mixer_get_feature_support; 236 | VdpVideoMixerSetFeatureEnables vdp_video_mixer_set_feature_enables; 237 | VdpVideoMixerGetFeatureEnables vdp_video_mixer_get_feature_enables; 238 | VdpVideoMixerSetAttributeValues vdp_video_mixer_set_attribute_values; 239 | VdpVideoMixerGetParameterValues vdp_video_mixer_get_parameter_values; 240 | VdpVideoMixerGetAttributeValues vdp_video_mixer_get_attribute_values; 241 | VdpVideoMixerQueryFeatureSupport vdp_video_mixer_query_feature_support; 242 | VdpVideoMixerQueryParameterSupport vdp_video_mixer_query_parameter_support; 243 | VdpVideoMixerQueryParameterValueRange vdp_video_mixer_query_parameter_value_range; 244 | VdpVideoMixerQueryAttributeSupport vdp_video_mixer_query_attribute_support; 245 | VdpVideoMixerQueryAttributeValueRange vdp_video_mixer_query_attribute_value_range; 246 | VdpGenerateCSCMatrix vdp_generate_csc_matrix; 247 | 248 | VdpDecoderCreate vdp_decoder_create; 249 | VdpDecoderDestroy vdp_decoder_destroy; 250 | VdpDecoderGetParameters vdp_decoder_get_parameters; 251 | VdpDecoderRender vdp_decoder_render; 252 | VdpDecoderQueryCapabilities vdp_decoder_query_capabilities; 253 | 254 | VdpBitmapSurfaceCreate vdp_bitmap_surface_create; 255 | VdpBitmapSurfaceDestroy vdp_bitmap_surface_destroy; 256 | VdpBitmapSurfaceGetParameters vdp_bitmap_surface_get_parameters; 257 | VdpBitmapSurfacePutBitsNative vdp_bitmap_surface_put_bits_native; 258 | VdpBitmapSurfaceQueryCapabilities vdp_bitmap_surface_query_capabilities; 259 | 260 | #endif 261 | -------------------------------------------------------------------------------- /video_mixer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Jens Kuske 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include "vdpau_private.h" 23 | #include "rgba.h" 24 | 25 | VdpStatus vdp_video_mixer_create(VdpDevice device, 26 | uint32_t feature_count, 27 | VdpVideoMixerFeature const *features, 28 | uint32_t parameter_count, 29 | VdpVideoMixerParameter const *parameters, 30 | void const *const *parameter_values, 31 | VdpVideoMixer *mixer) 32 | { 33 | device_ctx_t *dev = handle_get(device); 34 | if (!dev) 35 | return VDP_STATUS_INVALID_HANDLE; 36 | 37 | mixer_ctx_t *mix = handle_create(sizeof(*mix), mixer); 38 | if (!mix) 39 | return VDP_STATUS_RESOURCES; 40 | 41 | mix->device = dev; 42 | mix->contrast = 1.0; 43 | mix->saturation = 1.0; 44 | 45 | return VDP_STATUS_OK; 46 | } 47 | 48 | VdpStatus vdp_video_mixer_destroy(VdpVideoMixer mixer) 49 | { 50 | mixer_ctx_t *mix = handle_get(mixer); 51 | if (!mix) 52 | return VDP_STATUS_INVALID_HANDLE; 53 | 54 | handle_destroy(mixer); 55 | 56 | return VDP_STATUS_OK; 57 | } 58 | 59 | VdpStatus vdp_video_mixer_render(VdpVideoMixer mixer, 60 | VdpOutputSurface background_surface, 61 | VdpRect const *background_source_rect, 62 | VdpVideoMixerPictureStructure current_picture_structure, 63 | uint32_t video_surface_past_count, 64 | VdpVideoSurface const *video_surface_past, 65 | VdpVideoSurface video_surface_current, 66 | uint32_t video_surface_future_count, 67 | VdpVideoSurface const *video_surface_future, 68 | VdpRect const *video_source_rect, 69 | VdpOutputSurface destination_surface, 70 | VdpRect const *destination_rect, 71 | VdpRect const *destination_video_rect, 72 | uint32_t layer_count, 73 | VdpLayer const *layers) 74 | { 75 | mixer_ctx_t *mix = handle_get(mixer); 76 | if (!mix) 77 | return VDP_STATUS_INVALID_HANDLE; 78 | 79 | if (background_surface != VDP_INVALID_HANDLE) 80 | VDPAU_DBG_ONCE("Requested unimplemented background_surface"); 81 | 82 | 83 | if (current_picture_structure != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) 84 | VDPAU_DBG_ONCE("Requested unimplemented picture_structure"); 85 | 86 | 87 | 88 | output_surface_ctx_t *os = handle_get(destination_surface); 89 | if (!os) 90 | return VDP_STATUS_INVALID_HANDLE; 91 | 92 | if (os->yuv) 93 | yuv_unref(os->yuv); 94 | 95 | os->vs = handle_get(video_surface_current); 96 | if (!(os->vs)) 97 | return VDP_STATUS_INVALID_HANDLE; 98 | 99 | os->yuv = yuv_ref(os->vs->yuv); 100 | 101 | if (video_source_rect) 102 | { 103 | os->video_src_rect = *video_source_rect; 104 | } 105 | else 106 | { 107 | os->video_src_rect.x0 = os->video_src_rect.y0 = 0; 108 | os->video_src_rect.x1 = os->vs->width; 109 | os->video_src_rect.y1 = os->vs->height; 110 | } 111 | if (destination_video_rect) 112 | { 113 | os->video_dst_rect = *destination_video_rect; 114 | } 115 | else 116 | { 117 | os->video_dst_rect.x0 = os->video_dst_rect.y0 = 0; 118 | os->video_dst_rect.x1 = os->video_src_rect.x1 - os->video_src_rect.x0; 119 | os->video_dst_rect.y1 = os->video_src_rect.y1 - os->video_src_rect.y0; 120 | } 121 | 122 | os->csc_change = mix->csc_change; 123 | os->brightness = mix->brightness; 124 | os->contrast = mix->contrast; 125 | os->saturation = mix->saturation; 126 | os->hue = mix->hue; 127 | mix->csc_change = 0; 128 | 129 | if (mix->device->osd_enabled && (os->rgba.flags & RGBA_FLAG_DIRTY)) 130 | os->rgba.flags |= RGBA_FLAG_NEEDS_CLEAR; 131 | 132 | if (layer_count != 0) 133 | VDPAU_DBG_ONCE("Requested unimplemented additional layers"); 134 | 135 | 136 | return VDP_STATUS_OK; 137 | } 138 | 139 | VdpStatus vdp_video_mixer_get_feature_support(VdpVideoMixer mixer, 140 | uint32_t feature_count, 141 | VdpVideoMixerFeature const *features, 142 | VdpBool *feature_supports) 143 | { 144 | if (feature_count == 0) 145 | return VDP_STATUS_OK; 146 | 147 | if (!features || !feature_supports) 148 | return VDP_STATUS_INVALID_POINTER; 149 | 150 | mixer_ctx_t *mix = handle_get(mixer); 151 | if (!mix) 152 | return VDP_STATUS_INVALID_HANDLE; 153 | 154 | 155 | return VDP_STATUS_ERROR; 156 | } 157 | 158 | VdpStatus vdp_video_mixer_set_feature_enables(VdpVideoMixer mixer, 159 | uint32_t feature_count, 160 | VdpVideoMixerFeature const *features, 161 | VdpBool const *feature_enables) 162 | { 163 | if (feature_count == 0) 164 | return VDP_STATUS_OK; 165 | 166 | if (!features || !feature_enables) 167 | return VDP_STATUS_INVALID_POINTER; 168 | 169 | mixer_ctx_t *mix = handle_get(mixer); 170 | if (!mix) 171 | return VDP_STATUS_INVALID_HANDLE; 172 | 173 | 174 | return VDP_STATUS_OK; 175 | } 176 | 177 | VdpStatus vdp_video_mixer_get_feature_enables(VdpVideoMixer mixer, 178 | uint32_t feature_count, 179 | VdpVideoMixerFeature const *features, 180 | VdpBool *feature_enables) 181 | { 182 | if (!features || !feature_enables) 183 | return VDP_STATUS_INVALID_POINTER; 184 | 185 | mixer_ctx_t *mix = handle_get(mixer); 186 | if (!mix) 187 | return VDP_STATUS_INVALID_HANDLE; 188 | 189 | 190 | return VDP_STATUS_ERROR; 191 | } 192 | 193 | static void set_csc_matrix(mixer_ctx_t *mix, const VdpCSCMatrix *matrix) 194 | { 195 | mix->csc_change = 1; 196 | // default contrast for full-range has 1.0 as luma coefficients 197 | mix->contrast = ((*matrix)[0][0] + (*matrix)[1][0] + (*matrix)[2][0]) / 3; 198 | // the way brightness and contrast work with this driver, brightness 199 | // is the brightness of a "black" pixel 200 | mix->brightness = ((*matrix)[0][1] + (*matrix)[1][1] + (*matrix)[2][1]) / 2 + 201 | ((*matrix)[0][2] + (*matrix)[1][2] + (*matrix)[2][2]) / 2 + 202 | (*matrix)[0][3] + (*matrix)[1][3] + (*matrix)[2][3]; 203 | mix->brightness /= 3; 204 | 205 | float sin = (*matrix)[0][1] + (*matrix)[2][2]; 206 | float cos = (*matrix)[0][2] + (*matrix)[2][1]; 207 | float e = 0.001; 208 | if (-e < cos && cos < e) mix->hue = M_PI; 209 | else mix->hue = atanf(sin/cos); 210 | mix->saturation = sqrtf(sin * sin + cos * cos) / (1.403 + 1.773); 211 | } 212 | 213 | VdpStatus vdp_video_mixer_set_attribute_values(VdpVideoMixer mixer, 214 | uint32_t attribute_count, 215 | VdpVideoMixerAttribute const *attributes, 216 | void const *const *attribute_values) 217 | { 218 | if (!attributes || !attribute_values) 219 | return VDP_STATUS_INVALID_POINTER; 220 | 221 | mixer_ctx_t *mix = handle_get(mixer); 222 | if (!mix) 223 | return VDP_STATUS_INVALID_HANDLE; 224 | 225 | uint32_t i; 226 | for (i = 0; i < attribute_count; i++) 227 | if (attributes[i] == VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX) 228 | set_csc_matrix(mix, (const VdpCSCMatrix *)attribute_values[i]); 229 | 230 | return VDP_STATUS_OK; 231 | } 232 | 233 | VdpStatus vdp_video_mixer_get_parameter_values(VdpVideoMixer mixer, 234 | uint32_t parameter_count, 235 | VdpVideoMixerParameter const *parameters, 236 | void *const *parameter_values) 237 | { 238 | if (!parameters || !parameter_values) 239 | return VDP_STATUS_INVALID_POINTER; 240 | 241 | mixer_ctx_t *mix = handle_get(mixer); 242 | if (!mix) 243 | return VDP_STATUS_INVALID_HANDLE; 244 | 245 | 246 | return VDP_STATUS_ERROR; 247 | } 248 | 249 | VdpStatus vdp_video_mixer_get_attribute_values(VdpVideoMixer mixer, 250 | uint32_t attribute_count, 251 | VdpVideoMixerAttribute const *attributes, 252 | void *const *attribute_values) 253 | { 254 | if (!attributes || !attribute_values) 255 | return VDP_STATUS_INVALID_POINTER; 256 | 257 | mixer_ctx_t *mix = handle_get(mixer); 258 | if (!mix) 259 | return VDP_STATUS_INVALID_HANDLE; 260 | 261 | 262 | return VDP_STATUS_ERROR; 263 | } 264 | 265 | VdpStatus vdp_video_mixer_query_feature_support(VdpDevice device, 266 | VdpVideoMixerFeature feature, 267 | VdpBool *is_supported) 268 | { 269 | if (!is_supported) 270 | return VDP_STATUS_INVALID_POINTER; 271 | 272 | device_ctx_t *dev = handle_get(device); 273 | if (!dev) 274 | return VDP_STATUS_INVALID_HANDLE; 275 | 276 | *is_supported = VDP_FALSE; 277 | return VDP_STATUS_OK; 278 | } 279 | 280 | VdpStatus vdp_video_mixer_query_parameter_support(VdpDevice device, 281 | VdpVideoMixerParameter parameter, 282 | VdpBool *is_supported) 283 | { 284 | if (!is_supported) 285 | return VDP_STATUS_INVALID_POINTER; 286 | 287 | device_ctx_t *dev = handle_get(device); 288 | if (!dev) 289 | return VDP_STATUS_INVALID_HANDLE; 290 | 291 | switch (parameter) 292 | { 293 | case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 294 | case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 295 | case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 296 | case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 297 | *is_supported = VDP_TRUE; 298 | break; 299 | default: 300 | *is_supported = VDP_FALSE; 301 | break; 302 | } 303 | 304 | return VDP_STATUS_OK; 305 | } 306 | 307 | VdpStatus vdp_video_mixer_query_parameter_value_range(VdpDevice device, 308 | VdpVideoMixerParameter parameter, 309 | void *min_value, 310 | void *max_value) 311 | { 312 | if (!min_value || !max_value) 313 | return VDP_STATUS_INVALID_POINTER; 314 | 315 | device_ctx_t *dev = handle_get(device); 316 | if (!dev) 317 | return VDP_STATUS_INVALID_HANDLE; 318 | 319 | switch (parameter) 320 | { 321 | case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 322 | *(uint32_t *)min_value = 0; 323 | *(uint32_t *)max_value = 0; 324 | return VDP_STATUS_OK; 325 | case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 326 | case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 327 | *(uint32_t *)min_value = 0; 328 | *(uint32_t *)max_value = 8192; 329 | return VDP_STATUS_OK; 330 | } 331 | 332 | return VDP_STATUS_ERROR; 333 | } 334 | 335 | VdpStatus vdp_video_mixer_query_attribute_support(VdpDevice device, 336 | VdpVideoMixerAttribute attribute, 337 | VdpBool *is_supported) 338 | { 339 | if (!is_supported) 340 | return VDP_STATUS_INVALID_POINTER; 341 | 342 | device_ctx_t *dev = handle_get(device); 343 | if (!dev) 344 | return VDP_STATUS_INVALID_HANDLE; 345 | 346 | *is_supported = VDP_FALSE; 347 | 348 | return VDP_STATUS_OK; 349 | } 350 | 351 | VdpStatus vdp_video_mixer_query_attribute_value_range(VdpDevice device, 352 | VdpVideoMixerAttribute attribute, 353 | void *min_value, 354 | void *max_value) 355 | { 356 | if (!min_value || !max_value) 357 | return VDP_STATUS_INVALID_POINTER; 358 | 359 | device_ctx_t *dev = handle_get(device); 360 | if (!dev) 361 | return VDP_STATUS_INVALID_HANDLE; 362 | 363 | switch (attribute) 364 | { 365 | case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 366 | case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 367 | return VDP_STATUS_ERROR; 368 | 369 | case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 370 | case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 371 | case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 372 | *(float *)min_value = 0.0; 373 | *(float *)max_value = 1.0; 374 | return VDP_STATUS_OK; 375 | 376 | case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 377 | *(float *)min_value = -1.0; 378 | *(float *)max_value = 1.0; 379 | return VDP_STATUS_OK; 380 | 381 | case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 382 | *(uint8_t *)min_value = 0; 383 | *(uint8_t *)max_value = 1; 384 | return VDP_STATUS_OK; 385 | } 386 | 387 | return VDP_STATUS_ERROR; 388 | } 389 | 390 | VdpStatus vdp_generate_csc_matrix(VdpProcamp *procamp, 391 | VdpColorStandard standard, 392 | VdpCSCMatrix *csc_matrix) 393 | { 394 | if (!csc_matrix || !procamp) 395 | return VDP_STATUS_INVALID_POINTER; 396 | 397 | if (procamp->struct_version > VDP_PROCAMP_VERSION) 398 | return VDP_STATUS_INVALID_STRUCT_VERSION; 399 | 400 | // BT.601 table 401 | (*csc_matrix)[0][1] = 0.000; 402 | (*csc_matrix)[0][2] = 1.403; 403 | 404 | (*csc_matrix)[1][1] = -0.344; 405 | (*csc_matrix)[1][2] = -0.714; 406 | 407 | (*csc_matrix)[2][1] = 1.773; 408 | (*csc_matrix)[2][2] = 0.000; 409 | 410 | float uvcos = procamp->saturation * cosf(procamp->hue); 411 | float uvsin = procamp->saturation * sinf(procamp->hue); 412 | int i; 413 | for (i = 0; i < 3; i++) { 414 | (*csc_matrix)[i][0] = procamp->contrast; 415 | float u = (*csc_matrix)[i][1] * uvcos + (*csc_matrix)[i][2] * uvsin; 416 | float v = (*csc_matrix)[i][1] * uvsin + (*csc_matrix)[i][2] * uvcos; 417 | (*csc_matrix)[i][1] = u; 418 | (*csc_matrix)[i][2] = v; 419 | (*csc_matrix)[i][3] = - (u + v) / 2; 420 | (*csc_matrix)[i][3] += 0.5 - procamp->contrast / 2; 421 | (*csc_matrix)[i][3] += procamp->brightness; 422 | } 423 | 424 | return VDP_STATUS_OK; 425 | } 426 | --------------------------------------------------------------------------------