Commit 80964226 authored by Christian König's avatar Christian König

implement NV_vdpau_interop v7

v2: Actually implement interop between the gallium
    state tracker and the VDPAU backend.

v3: Make it also available in non legacy contexts,
    fix video buffer sharing.

v4: deny interop if we don't have the same screen object

v5: rebased on upstream changes

v6: implemented VDPAUGetSurfaceivNV, improved error handling,
    unregister all surfaces in VDPAUFiniNV

v7: squash merge with Mareks changes
Signed-off-by: Christian König's avatarChristian König <christian.koenig@amd.com>
parent 3d3a0b9b
/**************************************************************************
*
* Copyright 2013 Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
**************************************************************************/
/*
* Authors:
* Christian König <christian.koenig@amd.com>
*
*/
#ifndef _VDPAU_INTEROP_H_
#define _VDPAU_INTEROP_H_
/* driver specific functions for NV_vdpau_interop */
#define VDP_FUNC_ID_BASE_DRIVER 0x2000
#define VDP_FUNC_ID_VIDEO_SURFACE_GALLIUM (VDP_FUNC_ID_BASE_DRIVER + 0)
#define VDP_FUNC_ID_OUTPUT_SURFACE_GALLIUM (VDP_FUNC_ID_BASE_DRIVER + 1)
struct pipe_resource;
struct pipe_video_buffer;
typedef struct pipe_video_buffer *VdpVideoSurfaceGallium(uint32_t surface);
typedef struct pipe_resource *VdpOutputSurfaceGallium(uint32_t surface);
#endif /* _VDPAU_INTEROP_H_ */
......@@ -26,6 +26,9 @@
**************************************************************************/
#include <assert.h>
#include "util/u_memory.h"
#include "vdpau_private.h"
static void* ftab[67] =
......@@ -104,19 +107,31 @@ static void* ftab_winsys[1] =
&vlVdpPresentationQueueTargetCreateX11 /* VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 */
};
static void* ftab_driver[2] =
{
&vlVdpVideoSurfaceGallium, /* VDP_FUNC_ID_SURFACE_GALLIUM */
&vlVdpOutputSurfaceGallium /* VDP_FUNC_ID_OUTPUT_SURFACE_GALLIUM */
};
boolean vlGetFuncFTAB(VdpFuncId function_id, void **func)
{
assert(func);
*func = NULL;
if (function_id < VDP_FUNC_ID_BASE_WINSYS) {
if (function_id > 66)
return FALSE;
*func = ftab[function_id];
}
else {
if (function_id < Elements(ftab))
*func = ftab[function_id];
} else if (function_id < VDP_FUNC_ID_BASE_DRIVER) {
function_id -= VDP_FUNC_ID_BASE_WINSYS;
if (function_id > 0)
return FALSE;
*func = ftab_winsys[function_id];
if (function_id < Elements(ftab_winsys))
*func = ftab_winsys[function_id];
} else {
function_id -= VDP_FUNC_ID_BASE_DRIVER;
if (function_id < Elements(ftab_driver))
*func = ftab_driver[function_id];
}
return *func != NULL;
}
......@@ -725,3 +725,14 @@ vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface,
return VDP_STATUS_OK;
}
struct pipe_resource *vlVdpOutputSurfaceGallium(VdpOutputSurface surface)
{
vlVdpOutputSurface *vlsurface;
vlsurface = vlGetDataHTAB(surface);
if (!vlsurface || !vlsurface->surface)
return NULL;
return vlsurface->surface->texture;
}
......@@ -469,3 +469,24 @@ vlVdpVideoSurfaceClear(vlVdpSurface *vlsurf)
}
pipe->flush(pipe, NULL, 0);
}
/**
* Interop to mesa state tracker
*/
struct pipe_video_buffer *vlVdpVideoSurfaceGallium(VdpVideoSurface surface)
{
vlVdpSurface *p_surf = vlGetDataHTAB(surface);
if (!p_surf)
return NULL;
pipe_mutex_lock(p_surf->device->mutex);
if (p_surf->video_buffer == NULL) {
struct pipe_context *pipe = p_surf->device->context;
/* try to create a video buffer if we don't already have one */
p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
}
pipe_mutex_unlock(p_surf->device->mutex);
return p_surf->video_buffer;
}
......@@ -36,6 +36,8 @@
#include "pipe/p_compiler.h"
#include "pipe/p_video_codec.h"
#include "state_tracker/vdpau_interop.h"
#include "util/u_debug.h"
#include "util/u_rect.h"
#include "os/os_thread.h"
......@@ -498,6 +500,10 @@ VdpVideoMixerGetAttributeValues vlVdpVideoMixerGetAttributeValues;
VdpVideoMixerDestroy vlVdpVideoMixerDestroy;
VdpGenerateCSCMatrix vlVdpGenerateCSCMatrix;
/* interop to mesa state tracker */
VdpVideoSurfaceGallium vlVdpVideoSurfaceGallium;
VdpOutputSurfaceGallium vlVdpOutputSurfaceGallium;
#define VDPAU_OUT 0
#define VDPAU_ERR 1
#define VDPAU_WARN 2
......
......@@ -141,6 +141,7 @@ API_XML = \
NV_conditional_render.xml \
NV_primitive_restart.xml \
NV_texture_barrier.xml \
NV_vdpau_interop.xml \
OES_EGL_image.xml \
GL3x.xml
......
<?xml version="1.0"?>
<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
<OpenGLAPI>
<category name="GL_NV_vdpau_interop" number="396">
<function name="VDPAUInitNV" offset="assign">
<param name="vdpDevice" type="const GLvoid *"/>
<param name="getProcAddress" type="const GLvoid *"/>
</function>
<function name="VDPAUFiniNV" offset="assign"/>
<function name="VDPAURegisterVideoSurfaceNV" offset="assign">
<return type="GLintptr"/>
<param name="vdpSurface" type="const GLvoid *"/>
<param name="target" type="GLenum"/>
<param name="numTextureNames" type="GLsizei"/>
<param name="textureNames" type="const GLuint *"/>
</function>
<function name="VDPAURegisterOutputSurfaceNV" offset="assign">
<return type="GLintptr"/>
<param name="vdpSurface" type="const GLvoid *"/>
<param name="target" type="GLenum"/>
<param name="numTextureNames" type="GLsizei"/>
<param name="textureNames" type="const GLuint *"/>
</function>
<function name="VDPAUIsSurfaceNV" offset="assign">
<param name="surface" type="GLintptr"/>
</function>
<function name="VDPAUUnregisterSurfaceNV" offset="assign">
<param name="surface" type="GLintptr"/>
</function>
<function name="VDPAUGetSurfaceivNV" offset="assign">
<param name="surface" type="GLintptr"/>
<param name="pname" type="GLenum"/>
<param name="bufSize" type="GLsizei"/>
<param name="length" type="GLsizei *"/>
<param name="values" type="GLint *"/>
</function>
<function name="VDPAUSurfaceAccessNV" offset="assign">
<param name="surface" type="GLintptr"/>
<param name="access" type="GLenum"/>
</function>
<function name="VDPAUMapSurfacesNV" offset="assign">
<param name="numSurfaces" type="GLsizei"/>
<param name="surfaces" type="const GLintptr *"/>
</function>
<function name="VDPAUUnmapSurfacesNV" offset="assign">
<param name="numSurfaces" type="GLsizei"/>
<param name="surfaces" type="const GLintptr *"/>
</function>
<enum name="SURFACE_STATE_NV" value="0x86EB"/>
<enum name="SURFACE_REGISTERED_NV" value="0x86FD"/>
<enum name="SURFACE_MAPPED_NV" value="0x8700"/>
<enum name="WRITE_DISCARD_NV" value="0x88BE"/>
</category>
</OpenGLAPI>
......@@ -13118,4 +13118,6 @@
<xi:include href="EXT_transform_feedback.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="NV_vdpau_interop.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
</OpenGLAPI>
......@@ -111,6 +111,7 @@ header = """/**
#include "main/syncobj.h"
#include "main/formatquery.h"
#include "main/dispatch.h"
#include "main/vdpau.h"
#include "vbo/vbo.h"
......
......@@ -108,6 +108,7 @@ MAIN_FILES = \
$(SRCDIR)main/uniforms.c \
$(SRCDIR)main/uniform_query.cpp \
$(SRCDIR)main/varray.c \
$(SRCDIR)main/vdpau.c \
$(SRCDIR)main/version.c \
$(SRCDIR)main/viewport.c \
$(SRCDIR)main/vtxfmt.c \
......@@ -248,7 +249,8 @@ STATETRACKER_FILES = \
$(SRCDIR)state_tracker/st_manager.c \
$(SRCDIR)state_tracker/st_mesa_to_tgsi.c \
$(SRCDIR)state_tracker/st_program.c \
$(SRCDIR)state_tracker/st_texture.c
$(SRCDIR)state_tracker/st_texture.c \
$(SRCDIR)state_tracker/st_vdpau.c
PROGRAM_FILES = \
$(SRCDIR)program/arbprogparse.c \
......
......@@ -868,6 +868,20 @@ struct dd_function_table {
struct gl_framebuffer *fb,
GLuint index,
GLfloat *outValue);
/**
* \name NV_vdpau_interop interface
*/
void (*VDPAUMapSurface)(struct gl_context *ctx, GLenum target,
GLenum access, GLboolean output,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage,
const GLvoid *vdpSurface, GLuint index);
void (*VDPAUUnmapSurface)(struct gl_context *ctx, GLenum target,
GLenum access, GLboolean output,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage,
const GLvoid *vdpSurface, GLuint index);
};
......
......@@ -335,6 +335,7 @@ static const struct extension extension_table[] = {
{ "GL_NV_texture_barrier", o(NV_texture_barrier), GL, 2009 },
{ "GL_NV_texture_env_combine4", o(NV_texture_env_combine4), GLL, 1999 },
{ "GL_NV_texture_rectangle", o(NV_texture_rectangle), GLL, 2000 },
{ "GL_NV_vdpau_interop", o(NV_vdpau_interop), GL, 2010 },
{ "GL_S3_s3tc", o(ANGLE_texture_compression_dxt), GL, 1999 },
{ "GL_SGIS_generate_mipmap", o(dummy_true), GLL, 1997 },
{ "GL_SGIS_texture_border_clamp", o(ARB_texture_border_clamp), GLL, 1997 },
......
......@@ -3302,6 +3302,7 @@ struct gl_extensions
GLboolean NV_texture_barrier;
GLboolean NV_texture_env_combine4;
GLboolean NV_texture_rectangle;
GLboolean NV_vdpau_interop;
GLboolean TDFX_texture_compression_FXT1;
GLboolean OES_EGL_image;
GLboolean OES_draw_texture;
......@@ -3832,6 +3833,15 @@ struct gl_context
struct st_context *st;
void *aelt_context;
/*@}*/
/**
* \name NV_vdpau_interop
*/
/*@{*/
const void *vdpDevice;
const void *vdpGetProcAddress;
struct set *vdpSurfaces;
/*@}*/
};
......
/**************************************************************************
*
* Copyright 2013 Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
**************************************************************************/
/*
* Authors:
* Christian König <christian.koenig@amd.com>
*
*/
#include <stdbool.h>
#include "context.h"
#include "glformats.h"
#include "hash_table.h"
#include "set.h"
#include "texobj.h"
#include "teximage.h"
#include "vdpau.h"
#define MAX_TEXTURES 4
struct vdp_surface
{
GLenum target;
struct gl_texture_object *textures[MAX_TEXTURES];
GLenum access, state;
GLboolean output;
const GLvoid *vdpSurface;
};
void GLAPIENTRY
_mesa_VDPAUInitNV(const GLvoid *vdpDevice, const GLvoid *getProcAddress)
{
GET_CURRENT_CONTEXT(ctx);
if (!vdpDevice) {
_mesa_error(ctx, GL_INVALID_VALUE, "vdpDevice");
return;
}
if (!getProcAddress) {
_mesa_error(ctx, GL_INVALID_VALUE, "getProcAddress");
return;
}
if (ctx->vdpDevice || ctx->vdpGetProcAddress || ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUInitNV");
return;
}
ctx->vdpDevice = vdpDevice;
ctx->vdpGetProcAddress = getProcAddress;
ctx->vdpSurfaces = _mesa_set_create(NULL, _mesa_key_pointer_equal);
}
static void
unregister_surface(struct set_entry *entry)
{
struct vdp_surface *surf = (struct vdp_surface *)entry->key;
GET_CURRENT_CONTEXT(ctx);
if (surf->state == GL_SURFACE_MAPPED_NV) {
GLintptr surfaces[] = { (GLintptr)surf };
_mesa_VDPAUUnmapSurfacesNV(1, surfaces);
}
_mesa_set_remove(ctx->vdpSurfaces, entry);
FREE(surf);
}
void GLAPIENTRY
_mesa_VDPAUFiniNV()
{
GET_CURRENT_CONTEXT(ctx);
if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUFiniNV");
return;
}
_mesa_set_destroy(ctx->vdpSurfaces, unregister_surface);
ctx->vdpDevice = 0;
ctx->vdpGetProcAddress = 0;
ctx->vdpSurfaces = NULL;
}
static GLintptr
register_surface(struct gl_context *ctx, GLboolean isOutput,
const GLvoid *vdpSurface, GLenum target,
GLsizei numTextureNames, const GLuint *textureNames)
{
struct vdp_surface *surf;
int i;
if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV");
return (GLintptr)NULL;
}
if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE) {
_mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
return (GLintptr)NULL;
}
if (target == GL_TEXTURE_RECTANGLE && !ctx->Extensions.NV_texture_rectangle) {
_mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
return (GLintptr)NULL;
}
surf = CALLOC_STRUCT( vdp_surface );
surf->vdpSurface = vdpSurface;
surf->target = target;
surf->access = GL_READ_WRITE;
surf->state = GL_SURFACE_REGISTERED_NV;
surf->output = isOutput;
for (i = 0; i < numTextureNames; ++i) {
struct gl_texture_object *tex;
tex = _mesa_lookup_texture(ctx, textureNames[i]);
_mesa_lock_texture(ctx, tex);
if (tex->Immutable) {
_mesa_unlock_texture(ctx, tex);
FREE(surf);
_mesa_error(ctx, GL_INVALID_OPERATION,
"VDPAURegisterSurfaceNV(texture is immutable)");
return (GLintptr)NULL;
}
if (tex->Target == 0)
tex->Target = target;
else if (tex->Target != target) {
_mesa_unlock_texture(ctx, tex);
FREE(surf);
_mesa_error(ctx, GL_INVALID_OPERATION,
"VDPAURegisterSurfaceNV(target mismatch)");
return (GLintptr)NULL;
}
/* This will disallow respecifying the storage. */
tex->Immutable = GL_TRUE;
_mesa_unlock_texture(ctx, tex);
_mesa_reference_texobj(&surf->textures[i], tex);
}
_mesa_set_add(ctx->vdpSurfaces, _mesa_hash_pointer(surf), surf);
return (GLintptr)surf;
}
GLintptr GLAPIENTRY
_mesa_VDPAURegisterVideoSurfaceNV(const GLvoid *vdpSurface, GLenum target,
GLsizei numTextureNames,
const GLuint *textureNames)
{
GET_CURRENT_CONTEXT(ctx);
if (numTextureNames != 4) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAURegisterVideoSurfaceNV");
return (GLintptr)NULL;
}
return register_surface(ctx, false, vdpSurface, target,
numTextureNames, textureNames);
}
GLintptr GLAPIENTRY
_mesa_VDPAURegisterOutputSurfaceNV(const GLvoid *vdpSurface, GLenum target,
GLsizei numTextureNames,
const GLuint *textureNames)
{
GET_CURRENT_CONTEXT(ctx);
if (numTextureNames != 1) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAURegisterVideoSurfaceNV");
return (GLintptr)NULL;
}
return register_surface(ctx, true, vdpSurface, target,
numTextureNames, textureNames);
}
void GLAPIENTRY
_mesa_VDPAUIsSurfaceNV(GLintptr surface)
{
struct vdp_surface *surf = (struct vdp_surface *)surface;
GET_CURRENT_CONTEXT(ctx);
if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUIsSurfaceNV");
return;
}
if (!_mesa_set_search(ctx->vdpSurfaces, _mesa_hash_pointer(surf), surf)) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAUIsSurfaceNV");
return;
}
}
void GLAPIENTRY
_mesa_VDPAUUnregisterSurfaceNV(GLintptr surface)
{
struct vdp_surface *surf = (struct vdp_surface *)surface;
struct set_entry *entry;
int i;
GET_CURRENT_CONTEXT(ctx);
if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnregisterSurfaceNV");
return;
}
/* according to the spec it's ok when this is zero */
if (surface == 0)
return;
entry = _mesa_set_search(ctx->vdpSurfaces, _mesa_hash_pointer(surf), surf);
if (!entry) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAUUnregisterSurfaceNV");
return;
}
for (i = 0; i < MAX_TEXTURES; i++) {
if (surf->textures[i]) {
surf->textures[i]->Immutable = GL_FALSE;
_mesa_reference_texobj(&surf->textures[i], NULL);
}
}
_mesa_set_remove(ctx->vdpSurfaces, entry);
FREE(surf);
}
void GLAPIENTRY
_mesa_VDPAUGetSurfaceivNV(GLintptr surface, GLenum pname, GLsizei bufSize,
GLsizei *length, GLint *values)
{
struct vdp_surface *surf = (struct vdp_surface *)surface;
GET_CURRENT_CONTEXT(ctx);
if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUGetSurfaceivNV");
return;
}
if (!_mesa_set_search(ctx->vdpSurfaces, _mesa_hash_pointer(surf), surf)) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAUGetSurfaceivNV");
return;
}
if (pname != GL_SURFACE_STATE_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "VDPAUGetSurfaceivNV");
return;
}
if (bufSize < 1) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAUGetSurfaceivNV");
return;
}
values[0] = surf->state;
if (length != NULL)
*length = 1;
}
void GLAPIENTRY
_mesa_VDPAUSurfaceAccessNV(GLintptr surface, GLenum access)
{
struct vdp_surface *surf = (struct vdp_surface *)surface;
GET_CURRENT_CONTEXT(ctx);
if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
_mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
return;
}
if (!_mesa_set_search(ctx->vdpSurfaces, _mesa_hash_pointer(surf), surf)) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
return;
}
if (access != GL_READ_ONLY && access != GL_WRITE_ONLY &&
access != GL_READ_WRITE) {
_mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
return;