480 lines
19 KiB
C
480 lines
19 KiB
C
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
// Licensed under the terms of a valid Unreal Engine license agreement,
|
|
// and the separate 'Unreal Engine End User License Agreement for Publishing'.
|
|
|
|
// Copyright Epic Games Tools, LLC. All Rights Reserved.
|
|
|
|
/*
|
|
This is Epics's high level API for using 3D hardware to do Bink GPU-assisted
|
|
decoding and color conversion. It is supported on every 3D platform that
|
|
Bink runs on.
|
|
|
|
It's a simple API, so you should see your platform's example code
|
|
to see all the nitty-gritty details.
|
|
|
|
|
|
There two functions to start and stop Bink textures:
|
|
|
|
Create_Bink_shaders: This function creates the pixel shaders we use to
|
|
do the color space conversion. On most platforms, you need to provide
|
|
a pointer to GPU device pointer.
|
|
All of the other functions hang off the object that is returned here.
|
|
|
|
Free_Bink_shaders: Frees the pixel shaders created in Create_Bink_shaders.
|
|
|
|
There are four textures functions:
|
|
|
|
Create_Bink_textures: This function takes BINK object, creates the texture
|
|
resources to render it quickly and binds them together for rendering.
|
|
|
|
Free_Bink_textures: Frees the resources allocated in Create_Bink_textures.
|
|
|
|
Draw_Bink_textures: Renders the textures onto the screen.
|
|
|
|
Start_Bink_texture_update: This function starts the texture updating process.
|
|
It should be called before you call BinkDoFrame (synchronous or async).
|
|
On some platforms, this locks/maps the texture for updating; on consoles, it
|
|
makes sure that the GPU is done reading from the texture buffers that we're
|
|
about to overwrite.
|
|
|
|
Finish_Bink_texture_update: This function finishes the texture updating process.
|
|
It should be called after BinkDoFrame processing is done (in async mode: after
|
|
BinkDoFrameAsyncWait returns true). This will unlock/unmap textures (where it
|
|
applies) or issue a blit to transfer the new image data. On most consoles with
|
|
unified memory, we decode directly into GPU-readable memory, and this operation
|
|
is a no-op.
|
|
|
|
On Windows D3D9, there are two other functions:
|
|
|
|
Before_Reset_Bink_textures: Call before you call the D3D Reset function.
|
|
|
|
After_Reset_Bink_textures: Call after you call the D3D Reset function.
|
|
|
|
For Windows GL or D3D11, you simply free and re-create the textures completely
|
|
whenever the device is lost or reset.
|
|
|
|
|
|
|
|
So, basically, playback works like this:
|
|
|
|
1) Call Create_Bink_shaders to create the pixel shaders.
|
|
|
|
2) Open the Bink file with the BINKNOFRAMEBUFFERS flag (the Binktexture
|
|
implementations will allocate the memory to decompress into).
|
|
|
|
3) Call Create_Bink_textures to create the textures and bind the textures
|
|
into the Bink.
|
|
|
|
4) Call Start_Bink_texture_update before BinkDoFrame.
|
|
|
|
5) Call BinkDoFrame to decompress a video frame.
|
|
|
|
6) Call Finish_Bink_texture_update after BinkDoFrame (or after
|
|
BinkDoFrameAsyncWait returns true, if you're using async decoding).
|
|
|
|
7) Draw the frame using Draw_Bink_textures.
|
|
|
|
|
|
And that's it! (Skipping over a few details - see the examples for all
|
|
the details...)
|
|
|
|
Should drop in really quickly and it hides a ton of platform specific ugliness!
|
|
*/
|
|
|
|
#ifndef BINKTEXTURESH
|
|
#define BINKTEXTURESH
|
|
|
|
#ifndef __BINKH__
|
|
#include "bink.h"
|
|
#endif
|
|
|
|
RADDEFSTART
|
|
|
|
//=============================================================================
|
|
|
|
// On some platforms, you might have one app that uses BinkTextures with multiple
|
|
// graphics APIs - these defines let you have multiple providers in one
|
|
// EXE by suffixing the names of D3D9 and D3D11 (GL gets the non-suffix).
|
|
// This does mean that you must include D3D9 and/or D3D11 headers before
|
|
// including BinkTextures.h!
|
|
|
|
#if defined( BINKTEXTURESGPUAPITYPE )
|
|
|
|
#if defined( __d3d12_x_h__ ) || defined( __d3d12_xs_h__ ) ||defined( __d3d12_h__ ) || defined( BINKD3D12FUNCTIONS ) || defined( BINKD3D12GPUFUNCTIONS )
|
|
#ifdef BINKD3D12GPUFUNCTIONS
|
|
#define BINKTEXTURESSUFFIX D3D12GPU
|
|
#else
|
|
#define BINKTEXTURESSUFFIX D3D12
|
|
#endif
|
|
#elif defined( __d3d11_x_h__ ) || defined( __d3d11_h__ ) || defined( BINKD3D11FUNCTIONS ) || defined( BINKD3D11GPUFUNCTIONS )
|
|
#ifdef BINKD3D11GPUFUNCTIONS
|
|
#define BINKTEXTURESSUFFIX D3D11GPU
|
|
#else
|
|
#define BINKTEXTURESSUFFIX D3D11
|
|
#endif
|
|
#elif defined( _D3D9_H_ ) || defined( BINKD3D9FUNCTIONS )
|
|
#define BINKTEXTURESSUFFIX D3D9
|
|
#elif defined( BINKMETALFUNCTIONS )
|
|
#define BINKTEXTURESSUFFIX Metal
|
|
#elif defined( BINKVULKANFUNCTIONS )
|
|
#define BINKTEXTURESSUFFIX Vulkan
|
|
#elif defined(__gl_es20_h_) || defined(__gl_h_) || defined(__gl2_h_) || defined(__gl3_h_) || defined( BINKGLFUNCTIONS ) || defined(BINKGLGPUFUNCTIONS)
|
|
#ifdef BINKGLGPUFUNCTIONS
|
|
#define BINKTEXTURESSUFFIX GLGPU
|
|
#else
|
|
#define BINKTEXTURESSUFFIX GL
|
|
#endif
|
|
#elif defined(BINKNDAFUNCTIONS)
|
|
#define BINKTEXTURESSUFFIX BINKNDAFUNCTIONS
|
|
#elif defined(BINKRHIFUNCTIONS)
|
|
#define BINKTEXTURESSUFFIX RHI
|
|
#else
|
|
#ifndef BINKTEXTURESSUFFIX
|
|
#define BINKTEXTURESSUFFIX Null
|
|
#endif
|
|
#endif
|
|
|
|
#define Create_Bink_shaders RR_STRING_JOIN( Create_Bink_shaders, BINKTEXTURESSUFFIX )
|
|
|
|
#endif
|
|
|
|
typedef struct BINKSHADERS2 BINKSHADERS; // defined below
|
|
typedef struct BINKTEXTURES2 BINKTEXTURES; // defined below
|
|
|
|
//=============================================================================
|
|
|
|
// For some APIs, you need to pass structs as argument to our functions.
|
|
// This is where they get defined.
|
|
|
|
#if ( defined( __d3d12_h__ ) || defined( __d3d12_x_h__ ) || defined( __d3d12_xs_h__ ) ) && !defined( BINKTEXTURESD3D12STRUCTSDEF )
|
|
|
|
// BinkGPU can call you back at the beginning/end of its compute command lists in case you want to
|
|
// insert timestamp queries (or other markup) into the command list.
|
|
typedef void BINKGPUCOMMANDLISTCALLBACKD3D12( BINKTEXTURES * bink_tex, ID3D12GraphicsCommandList * cl, BOOL is_end, void * user_ptr );
|
|
|
|
// This is what you pass as "device" to Create_shaders.
|
|
typedef struct BINKCREATESHADERSD3D12 {
|
|
// The D3D12 device to use
|
|
ID3D12Device * device;
|
|
|
|
// Command queue to submit work to in BinkGPU mode. Ignored in CPU decoding mode.
|
|
ID3D12CommandQueue * gpu_mode_command_queue;
|
|
|
|
// The fence to use for synchronization. Needs to be updated from app code!
|
|
ID3D12Fence * fence;
|
|
|
|
// Prototype graphics pipeline state. Create Bink pipelines for the
|
|
// specified set of rasterizer state (multisampling or not),
|
|
// render target formats, etc. See binktexturesD3D12.cpp for
|
|
// details.
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC prototype;
|
|
|
|
// Callback to run at beginning/end of BinkGPU command list. Ignored in CPU decoding mode.
|
|
BINKGPUCOMMANDLISTCALLBACKD3D12 * gpu_command_list_callback;
|
|
void * gpu_command_list_user_ptr;
|
|
} BINKCREATESHADERSD3D12;
|
|
|
|
// This is what you pass as context to Draw_textures.
|
|
typedef struct BINKAPICONTEXTD3D12 {
|
|
// ---- Input parameters you provide
|
|
|
|
// Command list to render to
|
|
ID3D12GraphicsCommandList * command_list; // Command list to render to
|
|
|
|
// Fence value you're going to write via the command queue after executing
|
|
// the command_list. The sequence of fence values written needs to be
|
|
// monotonically increasing over time. This is what we use to synchronize
|
|
// buffer upload ands resource management!
|
|
UINT64 fence_value;
|
|
|
|
// ---- Output parameters we return
|
|
|
|
// In GPU decode mode, the draw command list may only run after decoding
|
|
// the frame has finished. Thus you need to call "Wait" on your graphics
|
|
// command queue to make sure our decode fence is signaled to the correct
|
|
// value before decoding can start.
|
|
//
|
|
// NOTE: "out_gpu_decode_fence" is not AddRef'd before being returned, so please
|
|
// don't call Release on it!
|
|
|
|
ID3D12Fence * out_gpu_decode_fence; // In GPU mode, this is the fence you have to call wait on before submitting command_list.
|
|
UINT64 out_gpu_decode_fence_val; // In GPU mode, this is the fence value you have to wait for before submitting command_list.
|
|
} BINKAPICONTEXTD3D12;
|
|
|
|
// We promise not to request more SRV descriptors than this per Bink, for any D3D12 BinkTextures implementation.
|
|
// So if you want to use a simple free list allocator for Bink video descriptors, you can just use this as your
|
|
// allocation granularity.
|
|
#define BINKTEXTURESD3D12_MAX_SRVS_PER_BINK 128
|
|
|
|
#define BINKTEXTURESD3D12STRUCTSDEF
|
|
|
|
#endif
|
|
|
|
#ifndef BINKCREATESHADERSPIPEANDQUEUEd
|
|
#define BINKCREATESHADERSPIPEANDQUEUEd
|
|
|
|
// Create_Bink_Shaders for some nda GPU implementations allows you to select which async compute pipe and queue ID to run
|
|
// decoding jobs on. If not specified, we use our default. (At the time of writing, this is pipe 6, queue 1).
|
|
// Fill out this struct and pass a pointer to it as "device" to Create_Bink_shaders.
|
|
typedef struct BINKCREATESHADERSPIPEANDQUEUE
|
|
{
|
|
// Which async compute pipe to use for BinkGPU. Ignored for CPU decoding.
|
|
// Corresponds to the "pipeId" in ComputeQueue::initialize.
|
|
U32 pipe_id;
|
|
|
|
// Which queue to use for BinkGPU on the given compute pipe. Ignored for CPU decoding.
|
|
// Corresponds to the "queueId" in ComputeQueue::initialize.
|
|
U32 queue_id;
|
|
} BINKCREATESHADERSPIPEANDQUEUE;
|
|
|
|
#endif
|
|
|
|
#ifndef BINKTEXTURES_METAL_DEF
|
|
#define BINKTEXTURES_METAL_DEF
|
|
|
|
// Create_Bink_Shaders for Metal needs a few more parameters - pass a pointer to this structure.
|
|
|
|
typedef struct BINKCREATESHADERSMETAL
|
|
{
|
|
void * mtlDevice;
|
|
void * stateDesc[2]; // MTLRenderPipelineDescriptor *
|
|
void * mtlQueue; // used on GPU-assist Bink Metal only
|
|
U32 render_target_formats[2]; // MTLPixelFormat(s) that we can render to
|
|
} BINKCREATESHADERSMETAL;
|
|
|
|
|
|
typedef struct BINKAPICONTEXTMETAL
|
|
{
|
|
void * command_buffer; // id <MTLCommandBuffer>
|
|
void * command_encoder; // id <MTLRenderCommandEncoder>
|
|
void * frame_texture; // View.currentDrawable.texture
|
|
U32 format_idx; // Index into render_target_formats. See BINKCREATESHADERSMETAL
|
|
} BINKAPICONTEXTMETAL;
|
|
|
|
#endif
|
|
|
|
#ifndef BINKTEXTURES_VULKAN_DEF
|
|
#define BINKTEXTURES_VULKAN_DEF
|
|
typedef struct BINKCREATESHADERSVULKAN
|
|
{
|
|
void *physical_device; // VkPhysicalDevice
|
|
void *logical_device; // VkDevice
|
|
void *queue; // VkQueue (needs graphics+compute capabilities where compute is only used for gpu decode)
|
|
U32 render_target_formats[2]; // VkFormat(s) that we can render to
|
|
} BINKCREATESHADERSVULKAN;
|
|
|
|
typedef struct BINKAPICONTEXTVULKAN
|
|
{
|
|
void * cmdbuf; // VkCommandBuffer
|
|
U32 format_idx; // Index into render_target_formats. See BINKCREATESHADERSVULKAN
|
|
} BINKAPICONTEXTVULKAN;
|
|
#endif
|
|
|
|
//=============================================================================
|
|
|
|
// Creates shaders that Bink uses.
|
|
// The value that you pass for device depends on the graphics API:
|
|
// D3D9 - The d3d9 device (type LPDIRECT3DDEVICE9)
|
|
// D3D11 - The d3d11 device (type D3D11Device *)
|
|
// D3D12 - Pointer to a filled-out BINKCREATESHADERSD3D12 struct
|
|
// GL - Parameter not used, just pass 0
|
|
// PS4 - Pass 0 for default parameters, or a pointer to a filled-out BINKCREATESHADERSPS4 struct
|
|
// Metal - Pointer to a filled out BINKCREATESHADERSMETAL struct
|
|
BINKSHADERS * Create_Bink_shaders( void * device );
|
|
|
|
// free our shaders
|
|
typedef void Free_Bink_shaders_ft( BINKSHADERS * shaders );
|
|
|
|
//=============================================================================
|
|
|
|
// allocate the textures that we'll need - shaders defines the device we use to
|
|
// create them. The user_ptr gets stored in the BINKTEXTURES and also passed
|
|
// to any underlying "alloc" functions we call.
|
|
typedef BINKTEXTURES * Create_Bink_textures_ft( BINKSHADERS * shaders, HBINK bink, void *user_ptr );
|
|
|
|
//=============================================================================
|
|
|
|
// frees the textures
|
|
typedef void Free_Bink_textures_ft( BINKTEXTURES * textures );
|
|
|
|
//=============================================================================
|
|
// Bink texture updating
|
|
|
|
// Start updating textures for this frame. Call before DoFrame.
|
|
typedef void Start_Bink_texture_update_ft( BINKTEXTURES * textures );
|
|
|
|
// Finish updating textures for this frame. Call after DoFrame is done.
|
|
typedef void Finish_Bink_texture_update_ft( BINKTEXTURES * textures );
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// Bink texture drawing functions
|
|
|
|
// Draws the textures as a screen-aligned quad.
|
|
|
|
// If you pass a zero for "shaders", we'll use the shader used to create the
|
|
// textures (which is normally what you want).
|
|
// The value that you pass for "graphics_context" depends on the graphics API:
|
|
// D3D9 - Parameter not used, just pass 0
|
|
// D3D11 - The d3d11 device context (type ID3D11DeviceContext *)
|
|
// D3D12 - Pointer to a BINKAPICONTEXTD3D12 struct with all fields filled out
|
|
// GL - Parameter not used, just pass 0
|
|
// PS3 - The Gcm context (usually, gCellGcmCurrentContext, type CellGcmContextData *)
|
|
// PS4 - The Gfx context pointer to use (type sce::Gnmx::GfxContext *)
|
|
// Xbox360 - Parameter not used, just pass 0
|
|
// XboxOne - The Xbox device context (type ID3D11DeviceContextX *)
|
|
// NX - The NX context pointer to use (type nn::gfx::CommandBuffer *)
|
|
// Metal - Pointer to a BINKAPICONTEXTMETAL struct with all the fields filled out
|
|
// PS5 - Pointer to the DrawCommandBuffer to use (no StateBuffer or Binder required)
|
|
typedef void Draw_Bink_textures_ft( BINKTEXTURES * textures,
|
|
BINKSHADERS * shaders,
|
|
void * graphics_context );
|
|
|
|
// Set the position to draw the video within the viewport.
|
|
// If you video doesn't move, you can call this once,
|
|
// otherwise call before each call to Draw_Bink_texture.
|
|
// By default, the video fills the video port.
|
|
//
|
|
// 0,0, 1,1 is the default which completely fills the viewport
|
|
typedef void Set_Bink_draw_position_ft( BINKTEXTURES * textures,
|
|
F32 x0, F32 y0, F32 x1, F32 y1 );
|
|
|
|
|
|
// 0,0, 1,0, 0,1 is the default which completely fills the viewport
|
|
typedef void Set_Bink_draw_corners_ft( BINKTEXTURES * textures,
|
|
F32 Ax, F32 Ay, F32 Bx, F32 By, F32 Cx, F32 Cy );
|
|
|
|
|
|
// Set draw source rect (from 0 to 1, in texturespace, so 0,0, 1,1 is whole texture)
|
|
typedef void Set_Bink_source_rect_ft( BINKTEXTURES * textures,
|
|
F32 u0, F32 v0, F32 u1, F32 v1 );
|
|
|
|
// Or these flags with draw_type_and_flags
|
|
#define BINKDRAWFLAG_SRGB_DECODE (0x80000000)
|
|
|
|
// Set the alpha settings for drawing.
|
|
// alpha_value is just a constant blend value for entire video frame
|
|
// draw_type is 0 = normal alpha, 1 = pre-multiplied alpha, 2 = opaque & copy alpha
|
|
// draw_type also contains flags in the high bits:
|
|
// BINKDRAWFLAG_SRGB_DECODE - decode sRGB to linear when rendering the video.
|
|
typedef void Set_Bink_alpha_settings_ft( BINKTEXTURES * textures,
|
|
F32 alpha_value,
|
|
S32 draw_type_and_flags );
|
|
|
|
// Set the hdr settings for drawing.
|
|
// tonemap specifies whether you want linear output (0), or filmic tonemapped output (1), or ST2084 HDR output (2).
|
|
// exposure is a scaling factor that happens before tonemapping (1.0=normal, <1.0 darken, >1.0 brighten)
|
|
// out_luma specifies the maximum luminance to output when tonemapping
|
|
typedef void Set_Bink_hdr_settings_ft( BINKTEXTURES * texutres,
|
|
S32 tonemap,
|
|
F32 exposure,
|
|
S32 output_nits );
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// For D3D9 only, these functions are called before and after you reset the D3D9 device
|
|
typedef void Before_Reset_Bink_textures_ft( BINKTEXTURES * textures );
|
|
typedef S32 After_Reset_Bink_textures_ft( BINKTEXTURES * textures );
|
|
|
|
//=============================================================================
|
|
|
|
#ifndef BINKTEXTURESTRUCTS
|
|
#define BINKTEXTURESTRUCTS
|
|
|
|
#define Create_Bink_textures( shader, bink, user_ptr ) (shader)->Create_textures( shader, bink, user_ptr )
|
|
#define Free_Bink_shaders( shader ) (shader)->Free_shaders( shader )
|
|
|
|
#define Start_Bink_texture_update( textures ) (textures)->Start_texture_update( textures )
|
|
#define Finish_Bink_texture_update( textures ) (textures)->Finish_texture_update( textures )
|
|
#define Draw_Bink_textures( textures, shaders, gr_ctx ) (textures)->Draw_textures( textures, shaders, gr_ctx )
|
|
#define Set_Bink_draw_position( textures, x0,y0, x1,y1 ) (textures)->Set_draw_position( textures, x0,y0, x1,y1 )
|
|
#define Set_Bink_draw_corners( textures, Ax,Ay, Bx,By, Cx,Cy ) (textures)->Set_draw_corners( textures, Ax,Ay, Bx,By, Cx,Cy )
|
|
#define Set_Bink_source_rect( textures, u0,v0, u1,v1 ) (textures)->Set_source_rect( textures, u0,v0, u1,v1 )
|
|
#define Set_Bink_alpha_settings( textures, alpha, draw_type_and_flags ) (textures)->Set_alpha_settings( textures, alpha, draw_type_and_flags )
|
|
#define Set_Bink_hdr_settings( textures, tonemap, exposure, out_nits ) (textures)->Set_hdr_settings( textures, tonemap, exposure, out_nits )
|
|
#define Before_Reset_Bink_textures( textures ) {if ((textures)->Before_Reset_textures) (textures)->Before_Reset_textures( textures );}
|
|
#define After_Reset_Bink_textures( textures ) {if ((textures)->After_Reset_textures) (textures)->After_Reset_textures( textures );}
|
|
#define Free_Bink_textures( textures ) (textures)->Free_textures( textures )
|
|
|
|
struct BINKSHADERS2
|
|
{
|
|
Create_Bink_textures_ft * Create_textures;
|
|
Free_Bink_shaders_ft * Free_shaders;
|
|
|
|
// you can use this for whatever you want
|
|
UINTa user_data[ 4 ];
|
|
};
|
|
|
|
struct BINKTEXTURES2
|
|
{
|
|
// wrap around doframe
|
|
Start_Bink_texture_update_ft * Start_texture_update;
|
|
Finish_Bink_texture_update_ft * Finish_texture_update;
|
|
|
|
// draw related functions
|
|
Draw_Bink_textures_ft * Draw_textures;
|
|
Set_Bink_draw_position_ft * Set_draw_position;
|
|
Set_Bink_draw_corners_ft * Set_draw_corners;
|
|
Set_Bink_source_rect_ft * Set_source_rect;
|
|
Set_Bink_alpha_settings_ft * Set_alpha_settings;
|
|
Set_Bink_hdr_settings_ft * Set_hdr_settings;
|
|
|
|
// D3D9 only (everywhere else is null)
|
|
Before_Reset_Bink_textures_ft * Before_Reset_textures;
|
|
After_Reset_Bink_textures_ft * After_Reset_textures;
|
|
|
|
Free_Bink_textures_ft * Free_textures;
|
|
|
|
// user pointer specified at Create_Bink_textures time
|
|
void * user_ptr;
|
|
|
|
// these are the platform specific texture pointers that you can draw manually with
|
|
void * Ytexture;
|
|
void * cRtexture;
|
|
void * cBtexture;
|
|
void * Atexture;
|
|
void * Htexture;
|
|
|
|
// you can use this for whatever you want
|
|
UINTa user_data[ 4 ];
|
|
};
|
|
|
|
#endif
|
|
//=============================================================================
|
|
|
|
|
|
// optional clean up, for when including the header multiple times for different APIs
|
|
#if defined(BINKTEXTURESCLEANUP)
|
|
#undef Create_Bink_shaders
|
|
|
|
#ifdef BINKD3D9FUNCTIONS
|
|
#undef BINKD3D9FUNCTIONS
|
|
#endif
|
|
#ifdef BINKD3D11FUNCTIONS
|
|
#undef BINKD3D11FUNCTIONS
|
|
#endif
|
|
#ifdef BINKD3D11GPUFUNCTIONS
|
|
#undef BINKD3D11GPUFUNCTIONS
|
|
#endif
|
|
#ifdef BINKD3D12FUNCTIONS
|
|
#undef BINKD3D12FUNCTIONS
|
|
#endif
|
|
#ifdef BINKD3D12GPUFUNCTIONS
|
|
#undef BINKD3D12GPUFUNCTIONS
|
|
#endif
|
|
#ifdef BINKNDAFUNCTIONS
|
|
#undef BINKNDAFUNCTIONS
|
|
#endif
|
|
#ifdef BINKTEXTURESSUFFIX
|
|
#undef BINKTEXTURESSUFFIX
|
|
#endif
|
|
#undef BINKTEXTURESH
|
|
#undef BINKTEXTURESCLEANUP
|
|
#endif
|
|
|
|
RADDEFEND
|
|
|
|
#endif
|