diff options
Diffstat (limited to 'src/gallium/state_trackers')
28 files changed, 1373 insertions, 383 deletions
diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h index 12f2aaddc91..0a31cf10a34 100644 --- a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h +++ b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h @@ -352,9 +352,9 @@ struct GalliumD3D10Device : public GalliumD3D10ScreenImpl<threadsafe> { for(unsigned i = 0; i < count; ++i) { - if(constbufs[i] != constant_buffers[s][i].p) + if(constbufs[i] != constant_buffers[s][start + i].p) { - constant_buffers[s][i] = constbufs[i]; + constant_buffers[s][start + i] = constbufs[i]; if(s < caps.stages && start + i < caps.constant_buffers[s]) pipe->set_constant_buffer(pipe, s, start + i, constbufs[i] ? constbufs[i]->resource : NULL); } @@ -391,11 +391,12 @@ struct GalliumD3D10Device : public GalliumD3D10ScreenImpl<threadsafe> { samplers[s][start + i] = samps[i]; sampler_csos[s].v[start + i] = samps[i] ? samps[i]->object : default_sampler; + last_different = i; } if(last_different >= 0) { num_samplers[s] = std::max(num_samplers[s], start + last_different + 1); - update_flags |= (UPDATE_SAMPLERS_SHIFT + s); + update_flags |= 1 << (UPDATE_SAMPLERS_SHIFT + s); } } } @@ -1726,9 +1727,26 @@ changed: SYNCHRONIZED; GalliumD3D11Resource<>* dst = (GalliumD3D11Resource<>*)dst_resource; GalliumD3D11Resource<>* src = (GalliumD3D11Resource<>*)src_resource; - unsigned dst_layer = d3d11_subresource_to_face(dst->resource, dst_subresource); - unsigned src_layer = d3d11_subresource_to_face(src->resource, src_subresource); - pipe->resource_resolve(pipe, dst->resource, dst_layer, src->resource, src_layer); + struct pipe_resolve_info info; + + info.dst.res = dst->resource; + info.src.res = src->resource; + info.dst.level = 0; + info.dst.layer = d3d11_subresource_to_face(dst->resource, dst_subresource); + info.src.layer = d3d11_subresource_to_face(src->resource, src_subresource); + + info.src.x0 = 0; + info.src.x1 = info.src.res->width0; + info.src.y0 = 0; + info.src.y1 = info.src.res->height0; + info.dst.x0 = 0; + info.dst.x1 = info.dst.res->width0; + info.dst.y0 = 0; + info.dst.y1 = info.dst.res->height0; + + info.mask = PIPE_MASK_RGBA | PIPE_MASK_ZS; + + pipe->resource_resolve(pipe, &info); } #if API >= 11 diff --git a/src/gallium/state_trackers/dri/common/dri_context.c b/src/gallium/state_trackers/dri/common/dri_context.c index e6612b1911d..bc8dacba1b7 100644 --- a/src/gallium/state_trackers/dri/common/dri_context.c +++ b/src/gallium/state_trackers/dri/common/dri_context.c @@ -48,6 +48,16 @@ dri_init_extensions(struct dri_context *ctx) driInitExtensions(st->ctx, NULL, GL_FALSE); } +static void +dri_pp_query(struct dri_context *ctx) +{ + unsigned int i; + + for (i = 0; i < PP_FILTERS; i++) { + ctx->pp_enabled[i] = driQueryOptioni(&ctx->optionCache, pp_filters[i].name); + } +} + GLboolean dri_create_context(gl_api api, const struct gl_config * visual, __DRIcontext * cPriv, void *sharedContextPrivate) @@ -105,6 +115,11 @@ dri_create_context(gl_api api, const struct gl_config * visual, if (api == API_OPENGL) dri_init_extensions(ctx); + // Context successfully created. See if post-processing is requested. + dri_pp_query(ctx); + + ctx->pp = pp_init(screen->base.screen, ctx->pp_enabled); + return GL_TRUE; fail: @@ -134,6 +149,8 @@ dri_destroy_context(__DRIcontext * cPriv) ctx->st->flush(ctx->st, 0, NULL); ctx->st->destroy(ctx->st); + if (ctx->pp) pp_free(ctx->pp); + FREE(ctx); } @@ -187,6 +204,13 @@ dri_make_current(__DRIcontext * cPriv, ctx->stapi->make_current(ctx->stapi, ctx->st, &draw->base, &read->base); + // This is ok to call here. If they are already init, it's a no-op. + if (draw->textures[ST_ATTACHMENT_BACK_LEFT] && draw->textures[ST_ATTACHMENT_DEPTH_STENCIL] + && ctx->pp) + pp_init_fbos(ctx->pp, draw->textures[ST_ATTACHMENT_BACK_LEFT]->width0, + draw->textures[ST_ATTACHMENT_BACK_LEFT]->height0, + draw->textures[ST_ATTACHMENT_DEPTH_STENCIL]); + return GL_TRUE; } diff --git a/src/gallium/state_trackers/dri/common/dri_context.h b/src/gallium/state_trackers/dri/common/dri_context.h index 35105e861f9..cfc8e3345e5 100644 --- a/src/gallium/state_trackers/dri/common/dri_context.h +++ b/src/gallium/state_trackers/dri/common/dri_context.h @@ -34,6 +34,7 @@ #include "pipe/p_compiler.h" #include "dri_wrapper.h" +#include "postprocess/filters.h" struct pipe_context; struct pipe_fence; @@ -61,6 +62,8 @@ struct dri_context /* gallium */ struct st_api *stapi; struct st_context_iface *st; + struct pp_queue_t *pp; + unsigned int pp_enabled[PP_FILTERS]; }; static INLINE struct dri_context * diff --git a/src/gallium/state_trackers/dri/common/dri_screen.c b/src/gallium/state_trackers/dri/common/dri_screen.c index 5931df993b0..dcb6fdf8f3c 100644 --- a/src/gallium/state_trackers/dri/common/dri_screen.c +++ b/src/gallium/state_trackers/dri/common/dri_screen.c @@ -42,15 +42,25 @@ #include "util/u_debug.h" PUBLIC const char __driConfigOptions[] = - DRI_CONF_BEGIN DRI_CONF_SECTION_PERFORMANCE - DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS) - DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0) - DRI_CONF_SECTION_END DRI_CONF_SECTION_QUALITY -/* DRI_CONF_FORCE_S3TC_ENABLE(false) */ - DRI_CONF_ALLOW_LARGE_TEXTURES(1) - DRI_CONF_SECTION_END DRI_CONF_END; - -static const uint __driNConfigOptions = 3; + DRI_CONF_BEGIN + DRI_CONF_SECTION_PERFORMANCE + DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS) + DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0) + DRI_CONF_SECTION_END + + DRI_CONF_SECTION_QUALITY +/* DRI_CONF_FORCE_S3TC_ENABLE(false) */ + DRI_CONF_ALLOW_LARGE_TEXTURES(1) + DRI_CONF_PP_CELSHADE(0) + DRI_CONF_PP_NORED(0) + DRI_CONF_PP_NOGREEN(0) + DRI_CONF_PP_NOBLUE(0) + DRI_CONF_PP_JIMENEZMLAA(0, 0, 32) + DRI_CONF_PP_JIMENEZMLAA_COLOR(0, 0, 32) + DRI_CONF_SECTION_END + DRI_CONF_END; + +static const uint __driNConfigOptions = 9; static const __DRIconfig ** dri_fill_in_modes(struct dri_screen *screen, diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c index fe4ddb312be..6cf237577ec 100644 --- a/src/gallium/state_trackers/dri/drm/dri2.c +++ b/src/gallium/state_trackers/dri/drm/dri2.c @@ -44,8 +44,19 @@ * DRI2 flush extension. */ static void -dri2_flush_drawable(__DRIdrawable *draw) +dri2_flush_drawable(__DRIdrawable *dPriv) { + struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); + struct dri_drawable *drawable = dri_drawable(dPriv); + + struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; + + if (ctx) { + if (ptex && ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) + pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); + + ctx->st->flush(ctx->st, 0, NULL); + } } static void @@ -266,7 +277,6 @@ dri2_allocate_buffer(__DRIscreen *sPriv, struct dri_screen *screen = dri_screen(sPriv); struct dri2_buffer *buffer; struct pipe_resource templ; - enum st_attachment_type statt; enum pipe_format pf; unsigned bind = 0; struct winsys_handle whandle; @@ -274,22 +284,16 @@ dri2_allocate_buffer(__DRIscreen *sPriv, switch (attachment) { case __DRI_BUFFER_FRONT_LEFT: case __DRI_BUFFER_FAKE_FRONT_LEFT: - statt = ST_ATTACHMENT_FRONT_LEFT; bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; break; case __DRI_BUFFER_BACK_LEFT: - statt = ST_ATTACHMENT_BACK_LEFT; bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; break; case __DRI_BUFFER_DEPTH: case __DRI_BUFFER_DEPTH_STENCIL: case __DRI_BUFFER_STENCIL: - statt = ST_ATTACHMENT_DEPTH_STENCIL; bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ break; - default: - statt = ST_ATTACHMENT_INVALID; - break; } switch (format) { @@ -662,20 +666,6 @@ fail: } static boolean -dri2_create_context(gl_api api, const struct gl_config * visual, - __DRIcontext * cPriv, void *sharedContextPrivate) -{ - struct dri_context *ctx = NULL; - - if (!dri_create_context(api, visual, cPriv, sharedContextPrivate)) - return FALSE; - - ctx = cPriv->driverPrivate; - - return TRUE; -} - -static boolean dri2_create_buffer(__DRIscreen * sPriv, __DRIdrawable * dPriv, const struct gl_config * visual, boolean isPixmap) @@ -702,7 +692,7 @@ const struct __DriverAPIRec driDriverAPI = { .InitScreen = NULL, .InitScreen2 = dri2_init_screen, .DestroyScreen = dri_destroy_screen, - .CreateContext = dri2_create_context, + .CreateContext = dri_create_context, .DestroyContext = dri_destroy_context, .CreateBuffer = dri2_create_buffer, .DestroyBuffer = dri_destroy_buffer, diff --git a/src/gallium/state_trackers/dri/sw/drisw.c b/src/gallium/state_trackers/dri/sw/drisw.c index a1879a8f46a..082df55e8ea 100644 --- a/src/gallium/state_trackers/dri/sw/drisw.c +++ b/src/gallium/state_trackers/dri/sw/drisw.c @@ -136,6 +136,9 @@ drisw_swap_buffers(__DRIdrawable *dPriv) ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; if (ptex) { + if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) + pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); + ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL); drisw_copy_to_front(dPriv, ptex); diff --git a/src/gallium/state_trackers/egl/Android.mk b/src/gallium/state_trackers/egl/Android.mk new file mode 100644 index 00000000000..e459bd4655e --- /dev/null +++ b/src/gallium/state_trackers/egl/Android.mk @@ -0,0 +1,54 @@ +# Mesa 3-D graphics library +# +# Copyright (C) 2010-2011 Chia-I Wu <[email protected]> +# Copyright (C) 2010-2011 LunarG Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +LOCAL_PATH := $(call my-dir) + +common_SOURCES := \ + common/egl_g3d.c \ + common/egl_g3d_api.c \ + common/egl_g3d_image.c \ + common/egl_g3d_st.c \ + common/egl_g3d_sync.c \ + common/native_helper.c + +android_SOURCES := \ + android/native_android.cpp + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(common_SOURCES) \ + $(android_SOURCES) + +LOCAL_CFLAGS := -DHAVE_ANDROID_BACKEND + +LOCAL_C_INCLUDES := \ + $(GALLIUM_TOP)/state_trackers/egl \ + $(GALLIUM_TOP)/winsys/sw \ + $(MESA_TOP)/src/egl/main \ + $(DRM_GRALLOC_TOP) + +LOCAL_MODULE := libmesa_st_egl + +include $(GALLIUM_COMMON_MK) +include $(BUILD_STATIC_LIBRARY) diff --git a/src/gallium/state_trackers/egl/android/native_android.cpp b/src/gallium/state_trackers/egl/android/native_android.cpp new file mode 100644 index 00000000000..211d6a2aeef --- /dev/null +++ b/src/gallium/state_trackers/egl/android/native_android.cpp @@ -0,0 +1,835 @@ +/* + * Mesa 3-D graphics library + * Version: 7.12 + * + * Copyright (C) 2010-2011 Chia-I Wu <[email protected]> + * Copyright (C) 2010-2011 LunarG Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#define LOG_TAG "EGL-GALLIUM" +#include <cutils/log.h> +#include <cutils/properties.h> +#include <hardware/gralloc.h> +#include <utils/Errors.h> +#include <ui/android_native_buffer.h> + +extern "C" { +#include "egllog.h" +} + +#include "util/u_memory.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_box.h" +#include "common/native.h" +#include "common/native_helper.h" +#include "android/android_sw_winsys.h" +#include "state_tracker/drm_driver.h" + +struct android_config; + +struct android_display { + struct native_display base; + + boolean use_drm; + const struct native_event_handler *event_handler; + struct android_config *configs; + int num_configs; +}; + +struct android_surface { + struct native_surface base; + + struct android_display *adpy; + android_native_window_t *win; + + /* staging color buffer for when buffer preserving is enabled */ + struct pipe_resource *color_res; + + uint stamp; + android_native_buffer_t *buf; + struct pipe_resource *buf_res; + + /* cache the current back buffers */ + struct { + int width; + int height; + int format; + } cache_key; + void *cache_handles[2]; + struct pipe_resource *cache_resources[2]; +}; + +struct android_config { + struct native_config base; +}; + +static INLINE struct android_display * +android_display(const struct native_display *ndpy) +{ + return (struct android_display *) ndpy; +} + +static INLINE struct android_surface * +android_surface(const struct native_surface *nsurf) +{ + return (struct android_surface *) nsurf; +} + +static INLINE struct android_config * +android_config(const struct native_config *nconf) +{ + return (struct android_config *) nconf; +} + +namespace android { + +static enum pipe_format +get_pipe_format(int native) +{ + enum pipe_format fmt; + + switch (native) { + case HAL_PIXEL_FORMAT_RGBA_8888: + fmt = PIPE_FORMAT_R8G8B8A8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGBX_8888: + fmt = PIPE_FORMAT_R8G8B8X8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGB_888: + fmt = PIPE_FORMAT_R8G8B8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGB_565: + fmt = PIPE_FORMAT_B5G6R5_UNORM; + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + fmt = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + case HAL_PIXEL_FORMAT_RGBA_5551: + /* fmt = PIPE_FORMAT_A1B5G5R5_UNORM; */ + case HAL_PIXEL_FORMAT_RGBA_4444: + /* fmt = PIPE_FORMAT_A4B4G4R4_UNORM; */ + default: + LOGE("unsupported native format 0x%x", native); + fmt = PIPE_FORMAT_NONE; + break; + } + + return fmt; +} + +#include <gralloc_drm_handle.h> +static int +get_handle_name(buffer_handle_t handle) +{ + struct gralloc_drm_handle_t *dh; + + /* check that the buffer is allocated by drm_gralloc and cast */ + dh = gralloc_drm_handle(handle); + + return (dh) ? dh->name : 0; +} + +/** + * Import an android_native_buffer_t allocated by the server. + */ +static struct pipe_resource * +import_buffer(struct android_display *adpy, const struct pipe_resource *templ, + struct android_native_buffer_t *abuf) +{ + struct pipe_screen *screen = adpy->base.screen; + struct pipe_resource *res; + + if (templ->bind & PIPE_BIND_RENDER_TARGET) { + if (!screen->is_format_supported(screen, templ->format, + templ->target, 0, PIPE_BIND_RENDER_TARGET)) + LOGW("importing unsupported buffer as render target"); + } + if (templ->bind & PIPE_BIND_SAMPLER_VIEW) { + if (!screen->is_format_supported(screen, templ->format, + templ->target, 0, PIPE_BIND_SAMPLER_VIEW)) + LOGW("importing unsupported buffer as sampler view"); + } + + if (adpy->use_drm) { + struct winsys_handle handle; + + memset(&handle, 0, sizeof(handle)); + handle.type = DRM_API_HANDLE_TYPE_SHARED; + /* for DRM, we need the GEM name */ + handle.handle = get_handle_name(abuf->handle); + if (!handle.handle) { + LOGE("unable to import invalid buffer %p", abuf); + return NULL; + } + + handle.stride = + abuf->stride * util_format_get_blocksize(templ->format); + + res = screen->resource_from_handle(screen, templ, &handle); + } + else { + struct android_winsys_handle handle; + + memset(&handle, 0, sizeof(handle)); + handle.handle = abuf->handle; + handle.stride = + abuf->stride * util_format_get_blocksize(templ->format); + + res = screen->resource_from_handle(screen, + templ, (struct winsys_handle *) &handle); + } + + if (!res) + LOGE("failed to import buffer %p", abuf); + + return res; +} + +static void +android_surface_clear_cache(struct native_surface *nsurf) +{ + struct android_surface *asurf = android_surface(nsurf); + int i; + + for (i = 0; i < Elements(asurf->cache_handles); i++) { + asurf->cache_handles[i] = NULL; + pipe_resource_reference(&asurf->cache_resources[i], NULL); + } + + memset(&asurf->cache_key, 0, sizeof(asurf->cache_key)); +} + +static struct pipe_resource * +android_surface_add_cache(struct native_surface *nsurf, + struct android_native_buffer_t *abuf) +{ + struct android_surface *asurf = android_surface(nsurf); + void *handle; + int idx; + + /* how about abuf->usage? */ + if (asurf->cache_key.width != abuf->width || + asurf->cache_key.height != abuf->height || + asurf->cache_key.format != abuf->format) + android_surface_clear_cache(&asurf->base); + + if (asurf->adpy->use_drm) + handle = (void *) get_handle_name(abuf->handle); + else + handle = (void *) abuf->handle; + /* NULL is invalid */ + if (!handle) { + LOGE("invalid buffer native buffer %p", abuf); + return NULL; + } + + /* find the slot to use */ + for (idx = 0; idx < Elements(asurf->cache_handles); idx++) { + if (asurf->cache_handles[idx] == handle || !asurf->cache_handles[idx]) + break; + } + if (idx == Elements(asurf->cache_handles)) { + LOGW("cache full: buf %p, width %d, height %d, format %d, usage 0x%x", + abuf, abuf->width, abuf->height, abuf->format, abuf->usage); + android_surface_clear_cache(&asurf->base); + idx = 0; + } + + if (idx == 0) { + asurf->cache_key.width = abuf->width; + asurf->cache_key.height = abuf->height; + asurf->cache_key.format = abuf->format; + } + + if (!asurf->cache_handles[idx]) { + struct pipe_resource templ; + + assert(!asurf->cache_resources[idx]); + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = get_pipe_format(asurf->buf->format); + templ.bind = PIPE_BIND_RENDER_TARGET; + if (!asurf->adpy->use_drm) { + templ.bind |= PIPE_BIND_TRANSFER_WRITE | + PIPE_BIND_TRANSFER_READ; + } + + templ.width0 = asurf->buf->width; + templ.height0 = asurf->buf->height; + templ.depth0 = 1; + templ.array_size = 1; + + if (templ.format != PIPE_FORMAT_NONE) { + asurf->cache_resources[idx] = + import_buffer(asurf->adpy, &templ, asurf->buf); + } + else { + asurf->cache_resources[idx] = NULL; + } + + asurf->cache_handles[idx] = handle; + } + + return asurf->cache_resources[idx]; +} + +/** + * Dequeue the next back buffer for rendering. + */ +static boolean +android_surface_dequeue_buffer(struct native_surface *nsurf) +{ + struct android_surface *asurf = android_surface(nsurf); + struct pipe_resource *res; + + if (asurf->win->dequeueBuffer(asurf->win, &asurf->buf) != NO_ERROR) { + LOGE("failed to dequeue window %p", asurf->win); + return FALSE; + } + + asurf->buf->common.incRef(&asurf->buf->common); + asurf->win->lockBuffer(asurf->win, asurf->buf); + + res = android_surface_add_cache(&asurf->base, asurf->buf); + if (!res) + return FALSE; + + pipe_resource_reference(&asurf->buf_res, res); + + return TRUE; +} + +/** + * Enqueue the back buffer. This will make it the next front buffer. + */ +static boolean +android_surface_enqueue_buffer(struct native_surface *nsurf) +{ + struct android_surface *asurf = android_surface(nsurf); + + pipe_resource_reference(&asurf->buf_res, NULL); + + asurf->win->queueBuffer(asurf->win, asurf->buf); + + asurf->buf->common.decRef(&asurf->buf->common); + asurf->buf = NULL; + + return TRUE; +} + +static boolean +android_surface_swap_buffers(struct native_surface *nsurf) +{ + struct android_surface *asurf = android_surface(nsurf); + struct android_display *adpy = asurf->adpy; + + if (!asurf->buf) + return TRUE; + + android_surface_enqueue_buffer(&asurf->base); + + asurf->stamp++; + adpy->event_handler->invalid_surface(&adpy->base, + &asurf->base, asurf->stamp); + + return TRUE; +} + +static void +copy_resources(struct native_display *ndpy, + struct pipe_resource *src, + struct pipe_resource *dst) +{ + struct pipe_context *pipe; + struct pipe_box box; + + pipe = ndpy_get_copy_context(ndpy); + if (!pipe) + return; + + u_box_origin_2d(src->width0, src->height0, &box); + pipe->resource_copy_region(pipe, dst, 0, 0, 0, 0, src, 0, &box); + pipe->flush(pipe, NULL); +} + +static boolean +android_surface_present(struct native_surface *nsurf, + enum native_attachment natt, + boolean preserve, + uint swap_interval) +{ + struct android_surface *asurf = android_surface(nsurf); + struct android_display *adpy = asurf->adpy; + boolean ret; + + if (swap_interval || natt != NATIVE_ATTACHMENT_BACK_LEFT) + return FALSE; + + /* we always render to color_res first when it exists */ + if (asurf->color_res) { + copy_resources(&adpy->base, asurf->color_res, asurf->buf_res); + if (!preserve) + pipe_resource_reference(&asurf->color_res, NULL); + } + else if (preserve) { + struct pipe_resource templ; + + memset(&templ, 0, sizeof(templ)); + templ.target = asurf->buf_res->target; + templ.format = asurf->buf_res->format; + templ.bind = PIPE_BIND_RENDER_TARGET; + templ.width0 = asurf->buf_res->width0; + templ.height0 = asurf->buf_res->height0; + templ.depth0 = asurf->buf_res->depth0; + templ.array_size = asurf->buf_res->array_size; + + asurf->color_res = + adpy->base.screen->resource_create(adpy->base.screen, &templ); + if (!asurf->color_res) + return FALSE; + + /* preserve the contents */ + copy_resources(&adpy->base, asurf->buf_res, asurf->color_res); + } + + return android_surface_swap_buffers(nsurf); +} + +static boolean +android_surface_validate(struct native_surface *nsurf, uint attachment_mask, + unsigned int *seq_num, struct pipe_resource **textures, + int *width, int *height) +{ + struct android_surface *asurf = android_surface(nsurf); + struct winsys_handle handle; + + if (!asurf->buf) { + if (!android_surface_dequeue_buffer(&asurf->base)) + return FALSE; + + /* color_res must be compatible with buf_res */ + if (asurf->color_res && + (asurf->color_res->format != asurf->buf_res->format || + asurf->color_res->width0 != asurf->buf_res->width0 || + asurf->color_res->height0 != asurf->buf_res->height0)) + pipe_resource_reference(&asurf->color_res, NULL); + } + + if (textures) { + /* we have access to only the back buffer */ + const enum native_attachment att = NATIVE_ATTACHMENT_BACK_LEFT; + + if (native_attachment_mask_test(attachment_mask, att)) { + textures[att] = NULL; + pipe_resource_reference(&textures[att], + (asurf->color_res) ? asurf->color_res : asurf->buf_res); + } + } + + if (seq_num) + *seq_num = asurf->stamp; + if (width) + *width = asurf->buf->width; + if (height) + *height = asurf->buf->height; + + return TRUE; +} + +static void +android_surface_wait(struct native_surface *nsurf) +{ +} + +static void +android_surface_destroy(struct native_surface *nsurf) +{ + struct android_surface *asurf = android_surface(nsurf); + int i; + + pipe_resource_reference(&asurf->color_res, NULL); + + if (asurf->buf) + android_surface_enqueue_buffer(&asurf->base); + + android_surface_clear_cache(&asurf->base); + + asurf->win->common.decRef(&asurf->win->common); + + FREE(asurf); +} + +static struct native_surface * +android_display_create_window_surface(struct native_display *ndpy, + EGLNativeWindowType win, + const struct native_config *nconf) +{ + struct android_display *adpy = android_display(ndpy); + struct android_config *aconf = android_config(nconf); + struct android_surface *asurf; + enum pipe_format format; + int val; + + if (win->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { + LOGE("invalid native window with magic 0x%x", win->common.magic); + return NULL; + } + if (win->query(win, NATIVE_WINDOW_FORMAT, &val)) { + LOGE("failed to query native window format"); + return NULL; + } + format = get_pipe_format(val); + if (format != nconf->color_format) { + LOGW("native window format 0x%x != config format 0x%x", + format, nconf->color_format); + if (!adpy->base.screen->is_format_supported(adpy->base.screen, + format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) { + LOGE("and the native window cannot be used as a render target"); + return NULL; + } + } + + asurf = CALLOC_STRUCT(android_surface); + if (!asurf) + return NULL; + + asurf->adpy = adpy; + asurf->win = win; + asurf->win->common.incRef(&asurf->win->common); + + /* request buffers that are for CPU access */ + if (!adpy->use_drm) { + native_window_set_usage(asurf->win, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + } + + asurf->base.destroy = android_surface_destroy; + asurf->base.present = android_surface_present; + asurf->base.validate = android_surface_validate; + asurf->base.wait = android_surface_wait; + + return &asurf->base; +} + +static boolean +android_display_init_configs(struct native_display *ndpy) +{ + struct android_display *adpy = android_display(ndpy); + const int native_formats[] = { + HAL_PIXEL_FORMAT_RGBA_8888, + HAL_PIXEL_FORMAT_RGBX_8888, + HAL_PIXEL_FORMAT_RGB_888, + HAL_PIXEL_FORMAT_RGB_565, + HAL_PIXEL_FORMAT_BGRA_8888, + }; + int i; + + adpy->configs = (struct android_config *) + CALLOC(Elements(native_formats), sizeof(*adpy->configs)); + if (!adpy->configs) + return FALSE; + + for (i = 0; i < Elements(native_formats); i++) { + enum pipe_format color_format; + struct android_config *aconf; + + color_format = get_pipe_format(native_formats[i]); + if (color_format == PIPE_FORMAT_NONE || + !adpy->base.screen->is_format_supported(adpy->base.screen, + color_format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) { + LOGI("skip unsupported native format 0x%x", native_formats[i]); + continue; + } + + aconf = &adpy->configs[adpy->num_configs++]; + /* only the back buffer */ + aconf->base.buffer_mask = 1 << NATIVE_ATTACHMENT_BACK_LEFT; + aconf->base.color_format = color_format; + aconf->base.window_bit = TRUE; + + aconf->base.native_visual_id = native_formats[i]; + aconf->base.native_visual_type = native_formats[i]; + } + + return TRUE; +} + +static boolean +android_display_init_drm(struct native_display *ndpy) +{ + struct android_display *adpy = android_display(ndpy); + const hw_module_t *mod; + int fd, err; + + /* get the authorized fd from gralloc */ + err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod); + if (!err) { + const gralloc_module_t *gr = (gralloc_module_t *) mod; + + err = -EINVAL; + if (gr->perform) + err = gr->perform(gr, GRALLOC_MODULE_PERFORM_GET_DRM_FD, &fd); + } + if (!err && fd >= 0) { + adpy->base.screen = + adpy->event_handler->new_drm_screen(&adpy->base, NULL, fd); + } + + if (adpy->base.screen) { + LOGI("using DRM screen"); + return TRUE; + } + else { + LOGW("failed to create DRM screen"); + LOGW("will fall back to other EGL drivers if any"); + return FALSE; + } +} + +static boolean +android_display_init_sw(struct native_display *ndpy) +{ + struct android_display *adpy = android_display(ndpy); + struct sw_winsys *ws; + + ws = android_create_sw_winsys(); + if (ws) { + adpy->base.screen = + adpy->event_handler->new_sw_screen(&adpy->base, ws); + } + + if (adpy->base.screen) { + LOGI("using SW screen"); + return TRUE; + } + else { + LOGE("failed to create SW screen"); + return FALSE; + } +} + +static boolean +android_display_init_screen(struct native_display *ndpy) +{ + struct android_display *adpy = android_display(ndpy); + + if (adpy->use_drm) + android_display_init_drm(&adpy->base); + else + android_display_init_sw(&adpy->base); + + if (!adpy->base.screen) + return FALSE; + + if (!android_display_init_configs(&adpy->base)) { + adpy->base.screen->destroy(adpy->base.screen); + adpy->base.screen = NULL; + return FALSE; + } + + return TRUE; +} + +static void +android_display_destroy(struct native_display *ndpy) +{ + struct android_display *adpy = android_display(ndpy); + + FREE(adpy->configs); + if (adpy->base.screen) + adpy->base.screen->destroy(adpy->base.screen); + FREE(adpy); +} + +static const struct native_config ** +android_display_get_configs(struct native_display *ndpy, int *num_configs) +{ + struct android_display *adpy = android_display(ndpy); + const struct native_config **configs; + int i; + + configs = (const struct native_config **) + MALLOC(adpy->num_configs * sizeof(*configs)); + if (configs) { + for (i = 0; i < adpy->num_configs; i++) + configs[i] = (const struct native_config *) &adpy->configs[i]; + if (num_configs) + *num_configs = adpy->num_configs; + } + + return configs; +} + +static int +android_display_get_param(struct native_display *ndpy, + enum native_param_type param) +{ + int val; + + switch (param) { + case NATIVE_PARAM_PRESERVE_BUFFER: + val = 1; + break; + default: + val = 0; + break; + } + + return val; +} + +static struct pipe_resource * +android_display_import_buffer(struct native_display *ndpy, + struct native_buffer *nbuf) +{ + struct android_display *adpy = android_display(ndpy); + struct android_native_buffer_t *abuf; + enum pipe_format format; + struct pipe_resource templ; + + if (nbuf->type != NATIVE_BUFFER_ANDROID) + return NULL; + + abuf = nbuf->u.android; + + if (!abuf || abuf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC || + abuf->common.version != sizeof(*abuf)) { + LOGE("invalid android native buffer"); + return NULL; + } + + format = get_pipe_format(abuf->format); + if (format == PIPE_FORMAT_NONE) + return NULL; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = format; + /* assume for texturing only */ + templ.bind = PIPE_BIND_SAMPLER_VIEW; + templ.width0 = abuf->width; + templ.height0 = abuf->height; + templ.depth0 = 1; + templ.array_size = 1; + + return import_buffer(adpy, &templ, abuf); +} + +static boolean +android_display_export_buffer(struct native_display *ndpy, + struct pipe_resource *res, + struct native_buffer *nbuf) +{ + return FALSE; +} + +static struct native_display_buffer android_display_buffer = { + android_display_import_buffer, + android_display_export_buffer +}; + +static struct android_display * +android_display_create(const struct native_event_handler *event_handler, + boolean use_sw) +{ + struct android_display *adpy; + char value[PROPERTY_VALUE_MAX]; + boolean force_sw; + + /* check if SW renderer is forced */ + if (property_get("debug.mesa.software", value, NULL)) + force_sw = (atoi(value) != 0); + else + force_sw = debug_get_bool_option("EGL_SOFTWARE", FALSE); + if (force_sw) + use_sw = TRUE; + + adpy = CALLOC_STRUCT(android_display); + if (!adpy) + return NULL; + + adpy->event_handler = event_handler; + adpy->use_drm = !use_sw; + + adpy->base.init_screen = android_display_init_screen; + adpy->base.destroy = android_display_destroy; + adpy->base.get_param = android_display_get_param; + adpy->base.get_configs = android_display_get_configs; + adpy->base.create_window_surface = android_display_create_window_surface; + + adpy->base.buffer = &android_display_buffer; + + return adpy; +} + +static const struct native_event_handler *android_event_handler; + +static struct native_display * +native_create_display(void *dpy, boolean use_sw) +{ + struct android_display *adpy; + + adpy = android_display_create(android_event_handler, use_sw); + + return (adpy) ? &adpy->base : NULL; +} + +static const struct native_platform android_platform = { + "Android", /* name */ + native_create_display +}; + +}; /* namespace android */ + +using namespace android; + +static void +android_log(EGLint level, const char *msg) +{ + switch (level) { + case _EGL_DEBUG: + LOGD("%s", msg); + break; + case _EGL_INFO: + LOGI("%s", msg); + break; + case _EGL_WARNING: + LOGW("%s", msg); + break; + case _EGL_FATAL: + LOG_FATAL("%s", msg); + break; + default: + break; + } +} + +const struct native_platform * +native_get_android_platform(const struct native_event_handler *event_handler) +{ + android_event_handler = event_handler; + /* use Android logger */ + _eglSetLogProc(android_log); + + return &android_platform; +} diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c index 6649f02b244..b5e3d99b811 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d.c @@ -132,6 +132,12 @@ egl_g3d_get_platform(_EGLDriver *drv, _EGLPlatformType plat) nplat = native_get_fbdev_platform(&egl_g3d_native_event_handler); #endif break; + case _EGL_PLATFORM_ANDROID: + plat_name = "Android"; +#ifdef HAVE_ANDROID_BACKEND + nplat = native_get_android_platform(&egl_g3d_native_event_handler); +#endif + break; default: break; } @@ -572,6 +578,11 @@ egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy) if (dpy->Platform == _EGL_PLATFORM_WAYLAND && gdpy->native->buffer) dpy->Extensions.MESA_drm_image = EGL_TRUE; +#ifdef EGL_ANDROID_image_native_buffer + if (dpy->Platform == _EGL_PLATFORM_ANDROID && gdpy->native->buffer) + dpy->Extensions.ANDROID_image_native_buffer = EGL_TRUE; +#endif + #ifdef EGL_WL_bind_wayland_display if (gdpy->native->wayland_bufmgr) dpy->Extensions.WL_bind_wayland_display = EGL_TRUE; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.c b/src/gallium/state_trackers/egl/common/egl_g3d_image.c index 7e9a29b0284..4d90c400319 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_image.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.c @@ -202,6 +202,24 @@ egl_g3d_reference_wl_buffer(_EGLDisplay *dpy, struct wl_buffer *buffer, #endif /* EGL_WL_bind_wayland_display */ +#ifdef EGL_ANDROID_image_native_buffer + +static struct pipe_resource * +egl_g3d_reference_android_native_buffer(_EGLDisplay *dpy, + struct android_native_buffer_t *buf) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct native_buffer nbuf; + + memset(&nbuf, 0, sizeof(nbuf)); + nbuf.type = NATIVE_BUFFER_ANDROID; + nbuf.u.android = buf; + + return gdpy->native->buffer->import_buffer(gdpy->native, &nbuf); +} + +#endif /* EGL_ANDROID_image_native_buffer */ + _EGLImage * egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLenum target, EGLClientBuffer buffer, @@ -239,6 +257,12 @@ egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, (struct wl_buffer *) buffer, &gimg->base, attribs); break; #endif +#ifdef EGL_ANDROID_image_native_buffer + case EGL_NATIVE_BUFFER_ANDROID: + ptex = egl_g3d_reference_android_native_buffer(dpy, + (struct android_native_buffer_t *) buffer); + break; +#endif default: ptex = NULL; break; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_st.c b/src/gallium/state_trackers/egl/common/egl_g3d_st.c index 60c3e332ac9..b839f848d7b 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_st.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_st.c @@ -126,7 +126,7 @@ pbuffer_reference_openvg_image(struct egl_g3d_surface *gsurf) } static void -pbuffer_allocate_render_texture(struct egl_g3d_surface *gsurf) +pbuffer_allocate_pbuffer_texture(struct egl_g3d_surface *gsurf) { struct egl_g3d_display *gdpy = egl_g3d_display(gsurf->base.Resource.Display); @@ -141,7 +141,8 @@ pbuffer_allocate_render_texture(struct egl_g3d_surface *gsurf) templ.depth0 = 1; templ.array_size = 1; templ.format = gsurf->stvis.color_format; - templ.bind = PIPE_BIND_RENDER_TARGET; + /* for rendering and binding to texture */ + templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; ptex = screen->resource_create(screen, &templ); gsurf->render_texture = ptex; @@ -166,7 +167,7 @@ egl_g3d_st_framebuffer_validate_pbuffer(struct st_framebuffer_iface *stfbi, if (!gsurf->render_texture) { switch (gsurf->client_buffer_type) { case EGL_NONE: - pbuffer_allocate_render_texture(gsurf); + pbuffer_allocate_pbuffer_texture(gsurf); break; case EGL_OPENVG_IMAGE: pbuffer_reference_openvg_image(gsurf); diff --git a/src/gallium/state_trackers/egl/common/native.h b/src/gallium/state_trackers/egl/common/native.h index fc50ee485fe..58593a489cd 100644 --- a/src/gallium/state_trackers/egl/common/native.h +++ b/src/gallium/state_trackers/egl/common/native.h @@ -293,6 +293,9 @@ native_get_drm_platform(const struct native_event_handler *event_handler); const struct native_platform * native_get_fbdev_platform(const struct native_event_handler *event_handler); +const struct native_platform * +native_get_android_platform(const struct native_event_handler *event_handler); + #ifdef __cplusplus } #endif diff --git a/src/gallium/state_trackers/egl/common/native_buffer.h b/src/gallium/state_trackers/egl/common/native_buffer.h index b8a66d17e12..503ed580b05 100644 --- a/src/gallium/state_trackers/egl/common/native_buffer.h +++ b/src/gallium/state_trackers/egl/common/native_buffer.h @@ -33,9 +33,11 @@ #include "pipe/p_state.h" struct native_display; +struct android_native_buffer_t; enum native_buffer_type { NATIVE_BUFFER_DRM, + NATIVE_BUFFER_ANDROID, NUM_NATIVE_BUFFERS }; @@ -50,6 +52,8 @@ struct native_buffer { unsigned handle; /**< the handle of the GEM object */ unsigned stride; } drm; + + struct android_native_buffer_t *android; /**< opaque native buffer */ } u; }; diff --git a/src/gallium/state_trackers/egl/drm/native_drm.c b/src/gallium/state_trackers/egl/drm/native_drm.c index 47910de8d3c..c013769e57d 100644 --- a/src/gallium/state_trackers/egl/drm/native_drm.c +++ b/src/gallium/state_trackers/egl/drm/native_drm.c @@ -134,8 +134,11 @@ drm_display_destroy(struct native_display *ndpy) if (drmdpy->device_name) FREE(drmdpy->device_name); - if (drmdpy->fd >= 0) - close(drmdpy->fd); + if (drmdpy->own_gbm) { + gbm_device_destroy(&drmdpy->gbmdrm->base.base); + if (drmdpy->fd >= 0) + close(drmdpy->fd); + } FREE(drmdpy); } @@ -258,7 +261,7 @@ drm_display_init_screen(struct native_display *ndpy) } static struct native_display * -drm_create_display(struct gbm_gallium_drm_device *gbmdrm, +drm_create_display(struct gbm_gallium_drm_device *gbmdrm, int own_gbm, const struct native_event_handler *event_handler) { struct drm_display *drmdpy; @@ -267,6 +270,8 @@ drm_create_display(struct gbm_gallium_drm_device *gbmdrm, if (!drmdpy) return NULL; + drmdpy->gbmdrm = gbmdrm; + drmdpy->own_gbm = own_gbm; drmdpy->fd = gbmdrm->base.base.fd; drmdpy->device_name = drm_get_device_name(drmdpy->fd); @@ -302,22 +307,30 @@ native_create_display(void *dpy, boolean use_sw) { struct gbm_gallium_drm_device *gbm; int fd; + int own_gbm = 0; gbm = dpy; if (gbm == NULL) { fd = open("/dev/dri/card0", O_RDWR); + /* FIXME: Use an internal constructor to create a gbm + * device with gallium backend directly, without setenv */ + setenv("GBM_BACKEND", "gbm_gallium_drm.so", 1); gbm = gbm_gallium_drm_device(gbm_create_device(fd)); + own_gbm = 1; } if (gbm == NULL) return NULL; if (strcmp(gbm_device_get_backend_name(&gbm->base.base), "drm") != 0 || - gbm->base.type != GBM_DRM_DRIVER_TYPE_GALLIUM) + gbm->base.type != GBM_DRM_DRIVER_TYPE_GALLIUM) { + if (own_gbm) + gbm_device_destroy(&gbm->base.base); return NULL; + } - return drm_create_display(gbm, drm_event_handler); + return drm_create_display(gbm, own_gbm, drm_event_handler); } static const struct native_platform drm_platform = { diff --git a/src/gallium/state_trackers/egl/drm/native_drm.h b/src/gallium/state_trackers/egl/drm/native_drm.h index 675a58a1922..18cebf4e276 100644 --- a/src/gallium/state_trackers/egl/drm/native_drm.h +++ b/src/gallium/state_trackers/egl/drm/native_drm.h @@ -41,6 +41,8 @@ #include "common/native_wayland_drm_bufmgr_helper.h" #endif +#include "gbm_gallium_drmint.h" + struct drm_config; struct drm_crtc; struct drm_connector; @@ -52,6 +54,8 @@ struct drm_display { const struct native_event_handler *event_handler; + struct gbm_gallium_drm_device *gbmdrm; + int own_gbm; int fd; char *device_name; struct drm_config *config; diff --git a/src/gallium/state_trackers/vdpau/decode.c b/src/gallium/state_trackers/vdpau/decode.c index 269c7a4baf8..50d63ea3f73 100644 --- a/src/gallium/state_trackers/vdpau/decode.c +++ b/src/gallium/state_trackers/vdpau/decode.c @@ -82,13 +82,22 @@ vlVdpDecoderCreate(VdpDevice device, goto error_decoder; } + vldecoder->num_buffers = pipe->screen->get_video_param + ( + pipe->screen, p_profile, + PIPE_VIDEO_CAP_NUM_BUFFERS_DESIRED + ); vldecoder->cur_buffer = 0; - for (i = 0; i < VL_NUM_DECODE_BUFFERS; ++i) { - vldecoder->buffer[i] = vldecoder->decoder->create_buffer(vldecoder->decoder); - if (!vldecoder->buffer[i]) { + vldecoder->buffers = CALLOC(vldecoder->num_buffers, sizeof(void*)); + if (!vldecoder->buffers) + goto error_alloc_buffers; + + for (i = 0; i < vldecoder->num_buffers; ++i) { + vldecoder->buffers[i] = vldecoder->decoder->create_buffer(vldecoder->decoder); + if (!vldecoder->buffers[i]) { ret = VDP_STATUS_ERROR; - goto error_buffer; + goto error_create_buffers; } } @@ -103,11 +112,15 @@ vlVdpDecoderCreate(VdpDevice device, return VDP_STATUS_OK; error_handle: -error_buffer: +error_create_buffers: + + for (i = 0; i < vldecoder->num_buffers; ++i) + if (vldecoder->buffers[i]) + vldecoder->decoder->destroy_buffer(vldecoder->decoder, vldecoder->buffers[i]); - for (i = 0; i < VL_NUM_DECODE_BUFFERS; ++i) - if (vldecoder->buffer[i]) - vldecoder->buffer[i]->destroy(vldecoder->buffer[i]); + FREE(vldecoder->buffers); + +error_alloc_buffers: vldecoder->decoder->destroy(vldecoder->decoder); @@ -128,9 +141,11 @@ vlVdpDecoderDestroy(VdpDecoder decoder) if (!vldecoder) return VDP_STATUS_INVALID_HANDLE; - for (i = 0; i < VL_NUM_DECODE_BUFFERS; ++i) - if (vldecoder->buffer[i]) - vldecoder->buffer[i]->destroy(vldecoder->buffer[i]); + for (i = 0; i < vldecoder->num_buffers; ++i) + if (vldecoder->buffers[i]) + vldecoder->decoder->destroy_buffer(vldecoder->decoder, vldecoder->buffers[i]); + + FREE(vldecoder->buffers); vldecoder->decoder->destroy(vldecoder->decoder); @@ -161,38 +176,37 @@ vlVdpDecoderGetParameters(VdpDecoder decoder, } static VdpStatus -vlVdpDecoderRenderMpeg2(struct pipe_video_decoder *decoder, - struct pipe_video_decode_buffer *buffer, - struct pipe_video_buffer *target, - VdpPictureInfoMPEG1Or2 *picture_info, - uint32_t bitstream_buffer_count, - VdpBitstreamBuffer const *bitstream_buffers) +vlVdpDecoderRenderMpeg12(struct pipe_video_decoder *decoder, + VdpPictureInfoMPEG1Or2 *picture_info, + uint32_t bitstream_buffer_count, + VdpBitstreamBuffer const *bitstream_buffers) { struct pipe_mpeg12_picture_desc picture; + struct pipe_mpeg12_quant_matrix quant; struct pipe_video_buffer *ref_frames[2]; - uint8_t intra_quantizer_matrix[64]; - unsigned num_ycbcr_blocks[3] = { 0, 0, 0 }; unsigned i; VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoding MPEG2\n"); + i = 0; + /* if surfaces equals VDP_STATUS_INVALID_HANDLE, they are not used */ - if (picture_info->forward_reference == VDP_INVALID_HANDLE) - ref_frames[0] = NULL; - else { - ref_frames[0] = ((vlVdpSurface *)vlGetDataHTAB(picture_info->forward_reference))->video_buffer; - if (!ref_frames[0]) + if (picture_info->forward_reference != VDP_INVALID_HANDLE) { + ref_frames[i] = ((vlVdpSurface *)vlGetDataHTAB(picture_info->forward_reference))->video_buffer; + if (!ref_frames[i]) return VDP_STATUS_INVALID_HANDLE; + ++i; } - if (picture_info->backward_reference == VDP_INVALID_HANDLE) - ref_frames[1] = NULL; - else { - ref_frames[1] = ((vlVdpSurface *)vlGetDataHTAB(picture_info->backward_reference))->video_buffer; - if (!ref_frames[1]) + if (picture_info->backward_reference != VDP_INVALID_HANDLE) { + ref_frames[i] = ((vlVdpSurface *)vlGetDataHTAB(picture_info->backward_reference))->video_buffer; + if (!ref_frames[i]) return VDP_STATUS_INVALID_HANDLE; + ++i; } + decoder->set_reference_frames(decoder, ref_frames, i); + memset(&picture, 0, sizeof(picture)); picture.base.profile = decoder->profile; picture.picture_coding_type = picture_info->picture_coding_type; @@ -202,24 +216,28 @@ vlVdpDecoderRenderMpeg2(struct pipe_video_decoder *decoder, picture.alternate_scan = picture_info->alternate_scan; picture.intra_vlc_format = picture_info->intra_vlc_format; picture.concealment_motion_vectors = picture_info->concealment_motion_vectors; + picture.intra_dc_precision = picture_info->intra_dc_precision; picture.f_code[0][0] = picture_info->f_code[0][0] - 1; picture.f_code[0][1] = picture_info->f_code[0][1] - 1; picture.f_code[1][0] = picture_info->f_code[1][0] - 1; picture.f_code[1][1] = picture_info->f_code[1][1] - 1; - buffer->begin_frame(buffer); + decoder->set_picture_parameters(decoder, &picture.base); - memcpy(intra_quantizer_matrix, picture_info->intra_quantizer_matrix, sizeof(intra_quantizer_matrix)); - intra_quantizer_matrix[0] = 1 << (7 - picture_info->intra_dc_precision); - buffer->set_quant_matrix(buffer, intra_quantizer_matrix, picture_info->non_intra_quantizer_matrix); + memset(&quant, 0, sizeof(quant)); + quant.base.codec = PIPE_VIDEO_CODEC_MPEG12; + quant.intra_matrix = picture_info->intra_quantizer_matrix; + quant.non_intra_matrix = picture_info->non_intra_quantizer_matrix; - for (i = 0; i < bitstream_buffer_count; ++i) - buffer->decode_bitstream(buffer, bitstream_buffers[i].bitstream_bytes, - bitstream_buffers[i].bitstream, &picture.base, num_ycbcr_blocks); + decoder->set_quant_matrix(decoder, &quant.base); + + decoder->begin_frame(decoder); - buffer->end_frame(buffer); + for (i = 0; i < bitstream_buffer_count; ++i) + decoder->decode_bitstream(decoder, bitstream_buffers[i].bitstream_bytes, + bitstream_buffers[i].bitstream); - decoder->flush_buffer(buffer, num_ycbcr_blocks, ref_frames, target); + decoder->end_frame(decoder); return VDP_STATUS_OK; } @@ -254,17 +272,19 @@ vlVdpDecoderRender(VdpDecoder decoder, // TODO: Recreate decoder with correct chroma return VDP_STATUS_INVALID_CHROMA_TYPE; - // TODO: Right now only mpeg2 is supported. + // TODO: Right now only mpeg 1 & 2 is supported. switch (vldecoder->decoder->profile) { + case PIPE_VIDEO_PROFILE_MPEG1: case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE: case PIPE_VIDEO_PROFILE_MPEG2_MAIN: ++vldecoder->cur_buffer; - vldecoder->cur_buffer %= VL_NUM_DECODE_BUFFERS; - return vlVdpDecoderRenderMpeg2(vldecoder->decoder, - vldecoder->buffer[vldecoder->cur_buffer], - vlsurf->video_buffer, - (VdpPictureInfoMPEG1Or2 *)picture_info, - bitstream_buffer_count,bitstream_buffers); + vldecoder->cur_buffer %= vldecoder->num_buffers; + + vldecoder->decoder->set_decode_buffer(vldecoder->decoder, vldecoder->buffers[vldecoder->cur_buffer]); + vldecoder->decoder->set_decode_target(vldecoder->decoder, vlsurf->video_buffer); + + return vlVdpDecoderRenderMpeg12(vldecoder->decoder, (VdpPictureInfoMPEG1Or2 *)picture_info, + bitstream_buffer_count, bitstream_buffers); break; default: diff --git a/src/gallium/state_trackers/vdpau/mixer.c b/src/gallium/state_trackers/vdpau/mixer.c index d5187006bfc..fbd24a29414 100644 --- a/src/gallium/state_trackers/vdpau/mixer.c +++ b/src/gallium/state_trackers/vdpau/mixer.c @@ -157,8 +157,7 @@ VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, vl_compositor_clear_layers(&vmixer->compositor); vl_compositor_set_buffer_layer(&vmixer->compositor, 0, surf->video_buffer, NULL, NULL); - vl_compositor_render(&vmixer->compositor, PIPE_MPEG12_PICTURE_TYPE_FRAME, - dst->surface, NULL, NULL); + vl_compositor_render(&vmixer->compositor, dst->surface, NULL, NULL); return VDP_STATUS_OK; } diff --git a/src/gallium/state_trackers/vdpau/presentation.c b/src/gallium/state_trackers/vdpau/presentation.c index 1176c7a30b7..7e324db5589 100644 --- a/src/gallium/state_trackers/vdpau/presentation.c +++ b/src/gallium/state_trackers/vdpau/presentation.c @@ -169,8 +169,7 @@ vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue, vl_compositor_clear_layers(&pq->compositor); vl_compositor_set_rgba_layer(&pq->compositor, 0, surf->sampler_view, NULL, NULL); - vl_compositor_render(&pq->compositor, PIPE_MPEG12_PICTURE_TYPE_FRAME, - drawable_surface, NULL, NULL); + vl_compositor_render(&pq->compositor, drawable_surface, NULL, NULL); pq->device->context->pipe->screen->flush_frontbuffer ( diff --git a/src/gallium/state_trackers/vdpau/vdpau_private.h b/src/gallium/state_trackers/vdpau/vdpau_private.h index e5d945629fb..5482eff0630 100644 --- a/src/gallium/state_trackers/vdpau/vdpau_private.h +++ b/src/gallium/state_trackers/vdpau/vdpau_private.h @@ -46,7 +46,6 @@ #define TOSTRING(x) QUOTEME(x) #define INFORMATION_STRING TOSTRING(INFORMATION) #define VL_HANDLES -#define VL_NUM_DECODE_BUFFERS 4 static inline enum pipe_video_chroma_format ChromaToPipe(VdpChromaType vdpau_type) @@ -256,7 +255,8 @@ typedef struct { vlVdpDevice *device; struct pipe_video_decoder *decoder; - struct pipe_video_decode_buffer *buffer[VL_NUM_DECODE_BUFFERS]; + unsigned num_buffers; + void **buffers; unsigned cur_buffer; } vlVdpDecoder; diff --git a/src/gallium/state_trackers/xorg/SConscript b/src/gallium/state_trackers/xorg/SConscript index 4ea4ec4ee8b..1768f701e48 100644 --- a/src/gallium/state_trackers/xorg/SConscript +++ b/src/gallium/state_trackers/xorg/SConscript @@ -32,6 +32,7 @@ sources = [ 'xorg_output.c', 'xorg_renderer.c', 'xorg_xv.c', + 'xorg_xvmc.c', ] st_xorg = env.ConvenienceLibrary( diff --git a/src/gallium/state_trackers/xorg/xorg_composite.c b/src/gallium/state_trackers/xorg/xorg_composite.c index f696b72e1e3..61ba6bdddf7 100644 --- a/src/gallium/state_trackers/xorg/xorg_composite.c +++ b/src/gallium/state_trackers/xorg/xorg_composite.c @@ -4,6 +4,7 @@ #include "xorg_exa_tgsi.h" #include "cso_cache/cso_context.h" +#include "util/u_format.h" #include "util/u_sampler.h" @@ -52,18 +53,17 @@ static const struct xorg_composite_blend xorg_blends[] = { static INLINE void -pixel_to_float4(Pixel pixel, float *color) +pixel_to_float4(Pixel pixel, float *color, enum pipe_format format) { - CARD32 r, g, b, a; - - a = (pixel >> 24) & 0xff; - r = (pixel >> 16) & 0xff; - g = (pixel >> 8) & 0xff; - b = (pixel >> 0) & 0xff; - color[0] = ((float)r) / 255.; - color[1] = ((float)g) / 255.; - color[2] = ((float)b) / 255.; - color[3] = ((float)a) / 255.; + const struct util_format_description *format_desc; + uint8_t packed[4]; + + format_desc = util_format_description(format); + packed[0] = pixel; + packed[1] = pixel >> 8; + packed[2] = pixel >> 16; + packed[3] = pixel >> 24; + format_desc->unpack_rgba_float(color, 0, packed, 0, 1, 1); } static boolean @@ -311,7 +311,7 @@ bind_shaders(struct exa_context *exa, int op, vs_traits |= VS_SOLID_FILL; debug_assert(pSrcPicture->format == PICT_a8r8g8b8); pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color, - exa->solid_color); + exa->solid_color, PIPE_FORMAT_B8G8R8A8_UNORM); exa->has_solid_color = TRUE; } else { debug_assert("!gradients not supported"); @@ -533,7 +533,7 @@ boolean xorg_solid_bind_state(struct exa_context *exa, unsigned vs_traits, fs_traits; struct xorg_shader shader; - pixel_to_float4(fg, exa->solid_color); + pixel_to_float4(fg, exa->solid_color, pixmap->tex->format); exa->has_solid_color = TRUE; #if 0 diff --git a/src/gallium/state_trackers/xorg/xorg_dri2.c b/src/gallium/state_trackers/xorg/xorg_dri2.c index 6f2c52eabb6..3350ac736cf 100644 --- a/src/gallium/state_trackers/xorg/xorg_dri2.c +++ b/src/gallium/state_trackers/xorg/xorg_dri2.c @@ -372,13 +372,15 @@ dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, save_accel = ms->exa->accel; ms->exa->accel = TRUE; - /* In case it won't be though, make sure the GPU copy contents of the - * source pixmap will be used for the software fallback - presumably the - * client modified them before calling in here. - */ - exaMoveInPixmap(src_priv->pPixmap); - DamageRegionAppend(src_draw, pRegion); - DamageRegionProcessPending(src_draw); + if (pSrcBuffer->attachment != DRI2BufferFrontLeft) { + /* In case it won't be though, make sure the GPU copy contents of the + * source pixmap will be used for the software fallback - presumably the + * client modified them before calling in here. + */ + exaMoveInPixmap(src_priv->pPixmap); + DamageRegionAppend(src_draw, pRegion); + DamageRegionProcessPending(src_draw); + } if (cust && cust->winsys_context_throttle) cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_SWAP); diff --git a/src/gallium/state_trackers/xorg/xorg_driver.c b/src/gallium/state_trackers/xorg/xorg_driver.c index 063ae92f6be..0ade319cdc3 100644 --- a/src/gallium/state_trackers/xorg/xorg_driver.c +++ b/src/gallium/state_trackers/xorg/xorg_driver.c @@ -817,7 +817,7 @@ drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) &ms->swapThrottling) ? X_CONFIG : X_DEFAULT; - ms->dirtyThrottling = cust ? cust->dirty_throttling : TRUE; + ms->dirtyThrottling = cust ? cust->dirty_throttling : FALSE; from_dt = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_DIRTY, &ms->dirtyThrottling) ? X_CONFIG : X_DEFAULT; diff --git a/src/gallium/state_trackers/xorg/xorg_tracker.h b/src/gallium/state_trackers/xorg/xorg_tracker.h index 664e8c75730..84a3a2fa4e2 100644 --- a/src/gallium/state_trackers/xorg/xorg_tracker.h +++ b/src/gallium/state_trackers/xorg/xorg_tracker.h @@ -222,4 +222,11 @@ void xorg_xv_init(ScreenPtr pScreen); +/*********************************************************************** + * xorg_xvmc.c + */ +void +xorg_xvmc_init(ScreenPtr pScreen, char *name); + + #endif /* _XORG_TRACKER_H_ */ diff --git a/src/gallium/state_trackers/xorg/xorg_xv.c b/src/gallium/state_trackers/xorg/xorg_xv.c index af4992fc2ed..67fd6dfb501 100644 --- a/src/gallium/state_trackers/xorg/xorg_xv.c +++ b/src/gallium/state_trackers/xorg/xorg_xv.c @@ -750,6 +750,8 @@ xorg_xv_init(ScreenPtr pScreen) if (num_adaptors) { xf86XVScreenInit(pScreen, adaptors, num_adaptors); + if (textured_adapter) + xorg_xvmc_init(pScreen, textured_adapter->name); } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because no adaptors could be initialized.\n"); diff --git a/src/gallium/state_trackers/xorg/xorg_xvmc.c b/src/gallium/state_trackers/xorg/xorg_xvmc.c new file mode 100644 index 00000000000..0f3f3f00907 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_xvmc.c @@ -0,0 +1,119 @@ +#include "xorg_tracker.h" + +#include <xf86.h> +#include <xf86xv.h> +#include <xf86xvmc.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/XvMC.h> +#include <fourcc.h> + +#define FOURCC_RGB 0x0000003 +#define XVIMAGE_RGB \ +{ \ + FOURCC_RGB, \ + XvRGB, \ + LSBFirst, \ + { \ + 'R', 'G', 'B', 0x00, \ + 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 \ + }, \ + 32, \ + XvPacked, \ + 1, \ + 24, 0x00FF0000, 0x0000FF00, 0x000000FF, \ + 0, 0, 0, \ + 0, 0, 0, \ + 0, 0, 0, \ + { \ + 'B','G','R','X', \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ + }, \ + XvTopToBottom \ +} + +static int subpicture_index_list[] = { + FOURCC_RGB, + FOURCC_IA44, + FOURCC_AI44 +}; + +static XF86MCImageIDList subpicture_list = +{ + sizeof(subpicture_index_list)/sizeof(*subpicture_index_list), + subpicture_index_list +}; + +static XF86MCSurfaceInfoRec yv12_mpeg2_surface = +{ + FOURCC_I420, + XVMC_CHROMA_FORMAT_420, + 0, + 2048, 2048, 2048, 2048, + XVMC_IDCT | XVMC_MPEG_2, + XVMC_SUBPICTURE_INDEPENDENT_SCALING | XVMC_BACKEND_SUBPICTURE, + &subpicture_list +}; + +static const XF86MCSurfaceInfoRec uyvy_mpeg2_surface = +{ + FOURCC_UYVY, + XVMC_CHROMA_FORMAT_422, + 0, + 2048, 2048, 2048, 2048, + XVMC_IDCT | XVMC_MPEG_2, + XVMC_SUBPICTURE_INDEPENDENT_SCALING | XVMC_BACKEND_SUBPICTURE, + &subpicture_list +}; + +static XF86MCSurfaceInfoPtr surfaces[] = +{ + (XF86MCSurfaceInfoPtr)&yv12_mpeg2_surface, + (XF86MCSurfaceInfoPtr)&uyvy_mpeg2_surface +}; + +static const XF86ImageRec rgb_subpicture = XVIMAGE_RGB; +static const XF86ImageRec ia44_subpicture = XVIMAGE_IA44; +static const XF86ImageRec ai44_subpicture = XVIMAGE_AI44; + +static XF86ImagePtr subpictures[] = +{ + (XF86ImagePtr)&rgb_subpicture, + (XF86ImagePtr)&ia44_subpicture, + (XF86ImagePtr)&ai44_subpicture +}; + +static const XF86MCAdaptorRec adaptor_template = +{ + "", + sizeof(surfaces)/sizeof(*surfaces), + surfaces, + sizeof(subpictures)/sizeof(*subpictures), + subpictures, + (xf86XvMCCreateContextProcPtr)NULL, + (xf86XvMCDestroyContextProcPtr)NULL, + (xf86XvMCCreateSurfaceProcPtr)NULL, + (xf86XvMCDestroySurfaceProcPtr)NULL, + (xf86XvMCCreateSubpictureProcPtr)NULL, + (xf86XvMCDestroySubpictureProcPtr)NULL +}; + +void +xorg_xvmc_init(ScreenPtr pScreen, char *name) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86MCAdaptorPtr adaptorXvMC = xf86XvMCCreateAdaptorRec(); + if (!adaptorXvMC) + return; + + *adaptorXvMC = adaptor_template; + adaptorXvMC->name = name; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[XvMC] Associated with %s.\n", name); + if (!xf86XvMCScreenInit(pScreen, 1, &adaptorXvMC)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[XvMC] Failed to initialize extension.\n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[XvMC] Extension initialized.\n"); + xf86XvMCDestroyAdaptorRec(adaptorXvMC); +} diff --git a/src/gallium/state_trackers/xorg/xvmc/surface.c b/src/gallium/state_trackers/xorg/xvmc/surface.c index 0c53b730287..79bd9c618ce 100644 --- a/src/gallium/state_trackers/xorg/xvmc/surface.c +++ b/src/gallium/state_trackers/xorg/xvmc/surface.c @@ -42,266 +42,125 @@ #include "xvmc_private.h" -static const unsigned const_empty_block_mask_420[3][2][2] = { - { { 0x20, 0x10 }, { 0x08, 0x04 } }, - { { 0x02, 0x02 }, { 0x02, 0x02 } }, - { { 0x01, 0x01 }, { 0x01, 0x01 } } -}; - -static enum pipe_mpeg12_picture_type PictureToPipe(int xvmc_pic) -{ - switch (xvmc_pic) { - case XVMC_TOP_FIELD: - return PIPE_MPEG12_PICTURE_TYPE_FIELD_TOP; - case XVMC_BOTTOM_FIELD: - return PIPE_MPEG12_PICTURE_TYPE_FIELD_BOTTOM; - case XVMC_FRAME_PICTURE: - return PIPE_MPEG12_PICTURE_TYPE_FRAME; - default: - assert(0); - } - - XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized picture type 0x%08X.\n", xvmc_pic); - - return -1; -} - -static inline void -MacroBlockTypeToPipeWeights(const XvMCMacroBlock *xvmc_mb, unsigned weights[2]) -{ - assert(xvmc_mb); - - switch (xvmc_mb->macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) { - case XVMC_MB_TYPE_MOTION_FORWARD: - weights[0] = PIPE_VIDEO_MV_WEIGHT_MAX; - weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN; - break; - - case (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD): - weights[0] = PIPE_VIDEO_MV_WEIGHT_HALF; - weights[1] = PIPE_VIDEO_MV_WEIGHT_HALF; - break; - - case XVMC_MB_TYPE_MOTION_BACKWARD: - weights[0] = PIPE_VIDEO_MV_WEIGHT_MIN; - weights[1] = PIPE_VIDEO_MV_WEIGHT_MAX; - break; - - default: - /* workaround for xines xxmc video out plugin */ - if (!(xvmc_mb->macroblock_type & ~XVMC_MB_TYPE_PATTERN)) { - weights[0] = PIPE_VIDEO_MV_WEIGHT_MAX; - weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN; - } else { - weights[0] = PIPE_VIDEO_MV_WEIGHT_MIN; - weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN; - } - break; - } -} - -static inline struct pipe_motionvector -MotionVectorToPipe(const XvMCMacroBlock *xvmc_mb, unsigned vector, - unsigned field_select_mask, unsigned weight) -{ - struct pipe_motionvector mv; - - assert(xvmc_mb); - - switch (xvmc_mb->motion_type) { - case XVMC_PREDICTION_FRAME: - mv.top.x = xvmc_mb->PMV[0][vector][0]; - mv.top.y = xvmc_mb->PMV[0][vector][1]; - mv.top.field_select = PIPE_VIDEO_FRAME; - mv.top.weight = weight; - - mv.bottom.x = xvmc_mb->PMV[0][vector][0]; - mv.bottom.y = xvmc_mb->PMV[0][vector][1]; - mv.bottom.weight = weight; - mv.bottom.field_select = PIPE_VIDEO_FRAME; - break; - - case XVMC_PREDICTION_FIELD: - mv.top.x = xvmc_mb->PMV[0][vector][0]; - mv.top.y = xvmc_mb->PMV[0][vector][1]; - mv.top.field_select = (xvmc_mb->motion_vertical_field_select & field_select_mask) ? - PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD; - mv.top.weight = weight; - - mv.bottom.x = xvmc_mb->PMV[1][vector][0]; - mv.bottom.y = xvmc_mb->PMV[1][vector][1]; - mv.bottom.field_select = (xvmc_mb->motion_vertical_field_select & (field_select_mask << 2)) ? - PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD; - mv.bottom.weight = weight; - break; - - default: // TODO: Support DUALPRIME and 16x8 - break; - } - - return mv; -} - -static inline void -UploadYcbcrBlocks(XvMCSurfacePrivate *surface, +static void +MacroBlocksToPipe(XvMCContextPrivate *context, + XvMCSurfacePrivate *surface, + unsigned int xvmc_picture_structure, const XvMCMacroBlock *xvmc_mb, - const XvMCBlockArray *xvmc_blocks) + const XvMCBlockArray *xvmc_blocks, + struct pipe_mpeg12_macroblock *mb, + unsigned int num_macroblocks) { - enum pipe_mpeg12_dct_intra intra; - enum pipe_mpeg12_dct_type coding; + unsigned int i, j, k; - unsigned tb, x, y, luma_blocks; - short *blocks; - - assert(surface); assert(xvmc_mb); + assert(xvmc_blocks); + assert(num_macroblocks); - if (!xvmc_mb->coded_block_pattern) - return; - - intra = xvmc_mb->macroblock_type & XVMC_MB_TYPE_INTRA ? - PIPE_MPEG12_DCT_INTRA : PIPE_MPEG12_DCT_DELTA; - - coding = xvmc_mb->dct_type == XVMC_DCT_TYPE_FIELD ? - PIPE_MPEG12_DCT_TYPE_FIELD : PIPE_MPEG12_DCT_TYPE_FRAME; - - blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES; - - for (y = 0, luma_blocks = 0; y < 2; ++y) { - for (x = 0; x < 2; ++x, ++tb) { - if (xvmc_mb->coded_block_pattern & const_empty_block_mask_420[0][y][x]) { + for (; num_macroblocks > 0; --num_macroblocks) { + mb->base.codec = PIPE_VIDEO_CODEC_MPEG12; + mb->x = xvmc_mb->x; + mb->y = xvmc_mb->y; + mb->macroblock_type = xvmc_mb->macroblock_type; - struct pipe_ycbcr_block *stream = surface->ycbcr[0].stream; - stream->x = xvmc_mb->x * 2 + x; - stream->y = xvmc_mb->y * 2 + y; - stream->intra = intra; - stream->coding = coding; + switch (xvmc_picture_structure) { + case XVMC_FRAME_PICTURE: + mb->macroblock_modes.bits.frame_motion_type = xvmc_mb->motion_type; + mb->macroblock_modes.bits.field_motion_type = 0; + break; - surface->ycbcr[0].num_blocks_added++; - surface->ycbcr[0].stream++; + case XVMC_TOP_FIELD: + case XVMC_BOTTOM_FIELD: + mb->macroblock_modes.bits.frame_motion_type = 0; + mb->macroblock_modes.bits.field_motion_type = xvmc_mb->motion_type; + break; - luma_blocks++; - } + default: + assert(0); } - } - - if (luma_blocks > 0) { - memcpy(surface->ycbcr[0].buffer, blocks, BLOCK_SIZE_BYTES * luma_blocks); - surface->ycbcr[0].buffer += BLOCK_SIZE_SAMPLES * luma_blocks; - blocks += BLOCK_SIZE_SAMPLES * luma_blocks; - } - - /* TODO: Implement 422, 444 */ - //assert(ctx->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420); - for (tb = 1; tb < 3; ++tb) { - if (xvmc_mb->coded_block_pattern & const_empty_block_mask_420[tb][0][0]) { + mb->macroblock_modes.bits.dct_type = xvmc_mb->dct_type; + mb->motion_vertical_field_select = xvmc_mb->motion_vertical_field_select; - struct pipe_ycbcr_block *stream = surface->ycbcr[tb].stream; - stream->x = xvmc_mb->x; - stream->y = xvmc_mb->y; - stream->intra = intra; - stream->coding = PIPE_MPEG12_DCT_TYPE_FRAME; + for (i = 0; i < 2; ++i) + for (j = 0; j < 2; ++j) + for (k = 0; k < 2; ++k) + mb->PMV[i][j][k] = xvmc_mb->PMV[i][j][k]; - memcpy(surface->ycbcr[tb].buffer, blocks, BLOCK_SIZE_BYTES); + mb->coded_block_pattern = xvmc_mb->coded_block_pattern; + mb->blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES; + mb->num_skipped_macroblocks = 0; - surface->ycbcr[tb].num_blocks_added++; - surface->ycbcr[tb].stream++; - surface->ycbcr[tb].buffer += BLOCK_SIZE_SAMPLES; - blocks += BLOCK_SIZE_SAMPLES; - } + ++xvmc_mb; + ++mb; } - } static void -MacroBlocksToPipe(XvMCSurfacePrivate *surface, - unsigned int xvmc_picture_structure, - const XvMCMacroBlock *xvmc_mb, - const XvMCBlockArray *xvmc_blocks, - unsigned int num_macroblocks) +SetDecoderStatus(XvMCSurfacePrivate *surface) { - unsigned int i, j; + struct pipe_video_decoder *decoder; + struct pipe_video_buffer *ref_frames[2]; - assert(xvmc_mb); - assert(xvmc_blocks); - assert(num_macroblocks); + XvMCContextPrivate *context_priv; - for (i = 0; i < num_macroblocks; ++i) { - unsigned mv_pos = xvmc_mb->x + surface->mv_stride * xvmc_mb->y; - unsigned mv_weights[2]; + unsigned i, num_refs = 0; - if (xvmc_mb->macroblock_type & (XVMC_MB_TYPE_PATTERN | XVMC_MB_TYPE_INTRA)) - UploadYcbcrBlocks(surface, xvmc_mb, xvmc_blocks); + assert(surface); - MacroBlockTypeToPipeWeights(xvmc_mb, mv_weights); + context_priv = surface->context->privData; + decoder = context_priv->decoder; - for (j = 0; j < 2; ++j) { - if (!surface->ref[j].mv) continue; + decoder->set_decode_buffer(decoder, surface->decode_buffer); + decoder->set_decode_target(decoder, surface->video_buffer); - surface->ref[j].mv[mv_pos] = MotionVectorToPipe - ( - xvmc_mb, j, - j ? XVMC_SELECT_FIRST_BACKWARD : XVMC_SELECT_FIRST_FORWARD, - mv_weights[j] - ); - } + for (i = 0; i < 2; ++i) { + if (surface->ref[i]) { + XvMCSurfacePrivate *ref = surface->ref[i]->privData; - ++xvmc_mb; + if (ref) + ref_frames[num_refs++] = ref->video_buffer; + } } + decoder->set_reference_frames(decoder, ref_frames, num_refs); } static void -unmap_and_flush_surface(XvMCSurfacePrivate *surface) +RecursiveEndFrame(XvMCSurfacePrivate *surface) { - struct pipe_video_buffer *ref_frames[2]; XvMCContextPrivate *context_priv; - unsigned i, num_ycbcr_blocks[3]; + unsigned i; assert(surface); context_priv = surface->context->privData; for ( i = 0; i < 2; ++i ) { - if (surface->ref[i].surface) { - XvMCSurfacePrivate *ref = surface->ref[i].surface->privData; + if (surface->ref[i]) { + XvMCSurface *ref = surface->ref[i]; assert(ref); - unmap_and_flush_surface(ref); - surface->ref[i].surface = NULL; - ref_frames[i] = ref->video_buffer; - } else { - ref_frames[i] = NULL; + surface->ref[i] = NULL; + RecursiveEndFrame(ref->privData); + surface->ref[i] = ref; } } - if (surface->mapped) { - surface->decode_buffer->end_frame(surface->decode_buffer); - for (i = 0; i < 3; ++i) - num_ycbcr_blocks[i] = surface->ycbcr[i].num_blocks_added; - context_priv->decoder->flush_buffer(surface->decode_buffer, - num_ycbcr_blocks, - ref_frames, - surface->video_buffer); - surface->mapped = 0; + if (surface->frame_started) { + surface->frame_started = 0; + SetDecoderStatus(surface); + + for (i = 0; i < 2; ++i) + surface->ref[i] = NULL; + + context_priv->decoder->end_frame(context_priv->decoder); } } PUBLIC Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface) { - static const uint8_t dummy_quant[64] = { - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 - }; - XvMCContextPrivate *context_priv; struct pipe_context *pipe; XvMCSurfacePrivate *surface_priv; @@ -323,9 +182,6 @@ Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surfac return BadAlloc; surface_priv->decode_buffer = context_priv->decoder->create_buffer(context_priv->decoder); - surface_priv->decode_buffer->set_quant_matrix(surface_priv->decode_buffer, dummy_quant, dummy_quant); - - surface_priv->mv_stride = surface_priv->decode_buffer->get_mv_stream_stride(surface_priv->decode_buffer); surface_priv->video_buffer = pipe->create_video_buffer ( pipe, PIPE_FORMAT_NV12, context_priv->decoder->chroma_format, @@ -355,15 +211,15 @@ Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int pictur XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks ) { - struct pipe_video_decode_buffer *t_buffer; + struct pipe_mpeg12_macroblock mb[num_macroblocks]; + struct pipe_video_decoder *decoder; + XvMCContextPrivate *context_priv; XvMCSurfacePrivate *target_surface_priv; XvMCSurfacePrivate *past_surface_priv; XvMCSurfacePrivate *future_surface_priv; XvMCMacroBlock *xvmc_mb; - unsigned i; - XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n", target_surface, past_surface, future_surface); @@ -394,6 +250,9 @@ Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int pictur assert(flags == 0 || flags == XVMC_SECOND_FIELD); + context_priv = context->privData; + decoder = context_priv->decoder; + target_surface_priv = target_surface->privData; past_surface_priv = past_surface ? past_surface->privData : NULL; future_surface_priv = future_surface ? future_surface->privData : NULL; @@ -402,50 +261,39 @@ Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int pictur assert(!past_surface || past_surface_priv->context == context); assert(!future_surface || future_surface_priv->context == context); - t_buffer = target_surface_priv->decode_buffer; - - // enshure that all reference frames are flushed - // not really nessasary, but speeds ups rendering + // call end frame on all referenced frames if (past_surface) - unmap_and_flush_surface(past_surface->privData); + RecursiveEndFrame(past_surface->privData); if (future_surface) - unmap_and_flush_surface(future_surface->privData); + RecursiveEndFrame(future_surface->privData); xvmc_mb = macroblocks->macro_blocks + first_macroblock; /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */ - if (target_surface_priv->mapped && ( - target_surface_priv->ref[0].surface != past_surface || - target_surface_priv->ref[1].surface != future_surface || + if (target_surface_priv->frame_started && ( + target_surface_priv->ref[0] != past_surface || + target_surface_priv->ref[1] != future_surface || (xvmc_mb->x == 0 && xvmc_mb->y == 0))) { - // If they change anyway we need to clear our surface - unmap_and_flush_surface(target_surface_priv); + // If they change anyway we must assume that the current frame is ended + RecursiveEndFrame(target_surface_priv); } - if (!target_surface_priv->mapped) { - t_buffer->begin_frame(t_buffer); - - for (i = 0; i < 3; ++i) { - target_surface_priv->ycbcr[i].num_blocks_added = 0; - target_surface_priv->ycbcr[i].stream = t_buffer->get_ycbcr_stream(t_buffer, i); - target_surface_priv->ycbcr[i].buffer = t_buffer->get_ycbcr_buffer(t_buffer, i); - } + target_surface_priv->ref[0] = past_surface; + target_surface_priv->ref[1] = future_surface; - for (i = 0; i < 2; ++i) { - target_surface_priv->ref[i].surface = i == 0 ? past_surface : future_surface; - - if (target_surface_priv->ref[i].surface) - target_surface_priv->ref[i].mv = t_buffer->get_mv_stream(t_buffer, i); - else - target_surface_priv->ref[i].mv = NULL; - } + SetDecoderStatus(target_surface_priv); - target_surface_priv->mapped = 1; + if (!target_surface_priv->frame_started) { + target_surface_priv->frame_started = 1; + decoder->begin_frame(decoder); } - MacroBlocksToPipe(target_surface_priv, picture_structure, xvmc_mb, blocks, num_macroblocks); + MacroBlocksToPipe(context_priv, target_surface_priv, picture_structure, + xvmc_mb, blocks, mb, num_macroblocks); + + context_priv->decoder->decode_macroblock(context_priv->decoder, &mb[0].base, num_macroblocks); XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface); @@ -543,7 +391,9 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable, assert(desty + desth - 1 < drawable_surface->height); */ - unmap_and_flush_surface(surface_priv); + RecursiveEndFrame(surface_priv); + + context_priv->decoder->flush(context_priv->decoder); vl_compositor_clear_layers(compositor); vl_compositor_set_buffer_layer(compositor, 0, surface_priv->video_buffer, &src_rect, NULL); @@ -567,7 +417,7 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable, // Workaround for r600g, there seems to be a bug in the fence refcounting code pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL); - vl_compositor_render(compositor, PictureToPipe(flags), context_priv->drawable_surface, &dst_rect, NULL); + vl_compositor_render(compositor, context_priv->drawable_surface, &dst_rect, NULL); pipe->flush(pipe, &surface_priv->fence); @@ -630,6 +480,7 @@ PUBLIC Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface) { XvMCSurfacePrivate *surface_priv; + XvMCContextPrivate *context_priv; XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface); @@ -639,10 +490,13 @@ Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface) return XvMCBadSurface; surface_priv = surface->privData; + context_priv = surface_priv->context->privData; - if (surface_priv->mapped) - surface_priv->decode_buffer->end_frame(surface_priv->decode_buffer); - surface_priv->decode_buffer->destroy(surface_priv->decode_buffer); + if (surface_priv->frame_started) { + SetDecoderStatus(surface_priv); + context_priv->decoder->end_frame(context_priv->decoder); + } + context_priv->decoder->destroy_buffer(context_priv->decoder, surface_priv->decode_buffer); surface_priv->video_buffer->destroy(surface_priv->video_buffer); FREE(surface_priv); surface->privData = NULL; diff --git a/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h b/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h index 5f8d9d13cb3..fd14ac916ee 100644 --- a/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h +++ b/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h @@ -45,7 +45,6 @@ struct vl_context; struct pipe_video_decoder; -struct pipe_video_decode_buffer; struct pipe_video_buffer; struct pipe_sampler_view; @@ -70,22 +69,13 @@ typedef struct typedef struct { - struct pipe_video_decode_buffer *decode_buffer; + void *decode_buffer; struct pipe_video_buffer *video_buffer; - bool mapped; // are we still mapped to memory? + // have we allready told the decoder to start a frame + bool frame_started; - struct { - unsigned num_blocks_added; - struct pipe_ycbcr_block *stream; - short *buffer; - } ycbcr[3]; - - unsigned mv_stride; - struct { - XvMCSurface *surface; - struct pipe_motionvector *mv; - } ref[2]; + XvMCSurface *ref[2]; struct pipe_fence_handle *fence; |