diff options
Diffstat (limited to 'src/gallium')
485 files changed, 49610 insertions, 6165 deletions
diff --git a/src/gallium/SConscript b/src/gallium/SConscript index 428bc31f86b..3072ee936f2 100644 --- a/src/gallium/SConscript +++ b/src/gallium/SConscript @@ -53,7 +53,7 @@ if env['drm']: # Needed by some state trackers SConscript('winsys/sw/null/SConscript') -if env['platform'] != 'embedded': +if not env['embedded']: SConscript('state_trackers/vega/SConscript') SConscript('state_trackers/egl/SConscript') @@ -66,8 +66,8 @@ if env['platform'] != 'embedded': if env['dri'] and env['xorg']: SConscript('state_trackers/xorg/SConscript') -if env['platform'] == 'windows': - SConscript('state_trackers/wgl/SConscript') + if env['platform'] == 'windows': + SConscript('state_trackers/wgl/SConscript') # # Winsys @@ -83,55 +83,55 @@ SConscript([ 'targets/graw-null/SConscript', ]) -if env['platform'] != 'embedded': +if not env['embedded']: SConscript([ 'targets/egl-static/SConscript' ]) -if env['x11']: - SConscript([ - 'targets/graw-xlib/SConscript', - 'targets/libgl-xlib/SConscript', - ]) + if env['x11']: + SConscript([ + 'targets/graw-xlib/SConscript', + 'targets/libgl-xlib/SConscript', + ]) -if env['platform'] == 'windows': - SConscript([ - 'targets/graw-gdi/SConscript', - 'targets/libgl-gdi/SConscript', - ]) + if env['platform'] == 'windows': + SConscript([ + 'targets/graw-gdi/SConscript', + 'targets/libgl-gdi/SConscript', + ]) -if env['dri']: - SConscript([ - 'targets/SConscript.dri', - 'targets/dri-swrast/SConscript', - 'targets/dri-vmwgfx/SConscript', - #'targets/dri-nouveau/SConscript', - ]) - if env['drm_intel']: + if env['dri']: SConscript([ - 'targets/dri-i915/SConscript', - 'targets/dri-i965/SConscript', + 'targets/SConscript.dri', + 'targets/dri-swrast/SConscript', + 'targets/dri-vmwgfx/SConscript', + #'targets/dri-nouveau/SConscript', ]) - if env['drm_radeon']: + if env['drm_intel']: + SConscript([ + 'targets/dri-i915/SConscript', + 'targets/dri-i965/SConscript', + ]) + if env['drm_radeon']: + SConscript([ + 'targets/dri-r300/SConscript', + 'targets/dri-r600/SConscript', + ]) + + if env['xorg'] and env['drm']: SConscript([ - 'targets/dri-r300/SConscript', - 'targets/dri-r600/SConscript', + #'targets/xorg-i915/SConscript', + #'targets/xorg-i965/SConscript', + #'targets/xorg-nouveau/SConscript', + #'targets/xorg-radeon/SConscript', + 'targets/xorg-vmwgfx/SConscript', ]) -if env['xorg'] and env['drm']: - SConscript([ - #'targets/xorg-i915/SConscript', - #'targets/xorg-i965/SConscript', - #'targets/xorg-nouveau/SConscript', - #'targets/xorg-radeon/SConscript', - 'targets/xorg-vmwgfx/SConscript', - ]) - # # Unit tests & tools # -if env['platform'] != 'embedded': +if not env['embedded']: SConscript('tests/unit/SConscript') SConscript('tests/graw/SConscript') diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile index d10f9cd49cb..7dae7bc908b 100644 --- a/src/gallium/auxiliary/Makefile +++ b/src/gallium/auxiliary/Makefile @@ -147,14 +147,17 @@ C_SOURCES = \ util/u_transfer.c \ util/u_resource.c \ util/u_upload_mgr.c \ - util/u_vbuf_mgr.c - - # Disabling until pipe-video branch gets merged in - #vl/vl_bitstream_parser.c \ - #vl/vl_mpeg12_mc_renderer.c \ - #vl/vl_compositor.c \ - #vl/vl_csc.c \ - #vl/vl_shader_build.c \ + util/u_vbuf_mgr.c \ + vl/vl_csc.c \ + vl/vl_compositor.c \ + vl/vl_decoder.c \ + vl/vl_mpeg12_decoder.c \ + vl/vl_mpeg12_bitstream.c \ + vl/vl_zscan.c \ + vl/vl_idct.c \ + vl/vl_mc.c \ + vl/vl_vertex_buffers.c \ + vl/vl_video_buffer.c GALLIVM_SOURCES = \ gallivm/lp_bld_arit.c \ @@ -225,3 +228,4 @@ util/u_format_table.c: util/u_format_table.py util/u_format_pack.py util/u_forma util/u_half.c: util/u_half.py $(PYTHON2) util/u_half.py > $@ +# DO NOT DELETE diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript index 457911d2f1f..d18f55f1644 100644 --- a/src/gallium/auxiliary/SConscript +++ b/src/gallium/auxiliary/SConscript @@ -195,12 +195,16 @@ source = [ 'util/u_transfer.c', 'util/u_upload_mgr.c', 'util/u_vbuf_mgr.c', - # Disabling until pipe-video branch gets merged in - #'vl/vl_bitstream_parser.c', - #'vl/vl_mpeg12_mc_renderer.c', - #'vl/vl_compositor.c', - #'vl/vl_csc.c', - #'vl/vl_shader_build.c', + 'vl/vl_csc.c', + 'vl/vl_compositor.c', + 'vl/vl_decoder.c', + 'vl/vl_mpeg12_decoder.c', + 'vl/vl_mpeg12_bitstream.c', + 'vl/vl_zscan.c', + 'vl/vl_idct.c', + 'vl/vl_mc.c', + 'vl/vl_vertex_buffers.c', + 'vl/vl_video_buffer.c', ] if env['llvm']: diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c index 56c26f57cce..996e295e4b5 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.c +++ b/src/gallium/auxiliary/draw/draw_llvm.c @@ -96,7 +96,7 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *var); * Create LLVM type for struct draw_jit_texture */ static LLVMTypeRef -create_jit_texture_type(struct gallivm_state *gallivm) +create_jit_texture_type(struct gallivm_state *gallivm, const char *struct_name) { LLVMTargetDataRef target = gallivm->target; LLVMTypeRef texture_type; @@ -120,13 +120,21 @@ create_jit_texture_type(struct gallivm_state *gallivm) elem_types[DRAW_JIT_TEXTURE_BORDER_COLOR] = LLVMArrayType(LLVMFloatTypeInContext(gallivm->context), 4); +#if HAVE_LLVM >= 0x0300 + texture_type = LLVMStructCreateNamed(gallivm->context, struct_name); + LLVMStructSetBody(texture_type, elem_types, + Elements(elem_types), 0); +#else texture_type = LLVMStructTypeInContext(gallivm->context, elem_types, Elements(elem_types), 0); + LLVMAddTypeName(gallivm->module, struct_name, texture_type); + /* Make sure the target's struct layout cache doesn't return * stale/invalid data. */ LLVMInvalidateStructLayout(gallivm->target, texture_type); +#endif LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, width, target, texture_type, @@ -176,7 +184,7 @@ create_jit_texture_type(struct gallivm_state *gallivm) */ static LLVMTypeRef create_jit_context_type(struct gallivm_state *gallivm, - LLVMTypeRef texture_type) + LLVMTypeRef texture_type, const char *struct_name) { LLVMTargetDataRef target = gallivm->target; LLVMTypeRef float_type = LLVMFloatTypeInContext(gallivm->context); @@ -189,11 +197,17 @@ create_jit_context_type(struct gallivm_state *gallivm, elem_types[3] = LLVMPointerType(float_type, 0); /* viewport */ elem_types[4] = LLVMArrayType(texture_type, PIPE_MAX_VERTEX_SAMPLERS); /* textures */ - +#if HAVE_LLVM >= 0x0300 + context_type = LLVMStructCreateNamed(gallivm->context, struct_name); + LLVMStructSetBody(context_type, elem_types, + Elements(elem_types), 0); +#else context_type = LLVMStructTypeInContext(gallivm->context, elem_types, Elements(elem_types), 0); + LLVMAddTypeName(gallivm->module, struct_name, context_type); LLVMInvalidateStructLayout(gallivm->target, context_type); +#endif LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, vs_constants, target, context_type, 0); @@ -215,7 +229,7 @@ create_jit_context_type(struct gallivm_state *gallivm, * Create LLVM type for struct pipe_vertex_buffer */ static LLVMTypeRef -create_jit_vertex_buffer_type(struct gallivm_state *gallivm) +create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_name) { LLVMTargetDataRef target = gallivm->target; LLVMTypeRef elem_types[3]; @@ -225,10 +239,17 @@ create_jit_vertex_buffer_type(struct gallivm_state *gallivm) elem_types[1] = LLVMInt32TypeInContext(gallivm->context); elem_types[2] = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0); /* vs_constants */ +#if HAVE_LLVM >= 0x0300 + vb_type = LLVMStructCreateNamed(gallivm->context, struct_name); + LLVMStructSetBody(vb_type, elem_types, + Elements(elem_types), 0); +#else vb_type = LLVMStructTypeInContext(gallivm->context, elem_types, Elements(elem_types), 0); + LLVMAddTypeName(gallivm->module, struct_name, vb_type); LLVMInvalidateStructLayout(gallivm->target, vb_type); +#endif LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, stride, target, vb_type, 0); @@ -258,10 +279,17 @@ create_jit_vertex_header(struct gallivm_state *gallivm, int data_elems) elem_types[1] = LLVMArrayType(LLVMFloatTypeInContext(gallivm->context), 4); elem_types[2] = LLVMArrayType(elem_types[1], data_elems); +#if HAVE_LLVM >= 0x0300 + vertex_header = LLVMStructCreateNamed(gallivm->context, struct_name); + LLVMStructSetBody(vertex_header, elem_types, + Elements(elem_types), 0); +#else vertex_header = LLVMStructTypeInContext(gallivm->context, elem_types, Elements(elem_types), 0); + LLVMAddTypeName(gallivm->module, struct_name, vertex_header); LLVMInvalidateStructLayout(gallivm->target, vertex_header); +#endif /* these are bit-fields and we can't take address of them LP_CHECK_MEMBER_OFFSET(struct vertex_header, clipmask, @@ -284,8 +312,6 @@ create_jit_vertex_header(struct gallivm_state *gallivm, int data_elems) target, vertex_header, DRAW_JIT_VERTEX_DATA); - LLVMAddTypeName(gallivm->module, struct_name, vertex_header); - return vertex_header; } @@ -299,19 +325,15 @@ create_jit_types(struct draw_llvm *llvm) struct gallivm_state *gallivm = llvm->gallivm; LLVMTypeRef texture_type, context_type, buffer_type, vb_type; - texture_type = create_jit_texture_type(gallivm); - LLVMAddTypeName(gallivm->module, "texture", texture_type); + texture_type = create_jit_texture_type(gallivm, "texture"); - context_type = create_jit_context_type(gallivm, texture_type); - LLVMAddTypeName(gallivm->module, "draw_jit_context", context_type); + context_type = create_jit_context_type(gallivm, texture_type, "draw_jit_context"); llvm->context_ptr_type = LLVMPointerType(context_type, 0); buffer_type = LLVMPointerType(LLVMIntTypeInContext(gallivm->context, 8), 0); - LLVMAddTypeName(gallivm->module, "buffer", buffer_type); llvm->buffer_ptr_type = LLVMPointerType(buffer_type, 0); - vb_type = create_jit_vertex_buffer_type(gallivm); - LLVMAddTypeName(gallivm->module, "pipe_vertex_buffer", vb_type); + vb_type = create_jit_vertex_buffer_type(gallivm, "pipe_vertex_buffer"); llvm->vb_ptr_type = LLVMPointerType(vb_type, 0); } @@ -1163,6 +1185,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant) struct lp_build_loop_state lp_loop; const int max_vertices = 4; LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS]; + LLVMValueRef fetch_max; void *code; struct lp_build_sampler_soa *sampler = 0; LLVMValueRef ret, ret_ptr; @@ -1234,6 +1257,11 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant) draw_llvm_variant_key_samplers(&variant->key), context_ptr); + /* fetch_max = start + count - 1 */ + fetch_max = LLVMBuildSub(builder, end, + lp_build_const_int32(gallivm, 1), + "fetch_max"); + #if DEBUG_STORE lp_build_printf(builder, "start = %d, end = %d, step = %d\n", start, end, step); @@ -1257,6 +1285,12 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant) builder, lp_loop.counter, lp_build_const_int32(gallivm, i), ""); + + /* make sure we're not out of bounds which can happen + * if fetch_count % 4 != 0, because on the last iteration + * a few of the 4 vertex fetches will be out of bounds */ + true_index = lp_build_min(&bld, true_index, fetch_max); + for (j = 0; j < draw->pt.nr_vertex_elements; ++j) { struct pipe_vertex_element *velem = &draw->pt.vertex_element[j]; LLVMValueRef vb_index = lp_build_const_int32(gallivm, velem->vertex_buffer_index); diff --git a/src/gallium/auxiliary/draw/draw_pipe_aaline.c b/src/gallium/auxiliary/draw/draw_pipe_aaline.c index 32af29ae144..458f85def2c 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aaline.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aaline.c @@ -784,6 +784,14 @@ aaline_destroy(struct draw_stage *stage) draw_free_temp_verts( stage ); + /* restore the old entry points */ + pipe->create_fs_state = aaline->driver_create_fs_state; + pipe->bind_fs_state = aaline->driver_bind_fs_state; + pipe->delete_fs_state = aaline->driver_delete_fs_state; + + pipe->bind_fragment_sampler_states = aaline->driver_bind_sampler_states; + pipe->set_fragment_sampler_views = aaline->driver_set_sampler_views; + FREE( stage ); } diff --git a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c index 60f6380c503..9265c379de8 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c @@ -768,7 +768,16 @@ aapoint_reset_stipple_counter(struct draw_stage *stage) static void aapoint_destroy(struct draw_stage *stage) { + struct aapoint_stage* aapoint = aapoint_stage(stage); + struct pipe_context *pipe = stage->draw->pipe; + draw_free_temp_verts( stage ); + + /* restore the old entry points */ + pipe->create_fs_state = aapoint->driver_create_fs_state; + pipe->bind_fs_state = aapoint->driver_bind_fs_state; + pipe->delete_fs_state = aapoint->driver_delete_fs_state; + FREE( stage ); } diff --git a/src/gallium/auxiliary/gallivm/f.cpp b/src/gallium/auxiliary/gallivm/f.cpp index 5eb09c01ab3..6b9c35b3ce5 100644 --- a/src/gallium/auxiliary/gallivm/f.cpp +++ b/src/gallium/auxiliary/gallivm/f.cpp @@ -15,8 +15,9 @@ * * How to use this source: * - * - Download and abuild the NTL library from - * http://shoup.net/ntl/download.html + * - Download and build the NTL library from + * http://shoup.net/ntl/download.html , or install libntl-dev package if on + * Debian. * * - Download boost source code matching to your distro. * @@ -24,22 +25,32 @@ * * - Build as * - * g++ -o minimax -I /path/to/ntl/include main.cpp f.cpp /path/to/ntl/src/ntl.a -lboost_math_tr1 + * g++ -o minimax -I /path/to/ntl/include main.cpp f.cpp /path/to/ntl/src/ntl.a * * - Run as * * ./minimax * - * - For example, to compute exp2 5th order polynomial between [0, 1] do: + * - For example, to compute log2 5th order polynomial between [1, 2] do: + * + * variant 0 + * range 1 2 + * order 5 0 + * step 200 + * info + * + * and take the coefficients from the P = { ... } array. + * + * - To compute exp2 5th order polynomial between [0, 1] do: * * variant 1 * range 0 1 * order 5 0 - * steps 200 + * step 200 * info * * - For more info see - * http://www.boost.org/doc/libs/1_36_0/libs/math/doc/sf_and_dist/html/math_toolkit/toolkit/internals2/minimax.html + * http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/toolkit/internals2/minimax.html */ #define L22 diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.c b/src/gallium/auxiliary/gallivm/lp_bld_arit.c index 02b3bde7893..2be8598704e 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_arit.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.c @@ -61,7 +61,7 @@ #include "lp_bld_arit.h" -#define EXP_POLY_DEGREE 3 +#define EXP_POLY_DEGREE 5 #define LOG_POLY_DEGREE 5 @@ -1645,7 +1645,7 @@ lp_build_rsqrt(struct lp_build_context *bld, assert(type.floating); if (util_cpu_caps.has_sse && type.width == 32 && type.length == 4) { - const unsigned num_iterations = 0; + const unsigned num_iterations = 1; LLVMValueRef res; unsigned i; @@ -2151,7 +2151,7 @@ lp_build_exp(struct lp_build_context *bld, assert(lp_check_value(bld->type, x)); - return lp_build_mul(bld, log2e, lp_build_exp2(bld, x)); + return lp_build_exp2(bld, lp_build_mul(bld, log2e, x)); } @@ -2168,7 +2168,7 @@ lp_build_log(struct lp_build_context *bld, assert(lp_check_value(bld->type, x)); - return lp_build_mul(bld, log2, lp_build_exp2(bld, x)); + return lp_build_mul(bld, log2, lp_build_log2(bld, x)); } @@ -2218,18 +2218,18 @@ lp_build_polynomial(struct lp_build_context *bld, */ const double lp_build_exp2_polynomial[] = { #if EXP_POLY_DEGREE == 5 - 0.999999999690134838155, - 0.583974334321735217258, - 0.164553105719676828492, - 0.0292811063701710962255, - 0.00354944426657875141846, - 0.000296253726543423377365 + 0.999999925063526176901, + 0.693153073200168932794, + 0.240153617044375388211, + 0.0558263180532956664775, + 0.00898934009049466391101, + 0.00187757667519147912699 #elif EXP_POLY_DEGREE == 4 - 1.00000001502262084505, - 0.563586057338685991394, - 0.150436017652442413623, - 0.0243220604213317927308, - 0.0025359088446580436489 + 1.00000259337069434683, + 0.693003834469974940458, + 0.24144275689150793076, + 0.0520114606103070150235, + 0.0135341679161270268764 #elif EXP_POLY_DEGREE == 3 0.999925218562710312959, 0.695833540494823811697, @@ -2465,6 +2465,12 @@ lp_build_log2_approx(struct lp_build_context *bld, assert(type.floating && type.width == 32); + /* + * We don't explicitly handle denormalized numbers. They will yield a + * result in the neighbourhood of -127, which appears to be adequate + * enough. + */ + i = LLVMBuildBitCast(builder, x, int_vec_type, ""); /* exp = (float) exponent(x) */ diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp index 0b724a34948..e252607f97f 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp @@ -193,7 +193,11 @@ lp_disassemble(const void* func) InitializeAllDisassemblers(); +#if HAVE_LLVM >= 0x0300 + OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(Triple)); +#else OwningPtr<const MCAsmInfo> AsmInfo(T->createAsmInfo(Triple)); +#endif if (!AsmInfo) { debug_printf("error: no assembly info for target %s\n", Triple.c_str()); @@ -207,17 +211,13 @@ lp_disassemble(const void* func) } raw_debug_ostream Out; - TargetMachine *TM = T->createTargetMachine(Triple, ""); #if HAVE_LLVM >= 0x0300 unsigned int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); #else int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); #endif -#if HAVE_LLVM >= 0x0300 - OwningPtr<MCInstPrinter> Printer( - T->createMCInstPrinter(*TM, AsmPrinterVariant, *AsmInfo)); -#elif HAVE_LLVM >= 0x0208 +#if HAVE_LLVM >= 0x0208 OwningPtr<MCInstPrinter> Printer( T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo)); #else @@ -229,6 +229,12 @@ lp_disassemble(const void* func) return; } +#if HAVE_LLVM >= 0x0300 + TargetMachine *TM = T->createTargetMachine(Triple, sys::getHostCPUName(), ""); +#else + TargetMachine *TM = T->createTargetMachine(Triple, ""); +#endif + const TargetInstrInfo *TII = TM->getInstrInfo(); /* @@ -287,7 +293,11 @@ lp_disassemble(const void* func) pc += Size; +#if HAVE_LLVM >= 0x0300 + const MCInstrDesc &TID = TII->get(Inst.getOpcode()); +#else const TargetInstrDesc &TID = TII->get(Inst.getOpcode()); +#endif /* * Keep track of forward jumps to a nearby address. diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp index d2d7eccd92f..85fabc574b2 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp @@ -83,8 +83,12 @@ lp_set_target_options(void) * to only assume a 4 bytes alignment for backwards compatibility. */ #if defined(PIPE_ARCH_X86) +#if HAVE_LLVM >= 0x0300 + llvm::StackAlignmentOverride = 4; +#else llvm::StackAlignment = 4; #endif +#endif #if defined(DEBUG) || defined(PROFILE) llvm::NoFramePointerElim = true; diff --git a/src/gallium/auxiliary/gallivm/lp_bld_type.c b/src/gallium/auxiliary/gallivm/lp_bld_type.c index c5cf6d4a6c4..efd159f8869 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_type.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_type.c @@ -325,16 +325,18 @@ lp_typekind_name(LLVMTypeKind t) return "LLVMArrayTypeKind"; case LLVMPointerTypeKind: return "LLVMPointerTypeKind"; +#if HAVE_LLVM < 0x0300 case LLVMOpaqueTypeKind: return "LLVMOpaqueTypeKind"; +#endif case LLVMVectorTypeKind: return "LLVMVectorTypeKind"; case LLVMMetadataTypeKind: return "LLVMMetadataTypeKind"; - /* Only in LLVM 2.7 and later??? +#if HAVE_LLVM == 0x0207 case LLVMUnionTypeKind: return "LLVMUnionTypeKind"; - */ +#endif default: return "unknown LLVMTypeKind"; } diff --git a/src/gallium/auxiliary/indices/u_unfilled_gen.py b/src/gallium/auxiliary/indices/u_unfilled_gen.py index 36896ce605d..085c47a114a 100644 --- a/src/gallium/auxiliary/indices/u_unfilled_gen.py +++ b/src/gallium/auxiliary/indices/u_unfilled_gen.py @@ -167,8 +167,8 @@ def trifan(intype, outtype): def polygon(intype, outtype): preamble(intype, outtype, prim='polygon') - print ' for (j = i = 0; j < nr; j+=6, i++) { ' - do_tri( intype, outtype, 'out+j', '0', 'i+1', 'i+2' ); + print ' for (j = i = 0; j < nr; j+=2, i++) { ' + line( intype, outtype, 'out+j', 'i', '(i+1)%(nr/2)' ) print ' }' postamble() diff --git a/src/gallium/auxiliary/indices/u_unfilled_indices.c b/src/gallium/auxiliary/indices/u_unfilled_indices.c index 26c5d4d4c72..c353717d656 100644 --- a/src/gallium/auxiliary/indices/u_unfilled_indices.c +++ b/src/gallium/auxiliary/indices/u_unfilled_indices.c @@ -71,6 +71,11 @@ static void generate_linear_uint( unsigned nr, } +/** + * Given a primitive type and number of vertices, return the number of vertices + * needed to draw the primitive with fill mode = PIPE_POLYGON_MODE_LINE using + * separate lines (PIPE_PRIM_LINES). + */ static unsigned nr_lines( unsigned prim, unsigned nr ) { @@ -86,7 +91,7 @@ static unsigned nr_lines( unsigned prim, case PIPE_PRIM_QUAD_STRIP: return (nr - 2) / 2 * 8; case PIPE_PRIM_POLYGON: - return (nr - 2) * 6; + return 2 * nr; /* a line (two verts) for each polygon edge */ default: assert(0); return 0; diff --git a/src/gallium/auxiliary/os/os_memory.h b/src/gallium/auxiliary/os/os_memory.h index 556662d35e1..91a84a24bc8 100644 --- a/src/gallium/auxiliary/os/os_memory.h +++ b/src/gallium/auxiliary/os/os_memory.h @@ -39,7 +39,7 @@ #include "pipe/p_compiler.h" -#if defined(PIPE_OS_EMBEDDED) +#if defined(PIPE_SUBSYSTEM_EMBEDDED) #ifdef __cplusplus extern "C" { diff --git a/src/gallium/auxiliary/os/os_misc.h b/src/gallium/auxiliary/os/os_misc.h index d59f9819fec..48522dac4d7 100644 --- a/src/gallium/auxiliary/os/os_misc.h +++ b/src/gallium/auxiliary/os/os_misc.h @@ -58,8 +58,6 @@ extern "C" { # define os_break() __debugbreak() #elif defined(PIPE_OS_UNIX) # define os_break() kill(getpid(), SIGTRAP) -#elif defined(PIPE_OS_EMBEDDED) -void os_break(void); #else # define os_break() abort() #endif @@ -70,8 +68,6 @@ void os_break(void); */ #if defined(DEBUG) || defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT) # define os_abort() os_break() -#elif defined(PIPE_OS_EMBEDDED) -void os_abort(void); #else # define os_abort() abort() #endif diff --git a/src/gallium/auxiliary/os/os_thread.h b/src/gallium/auxiliary/os/os_thread.h index 6b4281ad661..8f1245bff55 100644 --- a/src/gallium/auxiliary/os/os_thread.h +++ b/src/gallium/auxiliary/os/os_thread.h @@ -40,7 +40,7 @@ #include "util/u_debug.h" /* for assert */ -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_EMBEDDED) || defined(PIPE_OS_CYGWIN) +#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN) #include <pthread.h> /* POSIX threads headers */ #include <stdio.h> /* for perror() */ @@ -314,7 +314,7 @@ typedef int64_t pipe_condvar; * pipe_barrier */ -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_EMBEDDED) +#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_HAIKU) typedef pthread_barrier_t pipe_barrier; @@ -442,7 +442,7 @@ pipe_semaphore_wait(pipe_semaphore *sema) */ typedef struct { -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_EMBEDDED) || defined(PIPE_OS_CYGWIN) +#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN) pthread_key_t key; #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER) DWORD key; @@ -457,7 +457,7 @@ typedef struct { static INLINE void pipe_tsd_init(pipe_tsd *tsd) { -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_EMBEDDED) || defined(PIPE_OS_CYGWIN) +#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN) if (pthread_key_create(&tsd->key, NULL/*free*/) != 0) { perror("pthread_key_create(): failed to allocate key for thread specific data"); exit(-1); @@ -474,7 +474,7 @@ pipe_tsd_get(pipe_tsd *tsd) if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) { pipe_tsd_init(tsd); } -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_EMBEDDED) || defined(PIPE_OS_CYGWIN) +#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN) return pthread_getspecific(tsd->key); #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER) assert(0); @@ -491,7 +491,7 @@ pipe_tsd_set(pipe_tsd *tsd, void *value) if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) { pipe_tsd_init(tsd); } -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_EMBEDDED) || defined(PIPE_OS_CYGWIN) +#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN) if (pthread_setspecific(tsd->key, value) != 0) { perror("pthread_set_specific() failed"); exit(-1); diff --git a/src/gallium/auxiliary/os/os_time.c b/src/gallium/auxiliary/os/os_time.c index 325f316784c..73d86296d91 100644 --- a/src/gallium/auxiliary/os/os_time.c +++ b/src/gallium/auxiliary/os/os_time.c @@ -35,8 +35,6 @@ #include "pipe/p_config.h" -#if !defined(PIPE_OS_EMBEDDED) - #if defined(PIPE_OS_UNIX) # include <sys/time.h> /* timeval */ #elif defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) @@ -123,6 +121,3 @@ os_time_sleep(int64_t usecs) } #endif - - -#endif /* !PIPE_OS_EMBEDDED */ diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c index 072772eaa7e..587483c049b 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_exec.c +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c @@ -1839,6 +1839,17 @@ exec_tex(struct tgsi_exec_machine *mach, assert(0); } +#if 0 + debug_printf("fetch r: %g %g %g %g\n", + r[0].f[0], r[0].f[1], r[0].f[2], r[0].f[3]); + debug_printf("fetch g: %g %g %g %g\n", + r[1].f[0], r[1].f[1], r[1].f[2], r[1].f[3]); + debug_printf("fetch b: %g %g %g %g\n", + r[2].f[0], r[2].f[1], r[2].f[2], r[2].f[3]); + debug_printf("fetch a: %g %g %g %g\n", + r[3].f[0], r[3].f[1], r[3].f[2], r[3].f[3]); +#endif + for (chan = 0; chan < NUM_CHANNELS; chan++) { if (inst->Dst[0].Register.WriteMask & (1 << chan)) { store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); diff --git a/src/gallium/auxiliary/tgsi/tgsi_scan.c b/src/gallium/auxiliary/tgsi/tgsi_scan.c index 83c6ac75e54..f165f8240e6 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_scan.c +++ b/src/gallium/auxiliary/tgsi/tgsi_scan.c @@ -200,19 +200,20 @@ tgsi_scan_shader(const struct tgsi_token *tokens, info->file_max[file] = MAX2(info->file_max[file], (int)reg); } break; + case TGSI_TOKEN_TYPE_PROPERTY: - { - const struct tgsi_full_property *fullprop - = &parse.FullToken.FullProperty; + { + const struct tgsi_full_property *fullprop + = &parse.FullToken.FullProperty; - info->properties[info->num_properties].name = - fullprop->Property.PropertyName; - memcpy(info->properties[info->num_properties].data, - fullprop->u, 8 * sizeof(unsigned));; + info->properties[info->num_properties].name = + fullprop->Property.PropertyName; + memcpy(info->properties[info->num_properties].data, + fullprop->u, 8 * sizeof(unsigned));; - ++info->num_properties; - } - break; + ++info->num_properties; + } + break; default: assert( 0 ); @@ -222,6 +223,23 @@ tgsi_scan_shader(const struct tgsi_token *tokens, info->uses_kill = (info->opcode_count[TGSI_OPCODE_KIL] || info->opcode_count[TGSI_OPCODE_KILP]); + /* extract simple properties */ + for (i = 0; i < info->num_properties; ++i) { + switch (info->properties[i].name) { + case TGSI_PROPERTY_FS_COORD_ORIGIN: + info->origin_lower_left = info->properties[i].data[0]; + break; + case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: + info->pixel_center_integer = info->properties[i].data[0]; + break; + case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: + info->color0_writes_all_cbufs = info->properties[i].data[0]; + break; + default: + ; + } + } + tgsi_parse_free (&parse); } diff --git a/src/gallium/auxiliary/tgsi/tgsi_scan.h b/src/gallium/auxiliary/tgsi/tgsi_scan.h index 53ab3d509dd..d6e593b3968 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_scan.h +++ b/src/gallium/auxiliary/tgsi/tgsi_scan.h @@ -68,6 +68,9 @@ struct tgsi_shader_info boolean writes_edgeflag; /**< vertex shader outputs edgeflag */ boolean uses_kill; /**< KIL or KILP instruction used? */ boolean uses_instanceid; + boolean origin_lower_left; + boolean pixel_center_integer; + boolean color0_writes_all_cbufs; /** * Bitmask indicating which register files are accessed with diff --git a/src/gallium/auxiliary/util/u_debug.c b/src/gallium/auxiliary/util/u_debug.c index 36ce4b57713..2d6193039a7 100644 --- a/src/gallium/auxiliary/util/u_debug.c +++ b/src/gallium/auxiliary/util/u_debug.c @@ -48,7 +48,7 @@ void _debug_vprintf(const char *format, va_list ap) { -#if defined(PIPE_OS_WINDOWS) || defined(PIPE_OS_EMBEDDED) +#if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED) /* We buffer until we find a newline. */ static char buf[4096] = {'\0'}; size_t len = strlen(buf); @@ -730,7 +730,7 @@ debug_dump_float_rgba_bmp(const char *filename, pixel.rgbRed = float_to_ubyte(ptr[x*4 + 0]); pixel.rgbGreen = float_to_ubyte(ptr[x*4 + 1]); pixel.rgbBlue = float_to_ubyte(ptr[x*4 + 2]); - pixel.rgbAlpha = 255; + pixel.rgbAlpha = float_to_ubyte(ptr[x*4 + 3]); os_stream_write(stream, &pixel, 4); } } diff --git a/src/gallium/auxiliary/util/u_format.c b/src/gallium/auxiliary/util/u_format.c index 9cbdd0a5b99..34922ab18ab 100644 --- a/src/gallium/auxiliary/util/u_format.c +++ b/src/gallium/auxiliary/util/u_format.c @@ -390,3 +390,53 @@ util_format_translate(enum pipe_format dst_format, FREE(tmp_row); } } + +void util_format_compose_swizzles(const unsigned char swz1[4], + const unsigned char swz2[4], + unsigned char dst[4]) +{ + unsigned i; + + for (i = 0; i < 4; i++) { + dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ? + swz1[swz2[i]] : swz2[i]; + } +} + +void util_format_swizzle_4f(float *dst, const float *src, + const unsigned char swz[4]) +{ + unsigned i; + + for (i = 0; i < 4; i++) { + if (swz[i] <= UTIL_FORMAT_SWIZZLE_W) + dst[i] = src[swz[i]]; + else if (swz[i] == UTIL_FORMAT_SWIZZLE_0) + dst[i] = 0; + else if (swz[i] == UTIL_FORMAT_SWIZZLE_1) + dst[i] = 1; + } +} + +void util_format_unswizzle_4f(float *dst, const float *src, + const unsigned char swz[4]) +{ + unsigned i; + + for (i = 0; i < 4; i++) { + switch (swz[i]) { + case UTIL_FORMAT_SWIZZLE_X: + dst[0] = src[i]; + break; + case UTIL_FORMAT_SWIZZLE_Y: + dst[1] = src[i]; + break; + case UTIL_FORMAT_SWIZZLE_Z: + dst[2] = src[i]; + break; + case UTIL_FORMAT_SWIZZLE_W: + dst[3] = src[i]; + break; + } + } +} diff --git a/src/gallium/auxiliary/util/u_format.csv b/src/gallium/auxiliary/util/u_format.csv index a8baad111f1..a3d2aae62c8 100644 --- a/src/gallium/auxiliary/util/u_format.csv +++ b/src/gallium/auxiliary/util/u_format.csv @@ -259,3 +259,11 @@ PIPE_FORMAT_R32G32B32A32_FIXED , plain, 1, 1, h32 , h32 , h32 , h32 , xyzw, r PIPE_FORMAT_R10G10B10X2_USCALED , plain, 1, 1, u10 , u10 , u10 , x2 , xyz1, rgb # A.k.a. D3DDECLTYPE_DEC3N PIPE_FORMAT_R10G10B10X2_SNORM , plain, 1, 1, sn10, sn10, sn10 , x2 , xyz1, rgb + +PIPE_FORMAT_YV12 , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv +PIPE_FORMAT_YV16 , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv +PIPE_FORMAT_IYUV , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv +PIPE_FORMAT_NV12 , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv +PIPE_FORMAT_NV21 , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv +PIPE_FORMAT_IA44 , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv +PIPE_FORMAT_AI44 , other, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv diff --git a/src/gallium/auxiliary/util/u_format.h b/src/gallium/auxiliary/util/u_format.h index bb3ed72e932..566fa79e781 100644 --- a/src/gallium/auxiliary/util/u_format.h +++ b/src/gallium/auxiliary/util/u_format.h @@ -815,6 +815,25 @@ util_format_translate(enum pipe_format dst_format, unsigned src_x, unsigned src_y, unsigned width, unsigned height); +/* + * Swizzle operations. + */ + +/* Compose two sets of swizzles. + * If V is a 4D vector and the function parameters represent functions that + * swizzle vector components, this holds: + * swz2(swz1(V)) = dst(V) + */ +void util_format_compose_swizzles(const unsigned char swz1[4], + const unsigned char swz2[4], + unsigned char dst[4]); + +void util_format_swizzle_4f(float *dst, const float *src, + const unsigned char swz[4]); + +void util_format_unswizzle_4f(float *dst, const float *src, + const unsigned char swz[4]); + #ifdef __cplusplus } // extern "C" { #endif diff --git a/src/gallium/auxiliary/util/u_format_s3tc.c b/src/gallium/auxiliary/util/u_format_s3tc.c index bb989c29d81..d8a7c0d453f 100644 --- a/src/gallium/auxiliary/util/u_format_s3tc.c +++ b/src/gallium/auxiliary/util/u_format_s3tc.c @@ -119,8 +119,15 @@ util_format_s3tc_init(void) library = util_dl_open(DXTN_LIBNAME); if (!library) { - debug_printf("couldn't open " DXTN_LIBNAME ", software DXTn " - "compression/decompression unavailable\n"); + if (getenv("force_s3tc_enable") && + !strcmp(getenv("force_s3tc_enable"), "true")) { + debug_printf("couldn't open " DXTN_LIBNAME ", enabling DXTn due to " + "force_s3tc_enable=true environment variable\n"); + util_format_s3tc_enabled = TRUE; + } else { + debug_printf("couldn't open " DXTN_LIBNAME ", software DXTn " + "compression/decompression unavailable\n"); + } return; } diff --git a/src/gallium/auxiliary/util/u_format_yuv.c b/src/gallium/auxiliary/util/u_format_yuv.c index ab8bf29c97b..64ea0b35347 100644 --- a/src/gallium/auxiliary/util/u_format_yuv.c +++ b/src/gallium/auxiliary/util/u_format_yuv.c @@ -1045,3 +1045,138 @@ util_format_yuyv_fetch_rgba_float(float *dst, const uint8_t *src, dst[3] = 1.0f; } + +/* XXX: Stubbed for now */ +void +util_format_yv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv12_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv12_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} +void +util_format_yv16_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv16_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv16_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv16_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_yv16_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} +void +util_format_iyuv_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_iyuv_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_iyuv_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_iyuv_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_iyuv_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} +void +util_format_nv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv12_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv12_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} +void +util_format_nv21_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv21_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv21_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv21_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_nv21_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} +void +util_format_ia44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ia44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ia44_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ia44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ia44_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} +void +util_format_ai44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ai44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ai44_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ai44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height) {} +void +util_format_ai44_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j) {} diff --git a/src/gallium/auxiliary/util/u_format_yuv.h b/src/gallium/auxiliary/util/u_format_yuv.h index dc9632346d1..9f2365a5266 100644 --- a/src/gallium/auxiliary/util/u_format_yuv.h +++ b/src/gallium/auxiliary/util/u_format_yuv.h @@ -169,6 +169,141 @@ void util_format_yuyv_fetch_rgba_float(float *dst, const uint8_t *src, unsigned i, unsigned j); +/* XXX: Stubbed for now */ +void +util_format_yv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv12_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv12_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); +void +util_format_yv16_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv16_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv16_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv16_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_yv16_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); +void +util_format_iyuv_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_iyuv_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_iyuv_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_iyuv_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_iyuv_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); +void +util_format_nv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv12_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv12_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); +void +util_format_nv21_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv21_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv21_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv21_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_nv21_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); +void +util_format_ia44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ia44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ia44_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ia44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ia44_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); +void +util_format_ai44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ai44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ai44_unpack_rgba_float(float *dst_row, unsigned dst_stride, + const uint8_t *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ai44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride, + const float *src_row, unsigned src_stride, + unsigned width, unsigned height); +void +util_format_ai44_fetch_rgba_float(float *dst, const uint8_t *src, + unsigned i, unsigned j); + void util_format_r8g8_b8g8_unorm_unpack_rgba_float(float *dst_row, unsigned dst_stride, diff --git a/src/gallium/auxiliary/util/u_pack_color.h b/src/gallium/auxiliary/util/u_pack_color.h index 5378f2d782f..9391f1b80e0 100644 --- a/src/gallium/auxiliary/util/u_pack_color.h +++ b/src/gallium/auxiliary/util/u_pack_color.h @@ -458,6 +458,19 @@ util_pack_mask_z(enum pipe_format format, uint32_t z) } } + +static INLINE uint64_t +util_pack64_mask_z(enum pipe_format format, uint32_t z) +{ + switch (format) { + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + return z; + default: + return util_pack_mask_z(format, z); + } +} + + static INLINE uint32_t util_pack_mask_z_stencil(enum pipe_format format, uint32_t z, uint8_t s) { @@ -481,6 +494,21 @@ util_pack_mask_z_stencil(enum pipe_format format, uint32_t z, uint8_t s) } +static INLINE uint64_t +util_pack64_mask_z_stencil(enum pipe_format format, uint32_t z, uint8_t s) +{ + uint64_t packed; + + switch (format) { + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + packed = util_pack64_mask_z(format, z); + packed |= (uint64_t)s << 32ull; + return packed; + default: + return util_pack_mask_z_stencil(format, z, s); + } +} + /** * Note: it's assumed that z is in [0,1] @@ -525,6 +553,24 @@ util_pack_z(enum pipe_format format, double z) return 0; } } + + +static INLINE uint64_t +util_pack64_z(enum pipe_format format, double z) +{ + union fi fui; + + if (z == 0) + return 0; + + switch (format) { + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + fui.f = (float)z; + return fui.ui; + default: + return util_pack_z(format, z); + } +} /** @@ -554,6 +600,24 @@ util_pack_z_stencil(enum pipe_format format, double z, uint8_t s) } +static INLINE uint64_t +util_pack64_z_stencil(enum pipe_format format, double z, uint8_t s) +{ + uint64_t packed; + + switch (format) { + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + packed = util_pack64_z(format, z); + packed |= (uint64_t)s << 32ull; + break; + default: + return util_pack_z_stencil(format, z, s); + } + + return packed; +} + + /** * Pack 4 ubytes into a 4-byte word */ diff --git a/src/gallium/auxiliary/util/u_pstipple.c b/src/gallium/auxiliary/util/u_pstipple.c index f79a6938d1d..ac0df8c1a9c 100644 --- a/src/gallium/auxiliary/util/u_pstipple.c +++ b/src/gallium/auxiliary/util/u_pstipple.c @@ -52,6 +52,7 @@ #include "tgsi/tgsi_transform.h" #include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_scan.h" /** Approx number of new tokens for instructions in pstip_transform_inst() */ #define NUM_NEW_TOKENS 50 @@ -175,6 +176,7 @@ util_pstipple_create_sampler(struct pipe_context *pipe) */ struct pstip_transform_context { struct tgsi_transform_context base; + struct tgsi_shader_info info; uint tempsUsed; /**< bitmask */ int wincoordInput; int maxInput; @@ -183,12 +185,13 @@ struct pstip_transform_context { int texTemp; /**< temp registers */ int numImmed; boolean firstInstruction; + uint coordOrigin; }; /** * TGSI declaration transform callback. - * Look for a free sampler, a free input attrib, and two free temp regs. + * Track samplers used, temps used, inputs used. */ static void pstip_transform_decl(struct tgsi_transform_context *ctx, @@ -197,10 +200,11 @@ pstip_transform_decl(struct tgsi_transform_context *ctx, struct pstip_transform_context *pctx = (struct pstip_transform_context *) ctx; + /* XXX we can use tgsi_shader_info instead of some of this */ + if (decl->Declaration.File == TGSI_FILE_SAMPLER) { uint i; - for (i = decl->Range.First; - i <= decl->Range.Last; i++) { + for (i = decl->Range.First; i <= decl->Range.Last; i++) { pctx->samplersUsed |= 1 << i; } } @@ -211,8 +215,7 @@ pstip_transform_decl(struct tgsi_transform_context *ctx, } else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { uint i; - for (i = decl->Range.First; - i <= decl->Range.Last; i++) { + for (i = decl->Range.First; i <= decl->Range.Last; i++) { pctx->tempsUsed |= (1 << i); } } @@ -243,8 +246,16 @@ free_bit(uint bitfield) /** * TGSI instruction transform callback. - * Replace writes to result.color w/ a temp reg. - * Upon END instruction, insert texture sampling code for antialiasing. + * Before the first instruction, insert our new code to sample the + * stipple texture (using the fragment coord register) then kill the + * fragment if the stipple texture bit is off. + * + * Insert: + * declare new registers + * MUL texTemp, INPUT[wincoord], 1/32; + * TEX texTemp, texTemp, sampler; + * KIL -texTemp; # if -texTemp < 0, KILL fragment + * [...original code...] */ static void pstip_transform_inst(struct tgsi_transform_context *ctx, @@ -261,7 +272,7 @@ pstip_transform_inst(struct tgsi_transform_context *ctx, uint i; int wincoordInput; - /* find free sampler */ + /* find free texture sampler */ pctx->freeSampler = free_bit(pctx->samplersUsed); if (pctx->freeSampler >= PIPE_MAX_SAMPLERS) pctx->freeSampler = PIPE_MAX_SAMPLERS - 1; @@ -271,7 +282,7 @@ pstip_transform_inst(struct tgsi_transform_context *ctx, else wincoordInput = pctx->wincoordInput; - /* find one free temp reg */ + /* find one free temp register */ for (i = 0; i < 32; i++) { if ((pctx->tempsUsed & (1 << i)) == 0) { /* found a free temp */ @@ -397,6 +408,7 @@ util_pstipple_create_fragment_shader(struct pipe_context *pipe, struct pipe_shader_state *new_fs; struct pstip_transform_context transform; const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS; + unsigned i; new_fs = MALLOC(sizeof(*new_fs)); if (!new_fs) @@ -408,22 +420,33 @@ util_pstipple_create_fragment_shader(struct pipe_context *pipe, return NULL; } + /* Setup shader transformation info/context. + */ memset(&transform, 0, sizeof(transform)); transform.wincoordInput = -1; transform.maxInput = -1; transform.texTemp = -1; transform.firstInstruction = TRUE; + transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT; transform.base.transform_instruction = pstip_transform_inst; transform.base.transform_declaration = pstip_transform_decl; transform.base.transform_immediate = pstip_transform_immed; + tgsi_scan_shader(fs->tokens, &transform.info); + + /* find fragment coordinate origin property */ + for (i = 0; i < transform.info.num_properties; i++) { + if (transform.info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN) + transform.coordOrigin = transform.info.properties[i].data[0]; + } + tgsi_transform_shader(fs->tokens, (struct tgsi_token *) new_fs->tokens, newLen, &transform.base); #if 0 /* DEBUG */ tgsi_dump(fs->tokens, 0); - tgsi_dump(pstip_fs.tokens, 0); + tgsi_dump(new_fs->tokens, 0); #endif assert(transform.freeSampler < PIPE_MAX_SAMPLERS); diff --git a/src/gallium/auxiliary/util/u_surface.c b/src/gallium/auxiliary/util/u_surface.c index 4c5cc4da182..8e123867da6 100644 --- a/src/gallium/auxiliary/util/u_surface.c +++ b/src/gallium/auxiliary/util/u_surface.c @@ -358,8 +358,41 @@ util_clear_depth_stencil(struct pipe_context *pipe, dst_map += dst_stride; } } - break; + break; case 8: + { + uint64_t zstencil = util_pack64_z_stencil(dst->texture->format, + depth, stencil); + + assert(dst->format == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED); + + if (!need_rmw) { + for (i = 0; i < height; i++) { + uint64_t *row = (uint64_t *)dst_map; + for (j = 0; j < width; j++) + *row++ = zstencil; + dst_map += dst_stride; + } + } + else { + uint64_t src_mask; + + if (clear_flags & PIPE_CLEAR_DEPTH) + src_mask = 0x00000000ffffffffull; + else + src_mask = 0x000000ff00000000ull; + + for (i = 0; i < height; i++) { + uint64_t *row = (uint64_t *)dst_map; + for (j = 0; j < width; j++) { + uint64_t tmp = *row & ~src_mask; + *row++ = tmp | (zstencil & src_mask); + } + dst_map += dst_stride; + } + } + break; + } default: assert(0); break; diff --git a/src/gallium/auxiliary/util/u_tile.c b/src/gallium/auxiliary/util/u_tile.c index e3c7085ba92..23f12e5f464 100644 --- a/src/gallium/auxiliary/util/u_tile.c +++ b/src/gallium/auxiliary/util/u_tile.c @@ -318,6 +318,32 @@ z32f_get_tile_rgba(const float *src, } } +/*** PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED ***/ + +/** + * Return each Z value as four floats in [0,1]. + */ +static void +z32f_x24s8_get_tile_rgba(const float *src, + unsigned w, unsigned h, + float *p, + unsigned dst_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + float *pRow = p; + for (j = 0; j < w; j++, pRow += 4) { + pRow[0] = + pRow[1] = + pRow[2] = + pRow[3] = *src; + src += 2; + } + p += dst_stride; + } +} + void pipe_tile_raw_to_rgba(enum pipe_format format, @@ -352,6 +378,9 @@ pipe_tile_raw_to_rgba(enum pipe_format format, case PIPE_FORMAT_Z32_FLOAT: z32f_get_tile_rgba((float *) src, w, h, dst, dst_stride); break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + z32f_x24s8_get_tile_rgba((float *) src, w, h, dst, dst_stride); + break; default: util_format_read_4f(format, dst, dst_stride * sizeof(float), @@ -445,6 +474,12 @@ pipe_put_tile_rgba_format(struct pipe_context *pipe, case PIPE_FORMAT_X8Z24_UNORM: /*z24s8_put_tile_rgba((unsigned *) packed, w, h, p, src_stride);*/ break; + case PIPE_FORMAT_Z32_FLOAT: + /*z32f_put_tile_rgba((unsigned *) packed, w, h, p, src_stride);*/ + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + /*z32f_s8x24_put_tile_rgba((unsigned *) packed, w, h, p, src_stride);*/ + break; default: util_format_write_4f(format, p, src_stride * sizeof(float), diff --git a/src/gallium/auxiliary/util/u_upload_mgr.c b/src/gallium/auxiliary/util/u_upload_mgr.c index 9562acb8210..71fe53e3a27 100644 --- a/src/gallium/auxiliary/util/u_upload_mgr.c +++ b/src/gallium/auxiliary/util/u_upload_mgr.c @@ -72,6 +72,22 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, return upload; } +void u_upload_unmap( struct u_upload_mgr *upload ) +{ + if (upload->transfer) { + struct pipe_box *box = &upload->transfer->box; + if (upload->offset > box->x) { + + pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer, + box->x, upload->offset - box->x); + } + pipe_transfer_unmap(upload->pipe, upload->transfer); + pipe_transfer_destroy(upload->pipe, upload->transfer); + upload->transfer = NULL; + upload->map = NULL; + } +} + /* Release old buffer. * * This must usually be called prior to firing the command stream @@ -84,15 +100,7 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, void u_upload_flush( struct u_upload_mgr *upload ) { /* Unmap and unreference the upload buffer. */ - if (upload->transfer) { - if (upload->offset) { - pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer, - 0, upload->offset); - } - pipe_transfer_unmap(upload->pipe, upload->transfer); - pipe_transfer_destroy(upload->pipe, upload->transfer); - upload->transfer = NULL; - } + u_upload_unmap(upload); pipe_resource_reference( &upload->buffer, NULL ); upload->size = 0; } @@ -172,6 +180,15 @@ enum pipe_error u_upload_alloc( struct u_upload_mgr *upload, offset = MAX2(upload->offset, alloc_offset); + if (!upload->map) { + upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer, + offset, upload->size - offset, + PIPE_TRANSFER_WRITE | + PIPE_TRANSFER_FLUSH_EXPLICIT | + PIPE_TRANSFER_UNSYNCHRONIZED, + &upload->transfer); + } + assert(offset < upload->buffer->width0); assert(offset + size <= upload->buffer->width0); assert(size); @@ -223,10 +240,11 @@ enum pipe_error u_upload_buffer( struct u_upload_mgr *upload, struct pipe_transfer *transfer = NULL; const char *map = NULL; - map = (const char *)pipe_buffer_map(upload->pipe, - inbuf, - PIPE_TRANSFER_READ, - &transfer); + map = (const char *)pipe_buffer_map_range(upload->pipe, + inbuf, + offset, size, + PIPE_TRANSFER_READ, + &transfer); if (map == NULL) { ret = PIPE_ERROR_OUT_OF_MEMORY; diff --git a/src/gallium/auxiliary/util/u_upload_mgr.h b/src/gallium/auxiliary/util/u_upload_mgr.h index c9a2ffeb572..98915139801 100644 --- a/src/gallium/auxiliary/util/u_upload_mgr.h +++ b/src/gallium/auxiliary/util/u_upload_mgr.h @@ -56,15 +56,27 @@ struct u_upload_mgr *u_upload_create( struct pipe_context *pipe, */ void u_upload_destroy( struct u_upload_mgr *upload ); -/* Unmap and release old buffer. +/* Unmap and release old upload buffer. * + * This is like u_upload_unmap() except the upload buffer is released for + * recycling. This should be called on real hardware flushes on systems + * that don't support the PIPE_TRANSFER_UNSYNCHRONIZED flag, as otherwise + * the next u_upload_buffer will cause a sync on the buffer. + */ + +void u_upload_flush( struct u_upload_mgr *upload ); + +/** + * Unmap upload buffer + * + * \param upload Upload manager + * * This must usually be called prior to firing the command stream * which references the upload buffer, as many memory managers either * don't like firing a mapped buffer or cause subsequent maps of a - * fired buffer to wait. For now, it's easiest just to grab a new - * buffer. + * fired buffer to wait. */ -void u_upload_flush( struct u_upload_mgr *upload ); +void u_upload_unmap( struct u_upload_mgr *upload ); /** * Sub-allocate new memory from the upload buffer. diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.c b/src/gallium/auxiliary/util/u_vbuf_mgr.c index 04149525ea7..19eb689cfb2 100644 --- a/src/gallium/auxiliary/util/u_vbuf_mgr.c +++ b/src/gallium/auxiliary/util/u_vbuf_mgr.c @@ -79,6 +79,8 @@ struct u_vbuf_mgr_priv { void *saved_ve, *fallback_ve; boolean ve_binding_lock; + unsigned saved_buffer_offset[PIPE_MAX_ATTRIBS]; + boolean any_user_vbs; boolean incompatible_vb_layout; }; @@ -152,9 +154,9 @@ void u_vbuf_mgr_destroy(struct u_vbuf_mgr *mgrb) } -static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr, - int min_index, int max_index, - boolean *upload_flushed) +static enum u_vbuf_return_flags +u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr, + int min_index, int max_index) { struct translate_key key; struct translate_element *te; @@ -166,6 +168,7 @@ static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr, struct pipe_resource *out_buffer = NULL; unsigned i, num_verts, out_offset; struct pipe_vertex_element new_velems[PIPE_MAX_ATTRIBS]; + boolean upload_flushed = FALSE; memset(&key, 0, sizeof(key)); memset(tr_elem_index, 0xff, sizeof(tr_elem_index)); @@ -248,7 +251,7 @@ static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr, u_upload_alloc(mgr->b.uploader, key.output_stride * min_index, key.output_stride * num_verts, - &out_offset, &out_buffer, upload_flushed, + &out_offset, &out_buffer, &upload_flushed, (void**)&out_map); out_offset -= key.output_stride * min_index; @@ -308,6 +311,8 @@ static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr, } pipe_resource_reference(&out_buffer, NULL); + + return upload_flushed ? U_VBUF_UPLOAD_FLUSHED : 0; } static void u_vbuf_translate_end(struct u_vbuf_mgr_priv *mgr) @@ -485,6 +490,7 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb, pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer); pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL); + mgr->saved_buffer_offset[i] = vb->buffer_offset; if (!vb->buffer) { continue; @@ -510,14 +516,15 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb, mgr->b.nr_real_vertex_buffers = count; } -static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr, - int min_index, int max_index, - unsigned instance_count, - boolean *upload_flushed) +static enum u_vbuf_return_flags +u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr, + int min_index, int max_index, + unsigned instance_count) { unsigned i, nr = mgr->ve->count; unsigned count = max_index + 1 - min_index; boolean uploaded[PIPE_MAX_ATTRIBS] = {0}; + enum u_vbuf_return_flags retval = 0; for (i = 0; i < nr; i++) { unsigned index = mgr->ve->ve[i].vertex_buffer_index; @@ -537,6 +544,11 @@ static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr, } else if (vb->stride) { first = vb->stride * min_index; size = vb->stride * count; + + /* Unusual case when stride is smaller than the format size. + * XXX This won't work with interleaved arrays. */ + if (mgr->ve->native_format_size[i] > vb->stride) + size += mgr->ve->native_format_size[i] - vb->stride; } else { first = 0; size = mgr->ve->native_format_size[i]; @@ -551,11 +563,14 @@ static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr, vb->buffer_offset -= first; uploaded[index] = TRUE; - *upload_flushed = *upload_flushed || flushed; + if (flushed) + retval |= U_VBUF_UPLOAD_FLUSHED; } else { assert(mgr->b.real_vertex_buffer[index]); } } + + return retval; } static void u_vbuf_mgr_compute_max_index(struct u_vbuf_mgr_priv *mgr) @@ -597,14 +612,13 @@ static void u_vbuf_mgr_compute_max_index(struct u_vbuf_mgr_priv *mgr) } } -void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb, - const struct pipe_draw_info *info, - boolean *buffers_updated, - boolean *uploader_flushed) +enum u_vbuf_return_flags +u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb, + const struct pipe_draw_info *info) { struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; - boolean bufs_updated = FALSE, upload_flushed = FALSE; int min_index, max_index; + enum u_vbuf_return_flags retval = 0; u_vbuf_mgr_compute_max_index(mgr); @@ -617,32 +631,32 @@ void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb, /* Translate vertices with non-native layouts or formats. */ if (mgr->incompatible_vb_layout || mgr->ve->incompatible_layout) { - u_vbuf_translate_begin(mgr, min_index, max_index, &upload_flushed); + retval |= u_vbuf_translate_begin(mgr, min_index, max_index); if (mgr->fallback_ve) { - bufs_updated = TRUE; + retval |= U_VBUF_BUFFERS_UPDATED; } } /* Upload user buffers. */ if (mgr->any_user_vbs) { - u_vbuf_upload_buffers(mgr, min_index, max_index, info->instance_count, - &upload_flushed); - bufs_updated = TRUE; - } - - /* Set the return values. */ - if (buffers_updated) { - *buffers_updated = bufs_updated; - } - if (uploader_flushed) { - *uploader_flushed = upload_flushed; + retval |= u_vbuf_upload_buffers(mgr, min_index, max_index, + info->instance_count); + retval |= U_VBUF_BUFFERS_UPDATED; } + return retval; } void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgrb) { struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; + unsigned i; + + /* buffer offsets were modified in u_vbuf_upload_buffers */ + if (mgr->any_user_vbs) { + for (i = 0; i < mgr->b.nr_vertex_buffers; i++) + mgr->b.vertex_buffer[i].buffer_offset = mgr->saved_buffer_offset[i]; + } if (mgr->fallback_ve) { u_vbuf_translate_end(mgr); diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.h b/src/gallium/auxiliary/util/u_vbuf_mgr.h index 9380dce4f72..4e6372435d8 100644 --- a/src/gallium/auxiliary/util/u_vbuf_mgr.h +++ b/src/gallium/auxiliary/util/u_vbuf_mgr.h @@ -78,6 +78,11 @@ enum u_fetch_alignment { U_VERTEX_FETCH_DWORD_ALIGNED }; +enum u_vbuf_return_flags { + U_VBUF_BUFFERS_UPDATED = 1, + U_VBUF_UPLOAD_FLUSHED = 2 +}; + struct u_vbuf_mgr * u_vbuf_mgr_create(struct pipe_context *pipe, @@ -105,10 +110,9 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgr, unsigned count, const struct pipe_vertex_buffer *bufs); -void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgr, - const struct pipe_draw_info *info, - boolean *buffers_updated, - boolean *uploader_flushed); +enum u_vbuf_return_flags +u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgr, + const struct pipe_draw_info *info); void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgr); diff --git a/src/gallium/auxiliary/util/u_video.h b/src/gallium/auxiliary/util/u_video.h new file mode 100644 index 00000000000..6b67881e648 --- /dev/null +++ b/src/gallium/auxiliary/util/u_video.h @@ -0,0 +1,76 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef U_VIDEO_H +#define U_VIDEO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <pipe/p_defines.h> +#include <pipe/p_video_enums.h> + +/* u_reduce_video_profile() needs these */ +#include <pipe/p_compiler.h> +#include <util/u_debug.h> + +static INLINE enum pipe_video_codec +u_reduce_video_profile(enum pipe_video_profile profile) +{ + switch (profile) + { + case PIPE_VIDEO_PROFILE_MPEG1: + case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE: + case PIPE_VIDEO_PROFILE_MPEG2_MAIN: + return PIPE_VIDEO_CODEC_MPEG12; + + case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE: + case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE: + return PIPE_VIDEO_CODEC_MPEG4; + + case PIPE_VIDEO_PROFILE_VC1_SIMPLE: + case PIPE_VIDEO_PROFILE_VC1_MAIN: + case PIPE_VIDEO_PROFILE_VC1_ADVANCED: + return PIPE_VIDEO_CODEC_VC1; + + case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE: + case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: + case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: + return PIPE_VIDEO_CODEC_MPEG4_AVC; + + default: + assert(0); + return PIPE_VIDEO_CODEC_UNKNOWN; + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* U_VIDEO_H */ diff --git a/src/gallium/auxiliary/vl/vl_compositor.c b/src/gallium/auxiliary/vl/vl_compositor.c new file mode 100644 index 00000000000..faca96dc55b --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_compositor.c @@ -0,0 +1,765 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <pipe/p_compiler.h> +#include <pipe/p_context.h> + +#include <util/u_memory.h> +#include <util/u_draw.h> +#include <util/u_surface.h> + +#include <tgsi/tgsi_ureg.h> + +#include "vl_csc.h" +#include "vl_types.h" +#include "vl_compositor.h" + +typedef float csc_matrix[16]; + +static void * +create_vert_shader(struct vl_compositor *c) +{ + struct ureg_program *shader; + struct ureg_src vpos, vtex; + struct ureg_dst o_vpos, o_vtex; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return false; + + vpos = ureg_DECL_vs_input(shader, 0); + vtex = ureg_DECL_vs_input(shader, 1); + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0); + o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, 1); + + /* + * o_vpos = vpos + * o_vtex = vtex + */ + ureg_MOV(shader, o_vpos, vpos); + ureg_MOV(shader, o_vtex, vtex); + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, c->pipe); +} + +static void * +create_frag_shader_video_buffer(struct vl_compositor *c) +{ + struct ureg_program *shader; + struct ureg_src tc; + struct ureg_src csc[3]; + struct ureg_src sampler[3]; + struct ureg_dst texel; + struct ureg_dst fragment; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return false; + + tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR); + for (i = 0; i < 3; ++i) { + csc[i] = ureg_DECL_constant(shader, i); + sampler[i] = ureg_DECL_sampler(shader, i); + } + texel = ureg_DECL_temporary(shader); + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * texel.xyz = tex(tc, sampler[i]) + * fragment = csc * texel + */ + for (i = 0; i < 3; ++i) + ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, tc, sampler[i]); + + ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f)); + + for (i = 0; i < 3; ++i) + ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel)); + + ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f)); + + ureg_release_temporary(shader, texel); + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, c->pipe); +} + +static void * +create_frag_shader_palette(struct vl_compositor *c) +{ + struct ureg_program *shader; + struct ureg_src csc[3]; + struct ureg_src tc; + struct ureg_src sampler; + struct ureg_src palette; + struct ureg_dst texel; + struct ureg_dst fragment; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return false; + + for (i = 0; i < 3; ++i) + csc[i] = ureg_DECL_constant(shader, i); + + tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR); + sampler = ureg_DECL_sampler(shader, 0); + palette = ureg_DECL_sampler(shader, 1); + texel = ureg_DECL_temporary(shader); + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * texel = tex(tc, sampler) + * fragment.xyz = tex(texel, palette) * csc + * fragment.a = texel.a + */ + ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler); + ureg_MUL(shader, ureg_writemask(texel, TGSI_WRITEMASK_X), ureg_src(texel), ureg_imm1f(shader, 15.0f / 16.0f)); + ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(texel)); + + ureg_TEX(shader, texel, TGSI_TEXTURE_1D, ureg_src(texel), palette); + + for (i = 0; i < 3; ++i) + ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel)); + + ureg_release_temporary(shader, texel); + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, c->pipe); +} + +static void * +create_frag_shader_rgba(struct vl_compositor *c) +{ + struct ureg_program *shader; + struct ureg_src tc; + struct ureg_src sampler; + struct ureg_dst fragment; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return false; + + tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR); + sampler = ureg_DECL_sampler(shader, 0); + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * fragment = tex(tc, sampler) + */ + ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler); + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, c->pipe); +} + +static bool +init_shaders(struct vl_compositor *c) +{ + assert(c); + + c->vs = create_vert_shader(c); + if (!c->vs) { + debug_printf("Unable to create vertex shader.\n"); + return false; + } + + c->fs_video_buffer = create_frag_shader_video_buffer(c); + if (!c->fs_video_buffer) { + debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n"); + return false; + } + + c->fs_palette = create_frag_shader_palette(c); + if (!c->fs_palette) { + debug_printf("Unable to create Palette-to-RGB fragment shader.\n"); + return false; + } + + c->fs_rgba = create_frag_shader_rgba(c); + if (!c->fs_rgba) { + debug_printf("Unable to create RGB-to-RGB fragment shader.\n"); + return false; + } + + return true; +} + +static void cleanup_shaders(struct vl_compositor *c) +{ + assert(c); + + c->pipe->delete_vs_state(c->pipe, c->vs); + c->pipe->delete_fs_state(c->pipe, c->fs_video_buffer); + c->pipe->delete_fs_state(c->pipe, c->fs_palette); + c->pipe->delete_fs_state(c->pipe, c->fs_rgba); +} + +static bool +init_pipe_state(struct vl_compositor *c) +{ + struct pipe_rasterizer_state rast; + struct pipe_sampler_state sampler; + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state dsa; + unsigned i; + + assert(c); + + c->fb_state.nr_cbufs = 1; + c->fb_state.zsbuf = NULL; + + c->viewport.scale[2] = 1; + c->viewport.scale[3] = 1; + c->viewport.translate[2] = 0; + c->viewport.translate[3] = 0; + + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + + c->sampler_linear = c->pipe->create_sampler_state(c->pipe, &sampler); + + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + c->sampler_nearest = c->pipe->create_sampler_state(c->pipe, &sampler); + + memset(&blend, 0, sizeof blend); + blend.independent_blend_enable = 0; + blend.rt[0].blend_enable = 1; + blend.rt[0].rgb_func = PIPE_BLEND_ADD; + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + blend.rt[0].alpha_func = PIPE_BLEND_ADD; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.logicop_enable = 0; + blend.logicop_func = PIPE_LOGICOP_CLEAR; + blend.rt[0].colormask = PIPE_MASK_RGBA; + blend.dither = 0; + c->blend = c->pipe->create_blend_state(c->pipe, &blend); + + memset(&rast, 0, sizeof rast); + rast.flatshade = 1; + rast.front_ccw = 1; + rast.cull_face = PIPE_FACE_NONE; + rast.fill_back = PIPE_POLYGON_MODE_FILL; + rast.fill_front = PIPE_POLYGON_MODE_FILL; + rast.scissor = 1; + rast.line_width = 1; + rast.point_size_per_vertex = 1; + rast.offset_units = 1; + rast.offset_scale = 1; + rast.gl_rasterization_rules = 1; + + c->rast = c->pipe->create_rasterizer_state(c->pipe, &rast); + + memset(&dsa, 0, sizeof dsa); + dsa.depth.enabled = 0; + dsa.depth.writemask = 0; + dsa.depth.func = PIPE_FUNC_ALWAYS; + for (i = 0; i < 2; ++i) { + dsa.stencil[i].enabled = 0; + dsa.stencil[i].func = PIPE_FUNC_ALWAYS; + dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].valuemask = 0; + dsa.stencil[i].writemask = 0; + } + dsa.alpha.enabled = 0; + dsa.alpha.func = PIPE_FUNC_ALWAYS; + dsa.alpha.ref_value = 0; + c->dsa = c->pipe->create_depth_stencil_alpha_state(c->pipe, &dsa); + c->pipe->bind_depth_stencil_alpha_state(c->pipe, c->dsa); + return true; +} + +static void cleanup_pipe_state(struct vl_compositor *c) +{ + assert(c); + + /* Asserted in softpipe_delete_fs_state() for some reason */ + c->pipe->bind_vs_state(c->pipe, NULL); + c->pipe->bind_fs_state(c->pipe, NULL); + + c->pipe->delete_depth_stencil_alpha_state(c->pipe, c->dsa); + c->pipe->delete_sampler_state(c->pipe, c->sampler_linear); + c->pipe->delete_sampler_state(c->pipe, c->sampler_nearest); + c->pipe->delete_blend_state(c->pipe, c->blend); + c->pipe->delete_rasterizer_state(c->pipe, c->rast); +} + +static bool +create_vertex_buffer(struct vl_compositor *c) +{ + assert(c); + + pipe_resource_reference(&c->vertex_buf.buffer, NULL); + c->vertex_buf.buffer = pipe_buffer_create + ( + c->pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + sizeof(struct vertex4f) * VL_COMPOSITOR_MAX_LAYERS * 4 + ); + return c->vertex_buf.buffer != NULL; +} + +static bool +init_buffers(struct vl_compositor *c) +{ + struct pipe_vertex_element vertex_elems[2]; + + assert(c); + + /* + * Create our vertex buffer and vertex buffer elements + */ + c->vertex_buf.stride = sizeof(struct vertex4f); + c->vertex_buf.buffer_offset = 0; + create_vertex_buffer(c); + + vertex_elems[0].src_offset = 0; + vertex_elems[0].instance_divisor = 0; + vertex_elems[0].vertex_buffer_index = 0; + vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT; + vertex_elems[1].src_offset = sizeof(struct vertex2f); + vertex_elems[1].instance_divisor = 0; + vertex_elems[1].vertex_buffer_index = 0; + vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT; + c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems); + + /* + * Create our fragment shader's constant buffer + * Const buffer contains the color conversion matrix and bias vectors + */ + /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */ + c->csc_matrix = pipe_buffer_create + ( + c->pipe->screen, + PIPE_BIND_CONSTANT_BUFFER, + PIPE_USAGE_STATIC, + sizeof(csc_matrix) + ); + + return true; +} + +static void +cleanup_buffers(struct vl_compositor *c) +{ + assert(c); + + c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state); + pipe_resource_reference(&c->vertex_buf.buffer, NULL); + pipe_resource_reference(&c->csc_matrix, NULL); +} + +static INLINE struct pipe_video_rect +default_rect(struct vl_compositor_layer *layer) +{ + struct pipe_resource *res = layer->sampler_views[0]->texture; + struct pipe_video_rect rect = { 0, 0, res->width0, res->height0 }; + return rect; +} + +static INLINE struct vertex2f +calc_topleft(struct vertex2f size, struct pipe_video_rect rect) +{ + struct vertex2f res = { rect.x / size.x, rect.y / size.y }; + return res; +} + +static INLINE struct vertex2f +calc_bottomright(struct vertex2f size, struct pipe_video_rect rect) +{ + struct vertex2f res = { (rect.x + rect.w) / size.x, (rect.y + rect.h) / size.y }; + return res; +} + +static INLINE void +calc_src_and_dst(struct vl_compositor_layer *layer, unsigned width, unsigned height, + struct pipe_video_rect src, struct pipe_video_rect dst) +{ + struct vertex2f size = { width, height }; + + layer->src.tl = calc_topleft(size, src); + layer->src.br = calc_bottomright(size, src); + layer->dst.tl = calc_topleft(size, dst); + layer->dst.br = calc_bottomright(size, dst); +} + +static void +gen_rect_verts(struct vertex4f *vb, struct vl_compositor_layer *layer) +{ + assert(vb && layer); + + vb[0].x = layer->dst.tl.x; + vb[0].y = layer->dst.tl.y; + vb[0].z = layer->src.tl.x; + vb[0].w = layer->src.tl.y; + + vb[1].x = layer->dst.br.x; + vb[1].y = layer->dst.tl.y; + vb[1].z = layer->src.br.x; + vb[1].w = layer->src.tl.y; + + vb[2].x = layer->dst.br.x; + vb[2].y = layer->dst.br.y; + vb[2].z = layer->src.br.x; + vb[2].w = layer->src.br.y; + + vb[3].x = layer->dst.tl.x; + vb[3].y = layer->dst.br.y; + vb[3].z = layer->src.tl.x; + vb[3].w = layer->src.br.y; +} + +static void +gen_vertex_data(struct vl_compositor *c) +{ + struct vertex4f *vb; + struct pipe_transfer *buf_transfer; + unsigned i; + + assert(c); + + vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_DONTBLOCK, + &buf_transfer); + + if (!vb) { + // If buffer is still locked from last draw create a new one + create_vertex_buffer(c); + vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer); + } + + for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; i++) { + if (c->used_layers & (1 << i)) { + struct vl_compositor_layer *layer = &c->layers[i]; + gen_rect_verts(vb, layer); + vb += 4; + + if (layer->clearing && + c->dirty_tl.x >= layer->dst.tl.x && + c->dirty_tl.y >= layer->dst.tl.y && + c->dirty_br.x <= layer->dst.br.x && + c->dirty_br.y <= layer->dst.br.y) { + + // We clear the dirty area anyway, no need for clear_render_target + c->dirty_tl.x = c->dirty_tl.y = 1.0f; + c->dirty_br.x = c->dirty_br.y = 0.0f; + } + } + } + + pipe_buffer_unmap(c->pipe, buf_transfer); +} + +static void +draw_layers(struct vl_compositor *c) +{ + unsigned vb_index, i; + + assert(c); + + for (i = 0, vb_index = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) { + if (c->used_layers & (1 << i)) { + struct vl_compositor_layer *layer = &c->layers[i]; + struct pipe_sampler_view **samplers = &layer->sampler_views[0]; + unsigned num_sampler_views = !samplers[1] ? 1 : !samplers[2] ? 2 : 3; + + c->pipe->bind_fs_state(c->pipe, layer->fs); + c->pipe->bind_fragment_sampler_states(c->pipe, num_sampler_views, layer->samplers); + c->pipe->set_fragment_sampler_views(c->pipe, num_sampler_views, samplers); + util_draw_arrays(c->pipe, PIPE_PRIM_QUADS, vb_index * 4, 4); + vb_index++; + + // Remember the currently drawn area as dirty for the next draw command + c->dirty_tl.x = MIN2(layer->dst.tl.x, c->dirty_tl.x); + c->dirty_tl.y = MIN2(layer->dst.tl.y, c->dirty_tl.y); + c->dirty_br.x = MAX2(layer->dst.br.x, c->dirty_br.x); + c->dirty_br.y = MAX2(layer->dst.br.y, c->dirty_br.y); + } + } +} + +void +vl_compositor_reset_dirty_area(struct vl_compositor *c) +{ + assert(c); + + c->dirty_tl.x = c->dirty_tl.y = 0.0f; + c->dirty_br.x = c->dirty_br.y = 1.0f; +} + +void +vl_compositor_set_clear_color(struct vl_compositor *c, float color[4]) +{ + unsigned i; + + assert(c); + + for (i = 0; i < 4; ++i) + c->clear_color[i] = color[i]; +} + +void +vl_compositor_clear_layers(struct vl_compositor *c) +{ + unsigned i, j; + + assert(c); + + c->used_layers = 0; + for ( i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i) { + c->layers[i].fs = NULL; + for ( j = 0; j < 3; j++) + pipe_sampler_view_reference(&c->layers[i].sampler_views[j], NULL); + } +} + +void +vl_compositor_cleanup(struct vl_compositor *c) +{ + assert(c); + + vl_compositor_clear_layers(c); + + cleanup_buffers(c); + cleanup_shaders(c); + cleanup_pipe_state(c); +} + +void +vl_compositor_set_csc_matrix(struct vl_compositor *c, const float matrix[16]) +{ + struct pipe_transfer *buf_transfer; + + assert(c); + + memcpy + ( + pipe_buffer_map(c->pipe, c->csc_matrix, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer), + matrix, + sizeof(csc_matrix) + ); + + pipe_buffer_unmap(c->pipe, buf_transfer); +} + +void +vl_compositor_set_buffer_layer(struct vl_compositor *c, + unsigned layer, + struct pipe_video_buffer *buffer, + struct pipe_video_rect *src_rect, + struct pipe_video_rect *dst_rect) +{ + struct pipe_sampler_view **sampler_views; + unsigned i; + + assert(c && buffer); + + assert(layer < VL_COMPOSITOR_MAX_LAYERS); + + c->used_layers |= 1 << layer; + c->layers[layer].clearing = true; + c->layers[layer].fs = c->fs_video_buffer; + + sampler_views = buffer->get_sampler_view_components(buffer); + for (i = 0; i < 3; ++i) { + c->layers[layer].samplers[i] = c->sampler_linear; + pipe_sampler_view_reference(&c->layers[layer].sampler_views[i], sampler_views[i]); + } + + calc_src_and_dst(&c->layers[layer], buffer->width, buffer->height, + src_rect ? *src_rect : default_rect(&c->layers[layer]), + dst_rect ? *dst_rect : default_rect(&c->layers[layer])); +} + +void +vl_compositor_set_palette_layer(struct vl_compositor *c, + unsigned layer, + struct pipe_sampler_view *indexes, + struct pipe_sampler_view *palette, + struct pipe_video_rect *src_rect, + struct pipe_video_rect *dst_rect) +{ + assert(c && indexes && palette); + + assert(layer < VL_COMPOSITOR_MAX_LAYERS); + + c->used_layers |= 1 << layer; + c->layers[layer].clearing = false; + c->layers[layer].fs = c->fs_palette; + c->layers[layer].samplers[0] = c->sampler_linear; + c->layers[layer].samplers[1] = c->sampler_nearest; + c->layers[layer].samplers[2] = NULL; + pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], indexes); + pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], palette); + pipe_sampler_view_reference(&c->layers[layer].sampler_views[2], NULL); + calc_src_and_dst(&c->layers[layer], indexes->texture->width0, indexes->texture->height0, + src_rect ? *src_rect : default_rect(&c->layers[layer]), + dst_rect ? *dst_rect : default_rect(&c->layers[layer])); + +} + +void +vl_compositor_set_rgba_layer(struct vl_compositor *c, + unsigned layer, + struct pipe_sampler_view *rgba, + struct pipe_video_rect *src_rect, + struct pipe_video_rect *dst_rect) +{ + assert(c && rgba); + + assert(layer < VL_COMPOSITOR_MAX_LAYERS); + + c->used_layers |= 1 << layer; + c->layers[layer].clearing = rgba->swizzle_a == PIPE_SWIZZLE_ONE; + c->layers[layer].fs = c->fs_rgba; + c->layers[layer].samplers[0] = c->sampler_linear; + c->layers[layer].samplers[1] = NULL; + c->layers[layer].samplers[2] = NULL; + pipe_sampler_view_reference(&c->layers[layer].sampler_views[0], rgba); + pipe_sampler_view_reference(&c->layers[layer].sampler_views[1], NULL); + pipe_sampler_view_reference(&c->layers[layer].sampler_views[2], NULL); + calc_src_and_dst(&c->layers[layer], rgba->texture->width0, rgba->texture->height0, + src_rect ? *src_rect : default_rect(&c->layers[layer]), + dst_rect ? *dst_rect : default_rect(&c->layers[layer])); +} + +void +vl_compositor_render(struct vl_compositor *c, + enum pipe_mpeg12_picture_type picture_type, + struct pipe_surface *dst_surface, + struct pipe_video_rect *dst_area, + struct pipe_video_rect *dst_clip) +{ + struct pipe_scissor_state scissor; + + assert(c); + assert(dst_surface); + + c->fb_state.width = dst_surface->width; + c->fb_state.height = dst_surface->height; + c->fb_state.cbufs[0] = dst_surface; + + if (dst_area) { + c->viewport.scale[0] = dst_area->w; + c->viewport.scale[1] = dst_area->h; + c->viewport.translate[0] = dst_area->x; + c->viewport.translate[1] = dst_area->y; + } else { + c->viewport.scale[0] = dst_surface->width; + c->viewport.scale[1] = dst_surface->height; + c->viewport.translate[0] = 0; + c->viewport.translate[1] = 0; + } + + if (dst_clip) { + scissor.minx = dst_clip->x; + scissor.miny = dst_clip->y; + scissor.maxx = dst_clip->x + dst_clip->w; + scissor.maxy = dst_clip->y + dst_clip->h; + } else { + scissor.minx = 0; + scissor.miny = 0; + scissor.maxx = dst_surface->width; + scissor.maxy = dst_surface->height; + } + + gen_vertex_data(c); + + if (c->dirty_tl.x < c->dirty_br.x || c->dirty_tl.y < c->dirty_br.y) { + util_clear_render_target(c->pipe, dst_surface, c->clear_color, 0, 0, dst_surface->width, dst_surface->height); + c->dirty_tl.x = c->dirty_tl.y = 1.0f; + c->dirty_br.x = c->dirty_br.y = 0.0f; + } + + c->pipe->set_scissor_state(c->pipe, &scissor); + c->pipe->set_framebuffer_state(c->pipe, &c->fb_state); + c->pipe->set_viewport_state(c->pipe, &c->viewport); + c->pipe->bind_vs_state(c->pipe, c->vs); + c->pipe->set_vertex_buffers(c->pipe, 1, &c->vertex_buf); + c->pipe->bind_vertex_elements_state(c->pipe, c->vertex_elems_state); + c->pipe->set_constant_buffer(c->pipe, PIPE_SHADER_FRAGMENT, 0, c->csc_matrix); + c->pipe->bind_blend_state(c->pipe, c->blend); + c->pipe->bind_rasterizer_state(c->pipe, c->rast); + + draw_layers(c); +} + +bool +vl_compositor_init(struct vl_compositor *c, struct pipe_context *pipe) +{ + csc_matrix csc_matrix; + + c->pipe = pipe; + + if (!init_pipe_state(c)) + return false; + + if (!init_shaders(c)) { + cleanup_pipe_state(c); + return false; + } + if (!init_buffers(c)) { + cleanup_shaders(c); + cleanup_pipe_state(c); + return false; + } + + vl_compositor_clear_layers(c); + + vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, csc_matrix); + vl_compositor_set_csc_matrix(c, csc_matrix); + + c->clear_color[0] = c->clear_color[1] = 0.0f; + c->clear_color[2] = c->clear_color[3] = 0.0f; + vl_compositor_reset_dirty_area(c); + + return true; +} diff --git a/src/gallium/auxiliary/vl/vl_compositor.h b/src/gallium/auxiliary/vl/vl_compositor.h new file mode 100644 index 00000000000..0a9a7411a61 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_compositor.h @@ -0,0 +1,170 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_compositor_h +#define vl_compositor_h + +#include <pipe/p_state.h> +#include <pipe/p_video_decoder.h> +#include <pipe/p_video_state.h> + +#include "vl_types.h" + +struct pipe_context; + +/** + * composing and displaying of image data + */ + +#define VL_COMPOSITOR_MAX_LAYERS 16 + +struct vl_compositor_layer +{ + bool clearing; + + void *fs; + void *samplers[3]; + + struct pipe_sampler_view *sampler_views[3]; + struct { + struct vertex2f tl, br; + } src, dst; +}; + +struct vl_compositor +{ + struct pipe_context *pipe; + + struct pipe_framebuffer_state fb_state; + struct pipe_viewport_state viewport; + struct pipe_vertex_buffer vertex_buf; + struct pipe_resource *csc_matrix; + + void *sampler_linear; + void *sampler_nearest; + void *blend; + void *rast; + void *dsa; + void *vertex_elems_state; + + void *vs; + void *fs_video_buffer; + void *fs_palette; + void *fs_rgba; + + float clear_color[4]; + struct vertex2f dirty_tl, dirty_br; + + unsigned used_layers:VL_COMPOSITOR_MAX_LAYERS; + struct vl_compositor_layer layers[VL_COMPOSITOR_MAX_LAYERS]; +}; + +/** + * initialize this compositor + */ +bool +vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe); + +/** + * set yuv -> rgba conversion matrix + */ +void +vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float mat[16]); + +/** + * reset dirty area, so it's cleared with the clear colour + */ +void +vl_compositor_reset_dirty_area(struct vl_compositor *compositor); + +/** + * set the clear color + */ +void +vl_compositor_set_clear_color(struct vl_compositor *compositor, float color[4]); + +/** + * set overlay samplers + */ +/*@{*/ + +/** + * reset all currently set layers + */ +void +vl_compositor_clear_layers(struct vl_compositor *compositor); + +/** + * set a video buffer as a layer to render + */ +void +vl_compositor_set_buffer_layer(struct vl_compositor *compositor, + unsigned layer, + struct pipe_video_buffer *buffer, + struct pipe_video_rect *src_rect, + struct pipe_video_rect *dst_rect); + +/** + * set a paletted sampler as a layer to render + */ +void +vl_compositor_set_palette_layer(struct vl_compositor *compositor, + unsigned layer, + struct pipe_sampler_view *indexes, + struct pipe_sampler_view *palette, + struct pipe_video_rect *src_rect, + struct pipe_video_rect *dst_rect); + +/** + * set a rgba sampler as a layer to render + */ +void +vl_compositor_set_rgba_layer(struct vl_compositor *compositor, + unsigned layer, + struct pipe_sampler_view *rgba, + struct pipe_video_rect *src_rect, + struct pipe_video_rect *dst_rect); + +/*@}*/ + +/** + * render the layers to the frontbuffer + */ +void +vl_compositor_render(struct vl_compositor *compositor, + enum pipe_mpeg12_picture_type picture_type, + struct pipe_surface *dst_surface, + struct pipe_video_rect *dst_area, + struct pipe_video_rect *dst_clip); + +/** +* destroy this compositor +*/ +void +vl_compositor_cleanup(struct vl_compositor *compositor); + +#endif /* vl_compositor_h */ diff --git a/src/gallium/auxiliary/vl/vl_csc.c b/src/gallium/auxiliary/vl/vl_csc.c new file mode 100644 index 00000000000..4ca84e56a8c --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_csc.c @@ -0,0 +1,217 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <util/u_math.h> +#include <util/u_debug.h> + +#include "vl_csc.h" + +/* + * Color space conversion formulas + * + * To convert YCbCr to RGB, + * vec4 ycbcr, rgb + * mat44 csc + * rgb = csc * ycbcr + * + * To calculate the color space conversion matrix csc with ProcAmp adjustments, + * mat44 csc, cstd, procamp, bias + * csc = cstd * (procamp * bias) + * + * Where cstd is a matrix corresponding to one of the color standards (BT.601, BT.709, etc) + * adjusted for the kind of YCbCr -> RGB mapping wanted (1:1, full), + * bias is a matrix corresponding to the kind of YCbCr -> RGB mapping wanted (1:1, full) + * + * To calculate procamp, + * mat44 procamp, hue, saturation, brightness, contrast + * procamp = brightness * (saturation * (contrast * hue)) + * Alternatively, + * procamp = saturation * (brightness * (contrast * hue)) + * + * contrast + * [ c, 0, 0, 0] + * [ 0, c, 0, 0] + * [ 0, 0, c, 0] + * [ 0, 0, 0, 1] + * + * brightness + * [ 1, 0, 0, b] + * [ 0, 1, 0, 0] + * [ 0, 0, 1, 0] + * [ 0, 0, 0, 1] + * + * saturation + * [ 1, 0, 0, 0] + * [ 0, s, 0, 0] + * [ 0, 0, s, 0] + * [ 0, 0, 0, 1] + * + * hue + * [ 1, 0, 0, 0] + * [ 0, cos(h), sin(h), 0] + * [ 0, -sin(h), cos(h), 0] + * [ 0, 0, 0, 1] + * + * procamp + * [ c, 0, 0, b] + * [ 0, c*s*cos(h), c*s*sin(h), 0] + * [ 0, -c*s*sin(h), c*s*cos(h), 0] + * [ 0, 0, 0, 1] + * + * bias + * [ 1, 0, 0, ybias] + * [ 0, 1, 0, cbbias] + * [ 0, 0, 1, crbias] + * [ 0, 0, 0, 1] + * + * csc + * [ c*cstd[ 0], c*cstd[ 1]*s*cos(h) - c*cstd[ 2]*s*sin(h), c*cstd[ 2]*s*cos(h) + c*cstd[ 1]*s*sin(h), cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 2]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))] + * [ c*cstd[ 4], c*cstd[ 5]*s*cos(h) - c*cstd[ 6]*s*sin(h), c*cstd[ 6]*s*cos(h) + c*cstd[ 5]*s*sin(h), cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 6]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))] + * [ c*cstd[ 8], c*cstd[ 9]*s*cos(h) - c*cstd[10]*s*sin(h), c*cstd[10]*s*cos(h) + c*cstd[ 9]*s*sin(h), cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[10]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))] + * [ c*cstd[12], c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h), c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h), cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))] + */ + +/* + * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [16,235] + */ +static const float bt_601[16] = +{ + 1.0f, 0.0f, 1.371f, 0.0f, + 1.0f, -0.336f, -0.698f, 0.0f, + 1.0f, 1.732f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/* + * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [0,255] + */ +static const float bt_601_full[16] = +{ + 1.164f, 0.0f, 1.596f, 0.0f, + 1.164f, -0.391f, -0.813f, 0.0f, + 1.164f, 2.018f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/* + * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [16,235] + */ +static const float bt_709[16] = +{ + 1.0f, 0.0f, 1.540f, 0.0f, + 1.0f, -0.183f, -0.459f, 0.0f, + 1.0f, 1.816f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/* + * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [0,255] + */ +static const float bt_709_full[16] = +{ + 1.164f, 0.0f, 1.793f, 0.0f, + 1.164f, -0.213f, -0.534f, 0.0f, + 1.164f, 2.115f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +static const float identity[16] = +{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +const struct vl_procamp vl_default_procamp = { + 0.0f, /* brightness */ + 1.0f, /* contrast */ + 1.0f, /* saturation */ + 0.0f /* hue */ +}; + +void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs, + struct vl_procamp *procamp, + bool full_range, + float *matrix) +{ + float ybias = full_range ? -16.0f/255.0f : 0.0f; + float cbbias = -128.0f/255.0f; + float crbias = -128.0f/255.0f; + + const struct vl_procamp *p = procamp ? procamp : &vl_default_procamp; + float c = p->contrast; + float s = p->saturation; + float b = p->brightness; + float h = p->hue; + + const float *cstd; + + assert(matrix); + + switch (cs) { + case VL_CSC_COLOR_STANDARD_BT_601: + cstd = full_range ? &bt_601_full[0] : &bt_601[0]; + break; + case VL_CSC_COLOR_STANDARD_BT_709: + cstd = full_range ? &bt_709_full[0] : &bt_709[0]; + break; + case VL_CSC_COLOR_STANDARD_IDENTITY: + default: + assert(cs == VL_CSC_COLOR_STANDARD_IDENTITY); + memcpy(matrix, &identity[0], sizeof(float) * 16); + return; + } + + matrix[ 0] = c*cstd[ 0]; + matrix[ 1] = c*cstd[ 1]*s*cosf(h) - c*cstd[ 2]*s*sinf(h); + matrix[ 2] = c*cstd[ 2]*s*cosf(h) + c*cstd[ 1]*s*sinf(h); + matrix[ 3] = cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[ 2]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h)); + + matrix[ 4] = c*cstd[ 4]; + matrix[ 5] = c*cstd[ 5]*s*cosf(h) - c*cstd[ 6]*s*sinf(h); + matrix[ 6] = c*cstd[ 6]*s*cosf(h) + c*cstd[ 5]*s*sinf(h); + matrix[ 7] = cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[ 6]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h)); + + matrix[ 8] = c*cstd[ 8]; + matrix[ 9] = c*cstd[ 9]*s*cosf(h) - c*cstd[10]*s*sinf(h); + matrix[10] = c*cstd[10]*s*cosf(h) + c*cstd[ 9]*s*sinf(h); + matrix[11] = cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[10]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h)); + + matrix[12] = c*cstd[12]; + matrix[13] = c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h); + matrix[14] = c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h); + matrix[15] = cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h)); +} diff --git a/src/gallium/auxiliary/vl/vl_csc.h b/src/gallium/auxiliary/vl/vl_csc.h new file mode 100644 index 00000000000..9b73fb3aef2 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_csc.h @@ -0,0 +1,55 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_csc_h +#define vl_csc_h + +#include <pipe/p_compiler.h> + +struct vl_procamp +{ + float brightness; + float contrast; + float saturation; + float hue; +}; + +enum VL_CSC_COLOR_STANDARD +{ + VL_CSC_COLOR_STANDARD_IDENTITY, + VL_CSC_COLOR_STANDARD_BT_601, + VL_CSC_COLOR_STANDARD_BT_709 +}; + +extern const struct vl_procamp vl_default_procamp; + +void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs, + struct vl_procamp *procamp, + bool full_range, + float *matrix); + +#endif /* vl_csc_h */ diff --git a/src/gallium/auxiliary/vl/vl_decoder.c b/src/gallium/auxiliary/vl/vl_decoder.c new file mode 100644 index 00000000000..fac03359a0f --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_decoder.c @@ -0,0 +1,77 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <pipe/p_video_decoder.h> + +#include <util/u_video.h> + +#include "vl_decoder.h" +#include "vl_mpeg12_decoder.h" + +bool +vl_profile_supported(struct pipe_screen *screen, enum pipe_video_profile profile) +{ + assert(screen); + switch (u_reduce_video_profile(profile)) { + case PIPE_VIDEO_CODEC_MPEG12: + return true; + default: + return false; + } +} + +struct pipe_video_decoder * +vl_create_decoder(struct pipe_context *pipe, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height) +{ + unsigned buffer_width, buffer_height; + bool pot_buffers; + + assert(pipe); + assert(width > 0 && height > 0); + + pot_buffers = !pipe->screen->get_video_param + ( + pipe->screen, + profile, + PIPE_VIDEO_CAP_NPOT_TEXTURES + ); + + buffer_width = pot_buffers ? util_next_power_of_two(width) : align(width, MACROBLOCK_WIDTH); + buffer_height = pot_buffers ? util_next_power_of_two(height) : align(height, MACROBLOCK_HEIGHT); + + switch (u_reduce_video_profile(profile)) { + case PIPE_VIDEO_CODEC_MPEG12: + return vl_create_mpeg12_decoder(pipe, profile, entrypoint, chroma_format, buffer_width, buffer_height); + default: + return NULL; + } + return NULL; +} diff --git a/src/gallium/auxiliary/vl/vl_decoder.h b/src/gallium/auxiliary/vl/vl_decoder.h new file mode 100644 index 00000000000..0e9280dbfa2 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_decoder.h @@ -0,0 +1,50 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_decoder_h +#define vl_decoder_h + +#include <pipe/p_video_decoder.h> + +/** + * check if a given profile is supported with shader based decoding + */ +bool +vl_profile_supported(struct pipe_screen *screen, enum pipe_video_profile profile); + +/** + * standard implementation of pipe->create_video_decoder + */ +struct pipe_video_decoder * +vl_create_decoder(struct pipe_context *pipe, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height); + +#endif /* vl_decoder_h */ diff --git a/src/gallium/auxiliary/vl/vl_defines.h b/src/gallium/auxiliary/vl/vl_defines.h new file mode 100644 index 00000000000..7568db027e6 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_defines.h @@ -0,0 +1,41 @@ +/************************************************************************** + * + * Copyright 2011 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_defines_h +#define vl_defines_h + +/* constants usually used with all known codecs */ +#define MACROBLOCK_WIDTH 16 +#define MACROBLOCK_HEIGHT 16 + +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 8 + +#define VL_MAX_PLANES 3 +#define VL_MAX_REF_FRAMES 2 + +#endif diff --git a/src/gallium/auxiliary/vl/vl_idct.c b/src/gallium/auxiliary/vl/vl_idct.c new file mode 100644 index 00000000000..ad786145392 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_idct.c @@ -0,0 +1,871 @@ +/************************************************************************** + * + * Copyright 2010 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <pipe/p_context.h> +#include <pipe/p_screen.h> + +#include <util/u_draw.h> +#include <util/u_sampler.h> +#include <util/u_memory.h> + +#include <tgsi/tgsi_ureg.h> + +#include "vl_defines.h" +#include "vl_types.h" +#include "vl_vertex_buffers.h" +#include "vl_idct.h" + +enum VS_OUTPUT +{ + VS_O_VPOS, + VS_O_L_ADDR0, + VS_O_L_ADDR1, + VS_O_R_ADDR0, + VS_O_R_ADDR1 +}; + +/** + * The DCT matrix stored as hex representation of floats. Equal to the following equation: + * for (i = 0; i < 8; ++i) + * for (j = 0; j < 8; ++j) + * if (i == 0) const_matrix[i][j] = 1.0f / sqrtf(8.0f); + * else const_matrix[i][j] = sqrtf(2.0f / 8.0f) * cosf((2 * j + 1) * i * M_PI / (2.0f * 8.0f)); + */ +static const uint32_t const_matrix[8][8] = { + { 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3, 0x3eb504f3 }, + { 0x3efb14be, 0x3ed4db31, 0x3e8e39da, 0x3dc7c5c4, 0xbdc7c5c2, 0xbe8e39d9, 0xbed4db32, 0xbefb14bf }, + { 0x3eec835f, 0x3e43ef15, 0xbe43ef14, 0xbeec835e, 0xbeec835f, 0xbe43ef1a, 0x3e43ef1b, 0x3eec835f }, + { 0x3ed4db31, 0xbdc7c5c2, 0xbefb14bf, 0xbe8e39dd, 0x3e8e39d7, 0x3efb14bf, 0x3dc7c5d0, 0xbed4db34 }, + { 0x3eb504f3, 0xbeb504f3, 0xbeb504f4, 0x3eb504f1, 0x3eb504f3, 0xbeb504f0, 0xbeb504ef, 0x3eb504f4 }, + { 0x3e8e39da, 0xbefb14bf, 0x3dc7c5c8, 0x3ed4db32, 0xbed4db34, 0xbdc7c5bb, 0x3efb14bf, 0xbe8e39d7 }, + { 0x3e43ef15, 0xbeec835f, 0x3eec835f, 0xbe43ef07, 0xbe43ef23, 0x3eec8361, 0xbeec835c, 0x3e43ef25 }, + { 0x3dc7c5c4, 0xbe8e39dd, 0x3ed4db32, 0xbefb14c0, 0x3efb14be, 0xbed4db31, 0x3e8e39ce, 0xbdc7c596 }, +}; + +static void +calc_addr(struct ureg_program *shader, struct ureg_dst addr[2], + struct ureg_src tc, struct ureg_src start, bool right_side, + bool transposed, float size) +{ + unsigned wm_start = (right_side == transposed) ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_Y; + unsigned sw_start = right_side ? TGSI_SWIZZLE_Y : TGSI_SWIZZLE_X; + + unsigned wm_tc = (right_side == transposed) ? TGSI_WRITEMASK_Y : TGSI_WRITEMASK_X; + unsigned sw_tc = right_side ? TGSI_SWIZZLE_X : TGSI_SWIZZLE_Y; + + /* + * addr[0..1].(start) = right_side ? start.x : tc.x + * addr[0..1].(tc) = right_side ? tc.y : start.y + * addr[0..1].z = tc.z + * addr[1].(start) += 1.0f / scale + */ + ureg_MOV(shader, ureg_writemask(addr[0], wm_start), ureg_scalar(start, sw_start)); + ureg_MOV(shader, ureg_writemask(addr[0], wm_tc), ureg_scalar(tc, sw_tc)); + + ureg_ADD(shader, ureg_writemask(addr[1], wm_start), ureg_scalar(start, sw_start), ureg_imm1f(shader, 1.0f / size)); + ureg_MOV(shader, ureg_writemask(addr[1], wm_tc), ureg_scalar(tc, sw_tc)); +} + +static void +increment_addr(struct ureg_program *shader, struct ureg_dst daddr[2], + struct ureg_src saddr[2], bool right_side, bool transposed, + int pos, float size) +{ + unsigned wm_start = (right_side == transposed) ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_Y; + unsigned wm_tc = (right_side == transposed) ? TGSI_WRITEMASK_Y : TGSI_WRITEMASK_X; + + /* + * daddr[0..1].(start) = saddr[0..1].(start) + * daddr[0..1].(tc) = saddr[0..1].(tc) + */ + + ureg_MOV(shader, ureg_writemask(daddr[0], wm_start), saddr[0]); + ureg_ADD(shader, ureg_writemask(daddr[0], wm_tc), saddr[0], ureg_imm1f(shader, pos / size)); + ureg_MOV(shader, ureg_writemask(daddr[1], wm_start), saddr[1]); + ureg_ADD(shader, ureg_writemask(daddr[1], wm_tc), saddr[1], ureg_imm1f(shader, pos / size)); +} + +static void +fetch_four(struct ureg_program *shader, struct ureg_dst m[2], struct ureg_src addr[2], + struct ureg_src sampler, bool resource3d) +{ + ureg_TEX(shader, m[0], resource3d ? TGSI_TEXTURE_3D : TGSI_TEXTURE_2D, addr[0], sampler); + ureg_TEX(shader, m[1], resource3d ? TGSI_TEXTURE_3D : TGSI_TEXTURE_2D, addr[1], sampler); +} + +static void +matrix_mul(struct ureg_program *shader, struct ureg_dst dst, struct ureg_dst l[2], struct ureg_dst r[2]) +{ + struct ureg_dst tmp; + + tmp = ureg_DECL_temporary(shader); + + /* + * tmp.xy = dot4(m[0][0..1], m[1][0..1]) + * dst = tmp.x + tmp.y + */ + ureg_DP4(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(l[0]), ureg_src(r[0])); + ureg_DP4(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(l[1]), ureg_src(r[1])); + ureg_ADD(shader, dst, + ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y)); + + ureg_release_temporary(shader, tmp); +} + +static void * +create_mismatch_vert_shader(struct vl_idct *idct) +{ + struct ureg_program *shader; + struct ureg_src vpos; + struct ureg_src scale; + struct ureg_dst t_tex; + struct ureg_dst o_vpos, o_addr[2]; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return NULL; + + vpos = ureg_DECL_vs_input(shader, VS_I_VPOS); + + t_tex = ureg_DECL_temporary(shader); + + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS); + + o_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0); + o_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1); + + /* + * scale = (BLOCK_WIDTH, BLOCK_HEIGHT) / (dst.width, dst.height) + * + * t_vpos = vpos + 7 / BLOCK_WIDTH + * o_vpos.xy = t_vpos * scale + * + * o_addr = calc_addr(...) + * + */ + + scale = ureg_imm2f(shader, + (float)BLOCK_WIDTH / idct->buffer_width, + (float)BLOCK_HEIGHT / idct->buffer_height); + + ureg_MAD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), vpos, scale, scale); + ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f)); + + ureg_MUL(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), vpos, scale); + calc_addr(shader, o_addr, ureg_src(t_tex), ureg_src(t_tex), false, false, idct->buffer_width / 4); + + ureg_release_temporary(shader, t_tex); + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, idct->pipe); +} + +static void * +create_mismatch_frag_shader(struct vl_idct *idct) +{ + struct ureg_program *shader; + + struct ureg_src addr[2]; + + struct ureg_dst m[8][2]; + struct ureg_dst fragment; + + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return NULL; + + addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR); + addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR); + + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + for (i = 0; i < 8; ++i) { + m[i][0] = ureg_DECL_temporary(shader); + m[i][1] = ureg_DECL_temporary(shader); + } + + for (i = 0; i < 8; ++i) { + increment_addr(shader, m[i], addr, false, false, i, idct->buffer_height); + } + + for (i = 0; i < 8; ++i) { + struct ureg_src s_addr[2]; + s_addr[0] = ureg_src(m[i][0]); + s_addr[1] = ureg_src(m[i][1]); + fetch_four(shader, m[i], s_addr, ureg_DECL_sampler(shader, 0), false); + } + + for (i = 1; i < 8; ++i) { + ureg_ADD(shader, m[0][0], ureg_src(m[0][0]), ureg_src(m[i][0])); + ureg_ADD(shader, m[0][1], ureg_src(m[0][1]), ureg_src(m[i][1])); + } + + ureg_ADD(shader, m[0][0], ureg_src(m[0][0]), ureg_src(m[0][1])); + ureg_DP4(shader, m[0][0], ureg_abs(ureg_src(m[0][0])), ureg_imm1f(shader, 1 << 14)); + + ureg_MUL(shader, ureg_writemask(m[0][0], TGSI_WRITEMASK_W), ureg_abs(ureg_src(m[7][1])), ureg_imm1f(shader, 1 << 14)); + ureg_FRC(shader, m[0][0], ureg_src(m[0][0])); + ureg_SGT(shader, m[0][0], ureg_imm1f(shader, 0.5f), ureg_abs(ureg_src(m[0][0]))); + + ureg_CMP(shader, ureg_writemask(m[0][0], TGSI_WRITEMASK_W), ureg_negate(ureg_src(m[0][0])), + ureg_imm1f(shader, 1.0f / (1 << 15)), ureg_imm1f(shader, -1.0f / (1 << 15))); + ureg_MUL(shader, ureg_writemask(m[0][0], TGSI_WRITEMASK_W), ureg_src(m[0][0]), + ureg_scalar(ureg_src(m[0][0]), TGSI_SWIZZLE_X)); + + ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(m[7][1])); + ureg_ADD(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_src(m[0][0]), ureg_src(m[7][1])); + + for (i = 0; i < 8; ++i) { + ureg_release_temporary(shader, m[i][0]); + ureg_release_temporary(shader, m[i][1]); + } + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, idct->pipe); +} + +static void * +create_stage1_vert_shader(struct vl_idct *idct) +{ + struct ureg_program *shader; + struct ureg_src vrect, vpos; + struct ureg_src scale; + struct ureg_dst t_tex, t_start; + struct ureg_dst o_vpos, o_l_addr[2], o_r_addr[2]; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return NULL; + + vrect = ureg_DECL_vs_input(shader, VS_I_RECT); + vpos = ureg_DECL_vs_input(shader, VS_I_VPOS); + + t_tex = ureg_DECL_temporary(shader); + t_start = ureg_DECL_temporary(shader); + + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS); + + o_l_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0); + o_l_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1); + + o_r_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0); + o_r_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1); + + /* + * scale = (BLOCK_WIDTH, BLOCK_HEIGHT) / (dst.width, dst.height) + * + * t_vpos = vpos + vrect + * o_vpos.xy = t_vpos * scale + * o_vpos.zw = vpos + * + * o_l_addr = calc_addr(...) + * o_r_addr = calc_addr(...) + * + */ + + scale = ureg_imm2f(shader, + (float)BLOCK_WIDTH / idct->buffer_width, + (float)BLOCK_HEIGHT / idct->buffer_height); + + ureg_ADD(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), vpos, vrect); + ureg_MUL(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), ureg_src(t_tex), scale); + + ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_tex)); + ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f)); + + ureg_MUL(shader, ureg_writemask(t_start, TGSI_WRITEMASK_XY), vpos, scale); + + calc_addr(shader, o_l_addr, ureg_src(t_tex), ureg_src(t_start), false, false, idct->buffer_width / 4); + calc_addr(shader, o_r_addr, vrect, ureg_imm1f(shader, 0.0f), true, true, BLOCK_WIDTH / 4); + + ureg_release_temporary(shader, t_tex); + ureg_release_temporary(shader, t_start); + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, idct->pipe); +} + +static void * +create_stage1_frag_shader(struct vl_idct *idct) +{ + struct ureg_program *shader; + + struct ureg_src l_addr[2], r_addr[2]; + + struct ureg_dst l[4][2], r[2]; + struct ureg_dst *fragment; + + int i, j; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return NULL; + + fragment = MALLOC(idct->nr_of_render_targets * sizeof(struct ureg_dst)); + + l_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR); + l_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR); + + r_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0, TGSI_INTERPOLATE_LINEAR); + r_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1, TGSI_INTERPOLATE_LINEAR); + + for (i = 0; i < idct->nr_of_render_targets; ++i) + fragment[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, i); + + for (i = 0; i < 4; ++i) { + l[i][0] = ureg_DECL_temporary(shader); + l[i][1] = ureg_DECL_temporary(shader); + } + + r[0] = ureg_DECL_temporary(shader); + r[1] = ureg_DECL_temporary(shader); + + for (i = 0; i < 4; ++i) { + increment_addr(shader, l[i], l_addr, false, false, i - 2, idct->buffer_height); + } + + for (i = 0; i < 4; ++i) { + struct ureg_src s_addr[2]; + s_addr[0] = ureg_src(l[i][0]); + s_addr[1] = ureg_src(l[i][1]); + fetch_four(shader, l[i], s_addr, ureg_DECL_sampler(shader, 0), false); + } + + for (i = 0; i < idct->nr_of_render_targets; ++i) { + struct ureg_src s_addr[2]; + + increment_addr(shader, r, r_addr, true, true, i - (signed)idct->nr_of_render_targets / 2, BLOCK_HEIGHT); + + s_addr[0] = ureg_src(r[0]); + s_addr[1] = ureg_src(r[1]); + fetch_four(shader, r, s_addr, ureg_DECL_sampler(shader, 1), false); + + for (j = 0; j < 4; ++j) { + matrix_mul(shader, ureg_writemask(fragment[i], TGSI_WRITEMASK_X << j), l[j], r); + } + } + + for (i = 0; i < 4; ++i) { + ureg_release_temporary(shader, l[i][0]); + ureg_release_temporary(shader, l[i][1]); + } + ureg_release_temporary(shader, r[0]); + ureg_release_temporary(shader, r[1]); + + ureg_END(shader); + + FREE(fragment); + + return ureg_create_shader_and_destroy(shader, idct->pipe); +} + +void +vl_idct_stage2_vert_shader(struct vl_idct *idct, struct ureg_program *shader, + unsigned first_output, struct ureg_dst tex) +{ + struct ureg_src vrect, vpos; + struct ureg_src scale; + struct ureg_dst t_start; + struct ureg_dst o_l_addr[2], o_r_addr[2]; + + vrect = ureg_DECL_vs_input(shader, VS_I_RECT); + vpos = ureg_DECL_vs_input(shader, VS_I_VPOS); + + t_start = ureg_DECL_temporary(shader); + + --first_output; + + o_l_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_L_ADDR0); + o_l_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_L_ADDR1); + + o_r_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_R_ADDR0); + o_r_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output + VS_O_R_ADDR1); + + scale = ureg_imm2f(shader, + (float)BLOCK_WIDTH / idct->buffer_width, + (float)BLOCK_HEIGHT / idct->buffer_height); + + ureg_MUL(shader, ureg_writemask(tex, TGSI_WRITEMASK_Z), + ureg_scalar(vrect, TGSI_SWIZZLE_X), + ureg_imm1f(shader, BLOCK_WIDTH / idct->nr_of_render_targets)); + ureg_MUL(shader, ureg_writemask(t_start, TGSI_WRITEMASK_XY), vpos, scale); + + calc_addr(shader, o_l_addr, vrect, ureg_imm1f(shader, 0.0f), false, false, BLOCK_WIDTH / 4); + calc_addr(shader, o_r_addr, ureg_src(tex), ureg_src(t_start), true, false, idct->buffer_height / 4); + + ureg_MOV(shader, ureg_writemask(o_r_addr[0], TGSI_WRITEMASK_Z), ureg_src(tex)); + ureg_MOV(shader, ureg_writemask(o_r_addr[1], TGSI_WRITEMASK_Z), ureg_src(tex)); +} + +void +vl_idct_stage2_frag_shader(struct vl_idct *idct, struct ureg_program *shader, + unsigned first_input, struct ureg_dst fragment) +{ + struct ureg_src l_addr[2], r_addr[2]; + + struct ureg_dst l[2], r[2]; + + --first_input; + + l_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR); + l_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR); + + r_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_R_ADDR0, TGSI_INTERPOLATE_LINEAR); + r_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input + VS_O_R_ADDR1, TGSI_INTERPOLATE_LINEAR); + + l[0] = ureg_DECL_temporary(shader); + l[1] = ureg_DECL_temporary(shader); + r[0] = ureg_DECL_temporary(shader); + r[1] = ureg_DECL_temporary(shader); + + fetch_four(shader, l, l_addr, ureg_DECL_sampler(shader, 1), false); + fetch_four(shader, r, r_addr, ureg_DECL_sampler(shader, 0), true); + + matrix_mul(shader, fragment, l, r); + + ureg_release_temporary(shader, l[0]); + ureg_release_temporary(shader, l[1]); + ureg_release_temporary(shader, r[0]); + ureg_release_temporary(shader, r[1]); +} + +static bool +init_shaders(struct vl_idct *idct) +{ + idct->vs_mismatch = create_mismatch_vert_shader(idct); + if (!idct->vs_mismatch) + goto error_vs_mismatch; + + idct->fs_mismatch = create_mismatch_frag_shader(idct); + if (!idct->fs_mismatch) + goto error_fs_mismatch; + + idct->vs = create_stage1_vert_shader(idct); + if (!idct->vs) + goto error_vs; + + idct->fs = create_stage1_frag_shader(idct); + if (!idct->fs) + goto error_fs; + + return true; + +error_fs: + idct->pipe->delete_vs_state(idct->pipe, idct->vs); + +error_vs: + idct->pipe->delete_vs_state(idct->pipe, idct->vs_mismatch); + +error_fs_mismatch: + idct->pipe->delete_vs_state(idct->pipe, idct->fs); + +error_vs_mismatch: + return false; +} + +static void +cleanup_shaders(struct vl_idct *idct) +{ + idct->pipe->delete_vs_state(idct->pipe, idct->vs_mismatch); + idct->pipe->delete_fs_state(idct->pipe, idct->fs_mismatch); + idct->pipe->delete_vs_state(idct->pipe, idct->vs); + idct->pipe->delete_fs_state(idct->pipe, idct->fs); +} + +static bool +init_state(struct vl_idct *idct) +{ + struct pipe_blend_state blend; + struct pipe_rasterizer_state rs_state; + struct pipe_sampler_state sampler; + unsigned i; + + assert(idct); + + memset(&rs_state, 0, sizeof(rs_state)); + rs_state.point_size = 1; + rs_state.gl_rasterization_rules = true; + idct->rs_state = idct->pipe->create_rasterizer_state(idct->pipe, &rs_state); + if (!idct->rs_state) + goto error_rs_state; + + memset(&blend, 0, sizeof blend); + + blend.independent_blend_enable = 0; + blend.rt[0].blend_enable = 0; + blend.rt[0].rgb_func = PIPE_BLEND_ADD; + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_func = PIPE_BLEND_ADD; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.logicop_enable = 0; + blend.logicop_func = PIPE_LOGICOP_CLEAR; + /* Needed to allow color writes to FB, even if blending disabled */ + blend.rt[0].colormask = PIPE_MASK_RGBA; + blend.dither = 0; + idct->blend = idct->pipe->create_blend_state(idct->pipe, &blend); + if (!idct->blend) + goto error_blend; + + for (i = 0; i < 2; ++i) { + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_REPEAT; + sampler.wrap_t = PIPE_TEX_WRAP_REPEAT; + sampler.wrap_r = PIPE_TEX_WRAP_REPEAT; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + idct->samplers[i] = idct->pipe->create_sampler_state(idct->pipe, &sampler); + if (!idct->samplers[i]) + goto error_samplers; + } + + return true; + +error_samplers: + for (i = 0; i < 2; ++i) + if (idct->samplers[i]) + idct->pipe->delete_sampler_state(idct->pipe, idct->samplers[i]); + + idct->pipe->delete_rasterizer_state(idct->pipe, idct->rs_state); + +error_blend: + idct->pipe->delete_blend_state(idct->pipe, idct->blend); + +error_rs_state: + return false; +} + +static void +cleanup_state(struct vl_idct *idct) +{ + unsigned i; + + for (i = 0; i < 2; ++i) + idct->pipe->delete_sampler_state(idct->pipe, idct->samplers[i]); + + idct->pipe->delete_rasterizer_state(idct->pipe, idct->rs_state); + idct->pipe->delete_blend_state(idct->pipe, idct->blend); +} + +static bool +init_source(struct vl_idct *idct, struct vl_idct_buffer *buffer) +{ + struct pipe_resource *tex; + struct pipe_surface surf_templ; + + assert(idct && buffer); + + tex = buffer->sampler_views.individual.source->texture; + + buffer->fb_state_mismatch.width = tex->width0; + buffer->fb_state_mismatch.height = tex->height0; + buffer->fb_state_mismatch.nr_cbufs = 1; + + memset(&surf_templ, 0, sizeof(surf_templ)); + surf_templ.format = tex->format; + surf_templ.u.tex.first_layer = 0; + surf_templ.u.tex.last_layer = 0; + surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + buffer->fb_state_mismatch.cbufs[0] = idct->pipe->create_surface(idct->pipe, tex, &surf_templ); + + buffer->viewport_mismatch.scale[0] = tex->width0; + buffer->viewport_mismatch.scale[1] = tex->height0; + buffer->viewport_mismatch.scale[2] = 1; + buffer->viewport_mismatch.scale[3] = 1; + + return true; +} + +static void +cleanup_source(struct vl_idct *idct, struct vl_idct_buffer *buffer) +{ + assert(idct && buffer); + + pipe_surface_reference(&buffer->fb_state_mismatch.cbufs[0], NULL); + + pipe_sampler_view_reference(&buffer->sampler_views.individual.source, NULL); +} + +static bool +init_intermediate(struct vl_idct *idct, struct vl_idct_buffer *buffer) +{ + struct pipe_resource *tex; + struct pipe_surface surf_templ; + unsigned i; + + assert(idct && buffer); + + tex = buffer->sampler_views.individual.intermediate->texture; + + buffer->fb_state.width = tex->width0; + buffer->fb_state.height = tex->height0; + buffer->fb_state.nr_cbufs = idct->nr_of_render_targets; + for(i = 0; i < idct->nr_of_render_targets; ++i) { + memset(&surf_templ, 0, sizeof(surf_templ)); + surf_templ.format = tex->format; + surf_templ.u.tex.first_layer = i; + surf_templ.u.tex.last_layer = i; + surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + buffer->fb_state.cbufs[i] = idct->pipe->create_surface( + idct->pipe, tex, &surf_templ); + + if (!buffer->fb_state.cbufs[i]) + goto error_surfaces; + } + + buffer->viewport.scale[0] = tex->width0; + buffer->viewport.scale[1] = tex->height0; + buffer->viewport.scale[2] = 1; + buffer->viewport.scale[3] = 1; + + return true; + +error_surfaces: + for(i = 0; i < idct->nr_of_render_targets; ++i) + pipe_surface_reference(&buffer->fb_state.cbufs[i], NULL); + + return false; +} + +static void +cleanup_intermediate(struct vl_idct *idct, struct vl_idct_buffer *buffer) +{ + unsigned i; + + assert(idct && buffer); + + for(i = 0; i < idct->nr_of_render_targets; ++i) + pipe_surface_reference(&buffer->fb_state.cbufs[i], NULL); + + pipe_sampler_view_reference(&buffer->sampler_views.individual.intermediate, NULL); +} + +struct pipe_sampler_view * +vl_idct_upload_matrix(struct pipe_context *pipe, float scale) +{ + struct pipe_resource tex_templ, *matrix; + struct pipe_sampler_view sv_templ, *sv; + struct pipe_transfer *buf_transfer; + unsigned i, j, pitch; + float *f; + + struct pipe_box rect = + { + 0, 0, 0, + BLOCK_WIDTH / 4, + BLOCK_HEIGHT, + 1 + }; + + assert(pipe); + + memset(&tex_templ, 0, sizeof(tex_templ)); + tex_templ.target = PIPE_TEXTURE_2D; + tex_templ.format = PIPE_FORMAT_R32G32B32A32_FLOAT; + tex_templ.last_level = 0; + tex_templ.width0 = 2; + tex_templ.height0 = 8; + tex_templ.depth0 = 1; + tex_templ.array_size = 1; + tex_templ.usage = PIPE_USAGE_IMMUTABLE; + tex_templ.bind = PIPE_BIND_SAMPLER_VIEW; + tex_templ.flags = 0; + + matrix = pipe->screen->resource_create(pipe->screen, &tex_templ); + if (!matrix) + goto error_matrix; + + buf_transfer = pipe->get_transfer + ( + pipe, matrix, + 0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &rect + ); + if (!buf_transfer) + goto error_transfer; + + pitch = buf_transfer->stride / sizeof(float); + + f = pipe->transfer_map(pipe, buf_transfer); + if (!f) + goto error_map; + + for(i = 0; i < BLOCK_HEIGHT; ++i) + for(j = 0; j < BLOCK_WIDTH; ++j) + // transpose and scale + f[i * pitch + j] = ((const float (*)[8])const_matrix)[j][i] * scale; + + pipe->transfer_unmap(pipe, buf_transfer); + pipe->transfer_destroy(pipe, buf_transfer); + + memset(&sv_templ, 0, sizeof(sv_templ)); + u_sampler_view_default_template(&sv_templ, matrix, matrix->format); + sv = pipe->create_sampler_view(pipe, matrix, &sv_templ); + pipe_resource_reference(&matrix, NULL); + if (!sv) + goto error_map; + + return sv; + +error_map: + pipe->transfer_destroy(pipe, buf_transfer); + +error_transfer: + pipe_resource_reference(&matrix, NULL); + +error_matrix: + return NULL; +} + +bool vl_idct_init(struct vl_idct *idct, struct pipe_context *pipe, + unsigned buffer_width, unsigned buffer_height, + unsigned nr_of_render_targets, + struct pipe_sampler_view *matrix, + struct pipe_sampler_view *transpose) +{ + assert(idct && pipe); + assert(matrix && transpose); + + idct->pipe = pipe; + idct->buffer_width = buffer_width; + idct->buffer_height = buffer_height; + idct->nr_of_render_targets = nr_of_render_targets; + + pipe_sampler_view_reference(&idct->matrix, matrix); + pipe_sampler_view_reference(&idct->transpose, transpose); + + if(!init_shaders(idct)) + return false; + + if(!init_state(idct)) { + cleanup_shaders(idct); + return false; + } + + return true; +} + +void +vl_idct_cleanup(struct vl_idct *idct) +{ + cleanup_shaders(idct); + cleanup_state(idct); + + pipe_sampler_view_reference(&idct->matrix, NULL); + pipe_sampler_view_reference(&idct->transpose, NULL); +} + +bool +vl_idct_init_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer, + struct pipe_sampler_view *source, + struct pipe_sampler_view *intermediate) +{ + assert(buffer && idct); + assert(source && intermediate); + + memset(buffer, 0, sizeof(struct vl_idct_buffer)); + + buffer->idct = idct; + + pipe_sampler_view_reference(&buffer->sampler_views.individual.matrix, idct->matrix); + pipe_sampler_view_reference(&buffer->sampler_views.individual.source, source); + pipe_sampler_view_reference(&buffer->sampler_views.individual.transpose, idct->transpose); + pipe_sampler_view_reference(&buffer->sampler_views.individual.intermediate, intermediate); + + if (!init_source(idct, buffer)) + return false; + + if (!init_intermediate(idct, buffer)) + return false; + + return true; +} + +void +vl_idct_cleanup_buffer(struct vl_idct_buffer *buffer) +{ + assert(buffer); + + cleanup_source(buffer->idct, buffer); + cleanup_intermediate(buffer->idct, buffer); + + pipe_sampler_view_reference(&buffer->sampler_views.individual.matrix, NULL); + pipe_sampler_view_reference(&buffer->sampler_views.individual.transpose, NULL); +} + +void +vl_idct_flush(struct vl_idct_buffer *buffer, unsigned num_instances) +{ + struct vl_idct *idct; + assert(buffer); + + idct = buffer->idct; + + idct->pipe->bind_rasterizer_state(idct->pipe, idct->rs_state); + idct->pipe->bind_blend_state(idct->pipe, idct->blend); + idct->pipe->bind_fragment_sampler_states(idct->pipe, 2, idct->samplers); + idct->pipe->set_fragment_sampler_views(idct->pipe, 2, buffer->sampler_views.stage[0]); + + /* mismatch control */ + idct->pipe->set_framebuffer_state(idct->pipe, &buffer->fb_state_mismatch); + idct->pipe->set_viewport_state(idct->pipe, &buffer->viewport_mismatch); + idct->pipe->bind_vs_state(idct->pipe, idct->vs_mismatch); + idct->pipe->bind_fs_state(idct->pipe, idct->fs_mismatch); + util_draw_arrays_instanced(idct->pipe, PIPE_PRIM_POINTS, 0, 1, 0, num_instances); + + /* first stage */ + idct->pipe->set_framebuffer_state(idct->pipe, &buffer->fb_state); + idct->pipe->set_viewport_state(idct->pipe, &buffer->viewport); + idct->pipe->bind_vs_state(idct->pipe, idct->vs); + idct->pipe->bind_fs_state(idct->pipe, idct->fs); + util_draw_arrays_instanced(idct->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances); +} + +void +vl_idct_prepare_stage2(struct vl_idct_buffer *buffer) +{ + assert(buffer); + + /* second stage */ + buffer->idct->pipe->bind_rasterizer_state(buffer->idct->pipe, buffer->idct->rs_state); + buffer->idct->pipe->bind_fragment_sampler_states(buffer->idct->pipe, 2, buffer->idct->samplers); + buffer->idct->pipe->set_fragment_sampler_views(buffer->idct->pipe, 2, buffer->sampler_views.stage[1]); +} + diff --git a/src/gallium/auxiliary/vl/vl_idct.h b/src/gallium/auxiliary/vl/vl_idct.h new file mode 100644 index 00000000000..98e2c795564 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_idct.h @@ -0,0 +1,121 @@ +/************************************************************************** + * + * Copyright 2010 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_idct_h +#define vl_idct_h + +#include <pipe/p_state.h> + +#include <tgsi/tgsi_ureg.h> + +/* shader based inverse distinct cosinus transformation + * expect usage of vl_vertex_buffers as a todo list + */ +struct vl_idct +{ + struct pipe_context *pipe; + + unsigned buffer_width; + unsigned buffer_height; + unsigned nr_of_render_targets; + + void *rs_state; + void *blend; + + void *samplers[2]; + + void *vs_mismatch, *fs_mismatch; + void *vs, *fs; + + struct pipe_sampler_view *matrix; + struct pipe_sampler_view *transpose; +}; + +/* a set of buffers to work with */ +struct vl_idct_buffer +{ + struct vl_idct *idct; + + struct pipe_viewport_state viewport_mismatch; + struct pipe_viewport_state viewport; + + struct pipe_framebuffer_state fb_state_mismatch; + struct pipe_framebuffer_state fb_state; + + union + { + struct pipe_sampler_view *all[4]; + struct pipe_sampler_view *stage[2][2]; + struct { + struct pipe_sampler_view *source, *matrix; + struct pipe_sampler_view *intermediate, *transpose; + } individual; + } sampler_views; +}; + +/* upload the idct matrix, which can be shared by all idct instances of a pipe */ +struct pipe_sampler_view * +vl_idct_upload_matrix(struct pipe_context *pipe, float scale); + +void +vl_idct_stage2_vert_shader(struct vl_idct *idct, struct ureg_program *shader, + unsigned first_output, struct ureg_dst tex); + +void +vl_idct_stage2_frag_shader(struct vl_idct *idct, struct ureg_program *shader, + unsigned first_input, struct ureg_dst fragment); + +/* init an idct instance */ +bool +vl_idct_init(struct vl_idct *idct, struct pipe_context *pipe, + unsigned buffer_width, unsigned buffer_height, + unsigned nr_of_render_targets, + struct pipe_sampler_view *matrix, + struct pipe_sampler_view *transpose); + +/* destroy an idct instance */ +void +vl_idct_cleanup(struct vl_idct *idct); + +/* init a buffer assosiated with agiven idct instance */ +bool +vl_idct_init_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer, + struct pipe_sampler_view *source, + struct pipe_sampler_view *intermediate); + +/* cleanup a buffer of an idct instance */ +void +vl_idct_cleanup_buffer(struct vl_idct_buffer *buffer); + +/* flush the buffer and start rendering, vertex buffers needs to be setup before calling this */ +void +vl_idct_flush(struct vl_idct_buffer *buffer, unsigned num_verts); + +void +vl_idct_prepare_stage2(struct vl_idct_buffer *buffer); + +#endif diff --git a/src/gallium/auxiliary/vl/vl_mc.c b/src/gallium/auxiliary/vl/vl_mc.c new file mode 100644 index 00000000000..0b3723c9792 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mc.c @@ -0,0 +1,658 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <pipe/p_context.h> + +#include <util/u_sampler.h> +#include <util/u_draw.h> + +#include <tgsi/tgsi_ureg.h> + +#include "vl_defines.h" +#include "vl_vertex_buffers.h" +#include "vl_mc.h" +#include "vl_idct.h" + +enum VS_OUTPUT +{ + VS_O_VPOS, + VS_O_VTOP, + VS_O_VBOTTOM, + + VS_O_FLAGS = VS_O_VTOP, + VS_O_VTEX = VS_O_VBOTTOM +}; + +static struct ureg_dst +calc_position(struct vl_mc *r, struct ureg_program *shader, struct ureg_src block_scale) +{ + struct ureg_src vrect, vpos; + struct ureg_dst t_vpos; + struct ureg_dst o_vpos; + + vrect = ureg_DECL_vs_input(shader, VS_I_RECT); + vpos = ureg_DECL_vs_input(shader, VS_I_VPOS); + + t_vpos = ureg_DECL_temporary(shader); + + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS); + + /* + * block_scale = (MACROBLOCK_WIDTH, MACROBLOCK_HEIGHT) / (dst.width, dst.height) + * + * t_vpos = (vpos + vrect) * block_scale + * o_vpos.xy = t_vpos + * o_vpos.zw = vpos + */ + ureg_ADD(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), vpos, vrect); + ureg_MUL(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos), block_scale); + ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos)); + ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f)); + + return t_vpos; +} + +static struct ureg_dst +calc_line(struct ureg_program *shader) +{ + struct ureg_dst tmp; + struct ureg_src pos; + + tmp = ureg_DECL_temporary(shader); + + pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS, TGSI_INTERPOLATE_LINEAR); + + /* + * tmp.y = fraction(pos.y / 2) >= 0.5 ? 1 : 0 + */ + ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f)); + ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp)); + ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f)); + + return tmp; +} + +static void * +create_ref_vert_shader(struct vl_mc *r) +{ + struct ureg_program *shader; + struct ureg_src mv_scale; + struct ureg_src vmv[2]; + struct ureg_dst t_vpos; + struct ureg_dst o_vmv[2]; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return NULL; + + vmv[0] = ureg_DECL_vs_input(shader, VS_I_MV_TOP); + vmv[1] = ureg_DECL_vs_input(shader, VS_I_MV_BOTTOM); + + t_vpos = calc_position(r, shader, ureg_imm2f(shader, + (float)MACROBLOCK_WIDTH / r->buffer_width, + (float)MACROBLOCK_HEIGHT / r->buffer_height) + ); + + o_vmv[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP); + o_vmv[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM); + + /* + * mv_scale.xy = 0.5 / (dst.width, dst.height); + * mv_scale.z = 1.0f / 4.0f + * mv_scale.w = 1.0f / 255.0f + * + * // Apply motion vectors + * o_vmv[0..1].xy = vmv[0..1] * mv_scale + t_vpos + * o_vmv[0..1].zw = vmv[0..1] * mv_scale + * + */ + + mv_scale = ureg_imm4f(shader, + 0.5f / r->buffer_width, + 0.5f / r->buffer_height, + 1.0f / 4.0f, + 1.0f / PIPE_VIDEO_MV_WEIGHT_MAX); + + for (i = 0; i < 2; ++i) { + ureg_MAD(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_XY), mv_scale, vmv[i], ureg_src(t_vpos)); + ureg_MUL(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_ZW), mv_scale, vmv[i]); + } + + ureg_release_temporary(shader, t_vpos); + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, r->pipe); +} + +static void * +create_ref_frag_shader(struct vl_mc *r) +{ + const float y_scale = + r->buffer_height / 2 * + r->macroblock_size / MACROBLOCK_HEIGHT; + + struct ureg_program *shader; + struct ureg_src tc[2], sampler; + struct ureg_dst ref, field; + struct ureg_dst fragment; + unsigned label; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return NULL; + + tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP, TGSI_INTERPOLATE_LINEAR); + tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM, TGSI_INTERPOLATE_LINEAR); + + sampler = ureg_DECL_sampler(shader, 0); + ref = ureg_DECL_temporary(shader); + + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + field = calc_line(shader); + + /* + * ref = field.z ? tc[1] : tc[0] + * + * // Adjust tc acording to top/bottom field selection + * if (|ref.z|) { + * ref.y *= y_scale + * ref.y = floor(ref.y) + * ref.y += ref.z + * ref.y /= y_scale + * } + * fragment.xyz = tex(ref, sampler[0]) + */ + ureg_CMP(shader, ureg_writemask(ref, TGSI_WRITEMASK_XYZ), + ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)), + tc[1], tc[0]); + ureg_CMP(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), + ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)), + tc[1], tc[0]); + + ureg_IF(shader, ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z), &label); + + ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), + ureg_src(ref), ureg_imm1f(shader, y_scale)); + ureg_FLR(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), ureg_src(ref)); + ureg_ADD(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), + ureg_src(ref), ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z)); + ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), + ureg_src(ref), ureg_imm1f(shader, 1.0f / y_scale)); + + ureg_fixup_label(shader, label, ureg_get_instruction_number(shader)); + ureg_ENDIF(shader); + + ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), TGSI_TEXTURE_2D, ureg_src(ref), sampler); + + ureg_release_temporary(shader, ref); + + ureg_release_temporary(shader, field); + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, r->pipe); +} + +static void * +create_ycbcr_vert_shader(struct vl_mc *r, vl_mc_ycbcr_vert_shader vs_callback, void *callback_priv) +{ + struct ureg_program *shader; + + struct ureg_src vrect, vpos; + struct ureg_dst t_vpos, t_vtex; + struct ureg_dst o_vpos, o_flags; + + struct vertex2f scale = { + (float)BLOCK_WIDTH / r->buffer_width * MACROBLOCK_WIDTH / r->macroblock_size, + (float)BLOCK_HEIGHT / r->buffer_height * MACROBLOCK_HEIGHT / r->macroblock_size + }; + + unsigned label; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return NULL; + + vrect = ureg_DECL_vs_input(shader, VS_I_RECT); + vpos = ureg_DECL_vs_input(shader, VS_I_VPOS); + + t_vpos = calc_position(r, shader, ureg_imm2f(shader, scale.x, scale.y)); + t_vtex = ureg_DECL_temporary(shader); + + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS); + o_flags = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS); + + /* + * o_vtex.xy = t_vpos + * o_flags.z = intra * 0.5 + * + * if(interlaced) { + * t_vtex.xy = vrect.y ? { 0, scale.y } : { -scale.y : 0 } + * t_vtex.z = vpos.y % 2 + * t_vtex.y = t_vtex.z ? t_vtex.x : t_vtex.y + * o_vpos.y = t_vtex.y + t_vpos.y + * + * o_flags.w = t_vtex.z ? 0 : 1 + * } + * + */ + + vs_callback(callback_priv, r, shader, VS_O_VTEX, t_vpos); + + ureg_MUL(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_Z), + ureg_scalar(vpos, TGSI_SWIZZLE_Z), ureg_imm1f(shader, 0.5f)); + ureg_MOV(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W), ureg_imm1f(shader, -1.0f)); + + if (r->macroblock_size == MACROBLOCK_HEIGHT) { //TODO + ureg_IF(shader, ureg_scalar(vpos, TGSI_SWIZZLE_W), &label); + + ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_XY), + ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_Y)), + ureg_imm2f(shader, 0.0f, scale.y), + ureg_imm2f(shader, -scale.y, 0.0f)); + ureg_MUL(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z), + ureg_scalar(vpos, TGSI_SWIZZLE_Y), ureg_imm1f(shader, 0.5f)); + + ureg_FRC(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z), ureg_src(t_vtex)); + + ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y), + ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)), + ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Y)); + ureg_ADD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_Y), + ureg_src(t_vpos), ureg_src(t_vtex)); + + ureg_CMP(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W), + ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)), + ureg_imm1f(shader, 0.0f), ureg_imm1f(shader, 1.0f)); + + ureg_fixup_label(shader, label, ureg_get_instruction_number(shader)); + ureg_ENDIF(shader); + } + + ureg_release_temporary(shader, t_vtex); + ureg_release_temporary(shader, t_vpos); + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, r->pipe); +} + +static void * +create_ycbcr_frag_shader(struct vl_mc *r, float scale, bool invert, + vl_mc_ycbcr_frag_shader fs_callback, void *callback_priv) +{ + struct ureg_program *shader; + struct ureg_src flags; + struct ureg_dst tmp; + struct ureg_dst fragment; + unsigned label; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return NULL; + + flags = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS, TGSI_INTERPOLATE_LINEAR); + + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + tmp = calc_line(shader); + + /* + * if (field == tc.w) + * kill(); + * else { + * fragment.xyz = tex(tc, sampler) * scale + tc.z + * fragment.w = 1.0f + * } + */ + + ureg_SEQ(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), + ureg_scalar(flags, TGSI_SWIZZLE_W), ureg_src(tmp)); + + ureg_IF(shader, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), &label); + + ureg_KILP(shader); + + ureg_fixup_label(shader, label, ureg_get_instruction_number(shader)); + ureg_ELSE(shader, &label); + + fs_callback(callback_priv, r, shader, VS_O_VTEX, tmp); + + if (scale != 1.0f) + ureg_MAD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), + ureg_src(tmp), ureg_imm1f(shader, scale), + ureg_scalar(flags, TGSI_SWIZZLE_Z)); + else + ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), + ureg_src(tmp), ureg_scalar(flags, TGSI_SWIZZLE_Z)); + + ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(tmp), ureg_imm1f(shader, invert ? -1.0f : 1.0f)); + ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f)); + + ureg_fixup_label(shader, label, ureg_get_instruction_number(shader)); + ureg_ENDIF(shader); + + ureg_release_temporary(shader, tmp); + + ureg_END(shader); + + return ureg_create_shader_and_destroy(shader, r->pipe); +} + +static bool +init_pipe_state(struct vl_mc *r) +{ + struct pipe_sampler_state sampler; + struct pipe_blend_state blend; + struct pipe_rasterizer_state rs_state; + unsigned i; + + assert(r); + + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + r->sampler_ref = r->pipe->create_sampler_state(r->pipe, &sampler); + if (!r->sampler_ref) + goto error_sampler_ref; + + for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) { + memset(&blend, 0, sizeof blend); + blend.independent_blend_enable = 0; + blend.rt[0].blend_enable = 1; + blend.rt[0].rgb_func = PIPE_BLEND_ADD; + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_func = PIPE_BLEND_ADD; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.logicop_enable = 0; + blend.logicop_func = PIPE_LOGICOP_CLEAR; + blend.rt[0].colormask = i; + blend.dither = 0; + r->blend_clear[i] = r->pipe->create_blend_state(r->pipe, &blend); + if (!r->blend_clear[i]) + goto error_blend; + + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + r->blend_add[i] = r->pipe->create_blend_state(r->pipe, &blend); + if (!r->blend_add[i]) + goto error_blend; + + blend.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT; + blend.rt[0].alpha_dst_factor = PIPE_BLEND_REVERSE_SUBTRACT; + r->blend_sub[i] = r->pipe->create_blend_state(r->pipe, &blend); + if (!r->blend_sub[i]) + goto error_blend; + } + + memset(&rs_state, 0, sizeof(rs_state)); + /*rs_state.sprite_coord_enable */ + rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; + rs_state.point_quad_rasterization = true; + rs_state.point_size = BLOCK_WIDTH; + rs_state.gl_rasterization_rules = true; + r->rs_state = r->pipe->create_rasterizer_state(r->pipe, &rs_state); + if (!r->rs_state) + goto error_rs_state; + + return true; + +error_rs_state: +error_blend: + for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) { + if (r->blend_sub[i]) + r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]); + + if (r->blend_add[i]) + r->pipe->delete_blend_state(r->pipe, r->blend_add[i]); + + if (r->blend_clear[i]) + r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]); + } + + r->pipe->delete_sampler_state(r->pipe, r->sampler_ref); + +error_sampler_ref: + return false; +} + +static void +cleanup_pipe_state(struct vl_mc *r) +{ + unsigned i; + + assert(r); + + r->pipe->delete_sampler_state(r->pipe, r->sampler_ref); + for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) { + r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]); + r->pipe->delete_blend_state(r->pipe, r->blend_add[i]); + r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]); + } + r->pipe->delete_rasterizer_state(r->pipe, r->rs_state); +} + +bool +vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe, + unsigned buffer_width, unsigned buffer_height, + unsigned macroblock_size, float scale, + vl_mc_ycbcr_vert_shader vs_callback, + vl_mc_ycbcr_frag_shader fs_callback, + void *callback_priv) +{ + assert(renderer); + assert(pipe); + + memset(renderer, 0, sizeof(struct vl_mc)); + + renderer->pipe = pipe; + renderer->buffer_width = buffer_width; + renderer->buffer_height = buffer_height; + renderer->macroblock_size = macroblock_size; + + if (!init_pipe_state(renderer)) + goto error_pipe_state; + + renderer->vs_ref = create_ref_vert_shader(renderer); + if (!renderer->vs_ref) + goto error_vs_ref; + + renderer->vs_ycbcr = create_ycbcr_vert_shader(renderer, vs_callback, callback_priv); + if (!renderer->vs_ycbcr) + goto error_vs_ycbcr; + + renderer->fs_ref = create_ref_frag_shader(renderer); + if (!renderer->fs_ref) + goto error_fs_ref; + + renderer->fs_ycbcr = create_ycbcr_frag_shader(renderer, scale, false, fs_callback, callback_priv); + if (!renderer->fs_ycbcr) + goto error_fs_ycbcr; + + renderer->fs_ycbcr_sub = create_ycbcr_frag_shader(renderer, scale, true, fs_callback, callback_priv); + if (!renderer->fs_ycbcr_sub) + goto error_fs_ycbcr_sub; + + return true; + +error_fs_ycbcr_sub: + renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr); + +error_fs_ycbcr: + renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref); + +error_fs_ref: + renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr); + +error_vs_ycbcr: + renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref); + +error_vs_ref: + cleanup_pipe_state(renderer); + +error_pipe_state: + return false; +} + +void +vl_mc_cleanup(struct vl_mc *renderer) +{ + assert(renderer); + + cleanup_pipe_state(renderer); + + renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref); + renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr); + renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref); + renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr); + renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr_sub); +} + +bool +vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer) +{ + assert(renderer && buffer); + + buffer->renderer = renderer; + + buffer->viewport.scale[2] = 1; + buffer->viewport.scale[3] = 1; + buffer->viewport.translate[0] = 0; + buffer->viewport.translate[1] = 0; + buffer->viewport.translate[2] = 0; + buffer->viewport.translate[3] = 0; + + buffer->fb_state.nr_cbufs = 1; + buffer->fb_state.zsbuf = NULL; + + return true; +} + +void +vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer) +{ + assert(buffer); +} + +void +vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface) +{ + assert(buffer && surface); + + buffer->surface_cleared = false; + + buffer->viewport.scale[0] = surface->width; + buffer->viewport.scale[1] = surface->height; + + buffer->fb_state.width = surface->width; + buffer->fb_state.height = surface->height; + buffer->fb_state.cbufs[0] = surface; +} + +static void +prepare_pipe_4_rendering(struct vl_mc_buffer *buffer, unsigned mask) +{ + struct vl_mc *renderer; + + assert(buffer); + + renderer = buffer->renderer; + renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state); + + if (buffer->surface_cleared) + renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_add[mask]); + else + renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_clear[mask]); + + renderer->pipe->set_framebuffer_state(renderer->pipe, &buffer->fb_state); + renderer->pipe->set_viewport_state(renderer->pipe, &buffer->viewport); +} + +void +vl_mc_render_ref(struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref) +{ + struct vl_mc *renderer; + + assert(buffer && ref); + + prepare_pipe_4_rendering(buffer, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B); + + renderer = buffer->renderer; + + renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ref); + renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ref); + + renderer->pipe->set_fragment_sampler_views(renderer->pipe, 1, &ref); + renderer->pipe->bind_fragment_sampler_states(renderer->pipe, 1, &renderer->sampler_ref); + + util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, + renderer->buffer_width / MACROBLOCK_WIDTH * + renderer->buffer_height / MACROBLOCK_HEIGHT); + + buffer->surface_cleared = true; +} + +void +vl_mc_render_ycbcr(struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances) +{ + struct vl_mc *renderer; + unsigned mask = 1 << component; + + assert(buffer); + + if (num_instances == 0) + return; + + prepare_pipe_4_rendering(buffer, mask); + + renderer = buffer->renderer; + + renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ycbcr); + renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr); + + util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances); + + if (buffer->surface_cleared) { + renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_sub[mask]); + renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr_sub); + util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances); + } +} diff --git a/src/gallium/auxiliary/vl/vl_mc.h b/src/gallium/auxiliary/vl/vl_mc.h new file mode 100644 index 00000000000..9fabf02a3ac --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mc.h @@ -0,0 +1,99 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_mc_h +#define vl_mc_h + +#include <pipe/p_state.h> +#include <pipe/p_video_state.h> + +#include <tgsi/tgsi_ureg.h> + +#include "vl_defines.h" +#include "vl_types.h" + +#define VL_MC_NUM_BLENDERS (1 << VL_MAX_PLANES) + +struct pipe_context; + +struct vl_mc +{ + struct pipe_context *pipe; + unsigned buffer_width; + unsigned buffer_height; + unsigned macroblock_size; + + void *rs_state; + + void *blend_clear[VL_MC_NUM_BLENDERS]; + void *blend_add[VL_MC_NUM_BLENDERS]; + void *blend_sub[VL_MC_NUM_BLENDERS]; + void *vs_ref, *vs_ycbcr; + void *fs_ref, *fs_ycbcr, *fs_ycbcr_sub; + void *sampler_ref; +}; + +struct vl_mc_buffer +{ + struct vl_mc *renderer; + + bool surface_cleared; + + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state fb_state; +}; + +typedef void (*vl_mc_ycbcr_vert_shader)(void *priv, struct vl_mc *mc, + struct ureg_program *shader, + unsigned first_output, + struct ureg_dst tex); + +typedef void (*vl_mc_ycbcr_frag_shader)(void *priv, struct vl_mc *mc, + struct ureg_program *shader, + unsigned first_input, + struct ureg_dst dst); + +bool vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe, + unsigned picture_width, unsigned picture_height, + unsigned macroblock_size, float scale, + vl_mc_ycbcr_vert_shader vs_callback, + vl_mc_ycbcr_frag_shader fs_callback, + void *callback_priv); + +void vl_mc_cleanup(struct vl_mc *renderer); + +bool vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer); + +void vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer); + +void vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface); + +void vl_mc_render_ref(struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref); + +void vl_mc_render_ycbcr(struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances); + +#endif /* vl_mc_h */ diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c new file mode 100644 index 00000000000..9dd032e911d --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c @@ -0,0 +1,1837 @@ +/************************************************************************** + * + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +/** + * This file is based uppon slice_xvmc.c and vlc.h from the xine project, + * which in turn is based on mpeg2dec. The following is the original copyright: + * + * Copyright (C) 2000-2002 Michel Lespinasse <[email protected]> + * Copyright (C) 1999-2000 Aaron Holtzman <[email protected]> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdint.h> + +#include <pipe/p_compiler.h> +#include <pipe/p_video_state.h> + +#include "vl_vlc.h" +#include "vl_mpeg12_bitstream.h" + +/* take num bits from the high part of bit_buf and zero extend them */ +#define UBITS(buf,num) (((uint32_t)(buf)) >> (32 - (num))) + +/* take num bits from the high part of bit_buf and sign extend them */ +#define SBITS(buf,num) (((int32_t)(buf)) >> (32 - (num))) + +/* macroblock modes */ +#define MACROBLOCK_INTRA 1 +#define MACROBLOCK_PATTERN 2 +#define MACROBLOCK_MOTION_BACKWARD 4 +#define MACROBLOCK_MOTION_FORWARD 8 +#define MACROBLOCK_QUANT 16 + +/* motion_type */ +#define MOTION_TYPE_MASK (3*64) +#define MOTION_TYPE_BASE 64 +#define MC_FIELD (1*64) +#define MC_FRAME (2*64) +#define MC_16X8 (2*64) +#define MC_DMV (3*64) + +/* picture structure */ +#define TOP_FIELD 1 +#define BOTTOM_FIELD 2 +#define FRAME_PICTURE 3 + +/* picture coding type (mpeg2 header) */ +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +typedef struct { + uint8_t modes; + uint8_t len; +} MBtab; + +typedef struct { + uint8_t delta; + uint8_t len; +} MVtab; + +typedef struct { + int8_t dmv; + uint8_t len; +} DMVtab; + +typedef struct { + uint8_t cbp; + uint8_t len; +} CBPtab; + +typedef struct { + uint8_t size; + uint8_t len; +} DCtab; + +typedef struct { + uint8_t run; + uint8_t level; + uint8_t len; +} DCTtab; + +typedef struct { + uint8_t mba; + uint8_t len; +} MBAtab; + +#define INTRA MACROBLOCK_INTRA +#define QUANT MACROBLOCK_QUANT +#define MC MACROBLOCK_MOTION_FORWARD +#define CODED MACROBLOCK_PATTERN +#define FWD MACROBLOCK_MOTION_FORWARD +#define BWD MACROBLOCK_MOTION_BACKWARD +#define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD + +static const MBtab MB_I [] = { + {INTRA|QUANT, 2}, {INTRA, 1} +}; + +static const MBtab MB_P [] = { + {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5}, + {MC, 3}, {MC, 3}, {MC, 3}, {MC, 3}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1} +}; + +static const MBtab MB_B [] = { + {0, 0}, {INTRA|QUANT, 6}, + {BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6}, + {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5}, + {INTRA, 5}, {INTRA, 5}, + {FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4}, + {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2} +}; + +#undef INTRA +#undef QUANT +#undef MC +#undef CODED +#undef FWD +#undef BWD +#undef INTER + +static const MVtab MV_4 [] = { + { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} +}; + +static const MVtab MV_10 [] = { + { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, + { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10}, + {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9}, + { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, + { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, + { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7} +}; + +static const DMVtab DMV_2 [] = { + { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2} +}; + +static const CBPtab CBP_7 [] = { + {0x22, 7}, {0x12, 7}, {0x0a, 7}, {0x06, 7}, + {0x21, 7}, {0x11, 7}, {0x09, 7}, {0x05, 7}, + {0x3f, 6}, {0x3f, 6}, {0x03, 6}, {0x03, 6}, + {0x24, 6}, {0x24, 6}, {0x18, 6}, {0x18, 6}, + {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, + {0x02, 5}, {0x02, 5}, {0x02, 5}, {0x02, 5}, + {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, + {0x01, 5}, {0x01, 5}, {0x01, 5}, {0x01, 5}, + {0x38, 5}, {0x38, 5}, {0x38, 5}, {0x38, 5}, + {0x34, 5}, {0x34, 5}, {0x34, 5}, {0x34, 5}, + {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, + {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, + {0x28, 5}, {0x28, 5}, {0x28, 5}, {0x28, 5}, + {0x14, 5}, {0x14, 5}, {0x14, 5}, {0x14, 5}, + {0x30, 5}, {0x30, 5}, {0x30, 5}, {0x30, 5}, + {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3} +}; + +static const CBPtab CBP_9 [] = { + {0, 0}, {0x00, 9}, {0x27, 9}, {0x1b, 9}, + {0x3b, 9}, {0x37, 9}, {0x2f, 9}, {0x1f, 9}, + {0x3a, 8}, {0x3a, 8}, {0x36, 8}, {0x36, 8}, + {0x2e, 8}, {0x2e, 8}, {0x1e, 8}, {0x1e, 8}, + {0x39, 8}, {0x39, 8}, {0x35, 8}, {0x35, 8}, + {0x2d, 8}, {0x2d, 8}, {0x1d, 8}, {0x1d, 8}, + {0x26, 8}, {0x26, 8}, {0x1a, 8}, {0x1a, 8}, + {0x25, 8}, {0x25, 8}, {0x19, 8}, {0x19, 8}, + {0x2b, 8}, {0x2b, 8}, {0x17, 8}, {0x17, 8}, + {0x33, 8}, {0x33, 8}, {0x0f, 8}, {0x0f, 8}, + {0x2a, 8}, {0x2a, 8}, {0x16, 8}, {0x16, 8}, + {0x32, 8}, {0x32, 8}, {0x0e, 8}, {0x0e, 8}, + {0x29, 8}, {0x29, 8}, {0x15, 8}, {0x15, 8}, + {0x31, 8}, {0x31, 8}, {0x0d, 8}, {0x0d, 8}, + {0x23, 8}, {0x23, 8}, {0x13, 8}, {0x13, 8}, + {0x0b, 8}, {0x0b, 8}, {0x07, 8}, {0x07, 8} +}; + +static const DCtab DC_lum_5 [] = { + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5} +}; + +static const DCtab DC_chrom_5 [] = { + {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5} +}; + +static const DCtab DC_long [] = { + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} +}; + +static const DCTtab DCT_16 [] = { + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + { 2,18, 0}, { 2,17, 0}, { 2,16, 0}, { 2,15, 0}, + { 7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0}, + { 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0}, + { 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0} +}; + +static const DCTtab DCT_15 [] = { + { 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15}, + { 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15}, + { 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15}, + { 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15}, + { 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14}, + { 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14}, + { 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14}, + { 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14}, + { 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14}, + { 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14}, + { 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14}, + { 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14} +}; + +static const DCTtab DCT_13 [] = { + { 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13}, + { 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13}, + { 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13}, + { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13}, + { 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12}, + { 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12}, + { 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12}, + { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12}, + { 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12}, + { 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12}, + { 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12}, + { 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12} +}; + +static const DCTtab DCT_B14_10 [] = { + { 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10}, + { 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10} +}; + +static const DCTtab DCT_B14_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7}, + { 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, + { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, + { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8}, + { 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8} +}; + +static const DCTtab DCT_B14AC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2} +}; + +static const DCTtab DCT_B14DC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1} +}; + +static const DCTtab DCT_B15_10 [] = { + { 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9}, + { 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9} +}; + +static const DCTtab DCT_B15_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7}, + { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, + { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, + { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8}, + { 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7}, + { 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7}, + { 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8}, + { 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8} +}; + +static const MBAtab MBA_5 [] = { + {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1} +}; + +static const MBAtab MBA_11 [] = { + {32, 11}, {31, 11}, {30, 11}, {29, 11}, + {28, 11}, {27, 11}, {26, 11}, {25, 11}, + {24, 11}, {23, 11}, {22, 11}, {21, 11}, + {20, 10}, {20, 10}, {19, 10}, {19, 10}, + {18, 10}, {18, 10}, {17, 10}, {17, 10}, + {16, 10}, {16, 10}, {15, 10}, {15, 10}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7} +}; + +static const int non_linear_quantizer_scale[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 14, 16, 18, 20, 22, + 24, 28, 32, 36, 40, 44, 48, 52, + 56, 64, 72, 80, 88, 96, 104, 112 +}; + +static INLINE int +get_macroblock_modes(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc * picture) +{ + int macroblock_modes; + const MBtab * tab; + + switch (picture->picture_coding_type) { + case I_TYPE: + + tab = MB_I + vl_vlc_ubits(&bs->vlc, 1); + vl_vlc_dumpbits(&bs->vlc, tab->len); + macroblock_modes = tab->modes; + + return macroblock_modes; + + case P_TYPE: + + tab = MB_P + vl_vlc_ubits(&bs->vlc, 5); + vl_vlc_dumpbits(&bs->vlc, tab->len); + macroblock_modes = tab->modes; + + if (picture->picture_structure != FRAME_PICTURE) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= vl_vlc_ubits(&bs->vlc, 2) * MOTION_TYPE_BASE; + vl_vlc_dumpbits(&bs->vlc, 2); + } + return macroblock_modes; + } else if (picture->frame_pred_frame_dct) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= vl_vlc_ubits(&bs->vlc, 2) * MOTION_TYPE_BASE; + vl_vlc_dumpbits(&bs->vlc, 2); + } + return macroblock_modes; + } + + case B_TYPE: + + tab = MB_B + vl_vlc_ubits(&bs->vlc, 6); + vl_vlc_dumpbits(&bs->vlc, tab->len); + macroblock_modes = tab->modes; + + if (picture->picture_structure != FRAME_PICTURE) { + if (! (macroblock_modes & MACROBLOCK_INTRA)) { + macroblock_modes |= vl_vlc_ubits(&bs->vlc, 2) * MOTION_TYPE_BASE; + vl_vlc_dumpbits(&bs->vlc, 2); + } + } else if (picture->frame_pred_frame_dct) { + macroblock_modes |= MC_FRAME; + } else if (!(macroblock_modes & MACROBLOCK_INTRA)) { + macroblock_modes |= vl_vlc_ubits(&bs->vlc, 2) * MOTION_TYPE_BASE; + vl_vlc_dumpbits(&bs->vlc, 2); + } + return macroblock_modes; + + case D_TYPE: + + vl_vlc_dumpbits(&bs->vlc, 1); + return MACROBLOCK_INTRA; + + default: + return 0; + } +} + +static INLINE enum pipe_mpeg12_dct_type +get_dct_type(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc * picture, int macroblock_modes) +{ + enum pipe_mpeg12_dct_type dct_type = PIPE_MPEG12_DCT_TYPE_FRAME; + + if ((picture->picture_structure == FRAME_PICTURE) && + (!picture->frame_pred_frame_dct) && + (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN))) { + + dct_type = vl_vlc_ubits(&bs->vlc, 1) ? PIPE_MPEG12_DCT_TYPE_FIELD : PIPE_MPEG12_DCT_TYPE_FRAME; + vl_vlc_dumpbits(&bs->vlc, 1); + } + return dct_type; +} + +static INLINE int +get_quantizer_scale(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc * picture) +{ + int quantizer_scale_code; + + quantizer_scale_code = vl_vlc_ubits(&bs->vlc, 5); + vl_vlc_dumpbits(&bs->vlc, 5); + + if (picture->q_scale_type) + return non_linear_quantizer_scale[quantizer_scale_code]; + else + return quantizer_scale_code << 1; +} + +static INLINE int +get_motion_delta(struct vl_mpg12_bs *bs, unsigned f_code) +{ + int delta; + int sign; + const MVtab * tab; + + if (bs->vlc.buf & 0x80000000) { + vl_vlc_dumpbits(&bs->vlc, 1); + return 0; + } else if (bs->vlc.buf >= 0x0c000000) { + + tab = MV_4 + vl_vlc_ubits(&bs->vlc, 4); + delta = (tab->delta << f_code) + 1; + bs->vlc.bits += tab->len + f_code + 1; + bs->vlc.buf <<= tab->len; + + sign = vl_vlc_sbits(&bs->vlc, 1); + bs->vlc.buf <<= 1; + + if (f_code) + delta += vl_vlc_ubits(&bs->vlc, f_code); + bs->vlc.buf <<= f_code; + + return (delta ^ sign) - sign; + + } else { + + tab = MV_10 + vl_vlc_ubits(&bs->vlc, 10); + delta = (tab->delta << f_code) + 1; + bs->vlc.bits += tab->len + 1; + bs->vlc.buf <<= tab->len; + + sign = vl_vlc_sbits(&bs->vlc, 1); + bs->vlc.buf <<= 1; + + if (f_code) { + vl_vlc_needbits(&bs->vlc); + delta += vl_vlc_ubits(&bs->vlc, f_code); + vl_vlc_dumpbits(&bs->vlc, f_code); + } + + return (delta ^ sign) - sign; + } +} + +static INLINE int +bound_motion_vector(int vec, unsigned f_code) +{ +#if 1 + unsigned int limit; + int sign; + + limit = 16 << f_code; + + if ((unsigned int)(vec + limit) < 2 * limit) + return vec; + else { + sign = ((int32_t)vec) >> 31; + return vec - ((2 * limit) ^ sign) + sign; + } +#else + return ((int32_t)vec << (28 - f_code)) >> (28 - f_code); +#endif +} + +static INLINE int +get_dmv(struct vl_mpg12_bs *bs) +{ + const DMVtab * tab; + + tab = DMV_2 + vl_vlc_ubits(&bs->vlc, 2); + vl_vlc_dumpbits(&bs->vlc, tab->len); + return tab->dmv; +} + +static INLINE int +get_coded_block_pattern(struct vl_mpg12_bs *bs) +{ + const CBPtab * tab; + + vl_vlc_needbits(&bs->vlc); + + if (bs->vlc.buf >= 0x20000000) { + + tab = CBP_7 + (vl_vlc_ubits(&bs->vlc, 7) - 16); + vl_vlc_dumpbits(&bs->vlc, tab->len); + return tab->cbp; + + } else { + + tab = CBP_9 + vl_vlc_ubits(&bs->vlc, 9); + vl_vlc_dumpbits(&bs->vlc, tab->len); + return tab->cbp; + } +} + +static INLINE int +get_luma_dc_dct_diff(struct vl_mpg12_bs *bs) +{ + const DCtab * tab; + int size; + int dc_diff; + + if (bs->vlc.buf < 0xf8000000) { + tab = DC_lum_5 + vl_vlc_ubits(&bs->vlc, 5); + size = tab->size; + if (size) { + bs->vlc.bits += tab->len + size; + bs->vlc.buf <<= tab->len; + dc_diff = vl_vlc_ubits(&bs->vlc, size) - UBITS (SBITS (~bs->vlc.buf, 1), size); + bs->vlc.buf <<= size; + return dc_diff; + } else { + vl_vlc_dumpbits(&bs->vlc, 3); + return 0; + } + } else { + tab = DC_long + (vl_vlc_ubits(&bs->vlc, 9) - 0x1e0); + size = tab->size; + vl_vlc_dumpbits(&bs->vlc, tab->len); + vl_vlc_needbits(&bs->vlc); + dc_diff = vl_vlc_ubits(&bs->vlc, size) - UBITS (SBITS (~bs->vlc.buf, 1), size); + vl_vlc_dumpbits(&bs->vlc, size); + return dc_diff; + } +} + +static INLINE int +get_chroma_dc_dct_diff(struct vl_mpg12_bs *bs) +{ + const DCtab * tab; + int size; + int dc_diff; + + if (bs->vlc.buf < 0xf8000000) { + tab = DC_chrom_5 + vl_vlc_ubits(&bs->vlc, 5); + size = tab->size; + if (size) { + bs->vlc.bits += tab->len + size; + bs->vlc.buf <<= tab->len; + dc_diff = vl_vlc_ubits(&bs->vlc, size) - UBITS (SBITS (~bs->vlc.buf, 1), size); + bs->vlc.buf <<= size; + return dc_diff; + } else { + vl_vlc_dumpbits(&bs->vlc, 2); + return 0; + } + } else { + tab = DC_long + (vl_vlc_ubits(&bs->vlc, 10) - 0x3e0); + size = tab->size; + vl_vlc_dumpbits(&bs->vlc, tab->len + 1); + vl_vlc_needbits(&bs->vlc); + dc_diff = vl_vlc_ubits(&bs->vlc, size) - UBITS (SBITS (~bs->vlc.buf, 1), size); + vl_vlc_dumpbits(&bs->vlc, size); + return dc_diff; + } +} + +static INLINE void +get_intra_block_B14(struct vl_mpg12_bs *bs, int quantizer_scale, short *dest) +{ + int i, val; + const DCTtab *tab; + + i = 0; + + vl_vlc_needbits(&bs->vlc); + + while (1) { + if (bs->vlc.buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (vl_vlc_ubits(&bs->vlc, 5) - 5); + + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + bs->vlc.buf <<= tab->len; + bs->vlc.bits += tab->len + 1; + val = tab->level * quantizer_scale; + + val = (val ^ vl_vlc_sbits(&bs->vlc, 1)) - vl_vlc_sbits(&bs->vlc, 1); + + dest[i] = val; + + bs->vlc.buf <<= 1; + vl_vlc_needbits(&bs->vlc); + + continue; + + } else if (bs->vlc.buf >= 0x04000000) { + + tab = DCT_B14_8 + (vl_vlc_ubits(&bs->vlc, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS(bs->vlc.buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + val = vl_vlc_sbits(&bs->vlc, 12) * quantizer_scale; + + dest[i] = val; + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + + continue; + + } else if (bs->vlc.buf >= 0x02000000) { + tab = DCT_B14_10 + (vl_vlc_ubits(&bs->vlc, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00800000) { + tab = DCT_13 + (vl_vlc_ubits(&bs->vlc, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00200000) { + tab = DCT_15 + (vl_vlc_ubits(&bs->vlc, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + vl_vlc_ubits(&bs->vlc, 16); + bs->vlc.buf <<= 16; + vl_vlc_getword(&bs->vlc, bs->vlc.bits + 16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + + vl_vlc_dumpbits(&bs->vlc, 2); /* dump end of block code */ +} + +static INLINE void +get_intra_block_B15(struct vl_mpg12_bs *bs, int quantizer_scale, short *dest) +{ + int i, val; + const DCTtab * tab; + + i = 0; + + vl_vlc_needbits(&bs->vlc); + + while (1) { + if (bs->vlc.buf >= 0x04000000) { + + tab = DCT_B15_8 + (vl_vlc_ubits(&bs->vlc, 8) - 4); + + i += tab->run; + if (i < 64) { + + normal_code: + bs->vlc.buf <<= tab->len; + bs->vlc.bits += tab->len + 1; + val = tab->level * quantizer_scale; + + val = (val ^ vl_vlc_sbits(&bs->vlc, 1)) - vl_vlc_sbits(&bs->vlc, 1); + + dest[i] = val; + + bs->vlc.buf <<= 1; + vl_vlc_needbits(&bs->vlc); + + continue; + + } else { + + /* end of block. I commented out this code because if we */ + /* dont exit here we will still exit at the later test :) */ + + /* if (i >= 128) break; */ /* end of block */ + + /* escape code */ + + i += UBITS(bs->vlc.buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check against buffer overflow */ + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + val = vl_vlc_sbits(&bs->vlc, 12) * quantizer_scale; + + dest[i] = val; + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + + continue; + + } + } else if (bs->vlc.buf >= 0x02000000) { + tab = DCT_B15_10 + (vl_vlc_ubits(&bs->vlc, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00800000) { + tab = DCT_13 + (vl_vlc_ubits(&bs->vlc, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00200000) { + tab = DCT_15 + (vl_vlc_ubits(&bs->vlc, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + vl_vlc_ubits(&bs->vlc, 16); + bs->vlc.buf <<= 16; + vl_vlc_getword(&bs->vlc, bs->vlc.bits + 16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + + vl_vlc_dumpbits(&bs->vlc, 4); /* dump end of block code */ +} + +static INLINE void +get_non_intra_block(struct vl_mpg12_bs *bs, int quantizer_scale, short *dest) +{ + int i, val; + const DCTtab *tab; + + i = -1; + + vl_vlc_needbits(&bs->vlc); + if (bs->vlc.buf >= 0x28000000) { + tab = DCT_B14DC_5 + (vl_vlc_ubits(&bs->vlc, 5) - 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bs->vlc.buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (vl_vlc_ubits(&bs->vlc, 5) - 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + bs->vlc.buf <<= tab->len; + bs->vlc.bits += tab->len + 1; + val = ((2*tab->level+1) * quantizer_scale) >> 1; + + val = (val ^ vl_vlc_sbits(&bs->vlc, 1)) - vl_vlc_sbits(&bs->vlc, 1); + + dest[i] = val; + + bs->vlc.buf <<= 1; + vl_vlc_needbits(&bs->vlc); + + continue; + + } + + entry_2: + if (bs->vlc.buf >= 0x04000000) { + + tab = DCT_B14_8 + (vl_vlc_ubits(&bs->vlc, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS(bs->vlc.buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + val = 2 * (vl_vlc_sbits(&bs->vlc, 12) + vl_vlc_sbits(&bs->vlc, 1)) + 1; + val = (val * quantizer_scale) / 2; + + dest[i] = val; + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + + continue; + + } else if (bs->vlc.buf >= 0x02000000) { + tab = DCT_B14_10 + (vl_vlc_ubits(&bs->vlc, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00800000) { + tab = DCT_13 + (vl_vlc_ubits(&bs->vlc, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00200000) { + tab = DCT_15 + (vl_vlc_ubits(&bs->vlc, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + vl_vlc_ubits(&bs->vlc, 16); + bs->vlc.buf <<= 16; + vl_vlc_getword(&bs->vlc, bs->vlc.bits + 16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + vl_vlc_dumpbits(&bs->vlc, 2); /* dump end of block code */ +} + +static INLINE void +get_mpeg1_intra_block(struct vl_mpg12_bs *bs, int quantizer_scale, short *dest) +{ + int i, val; + const DCTtab * tab; + + i = 0; + + vl_vlc_needbits(&bs->vlc); + + while (1) { + if (bs->vlc.buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (vl_vlc_ubits(&bs->vlc, 5) - 5); + + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + bs->vlc.buf <<= tab->len; + bs->vlc.bits += tab->len + 1; + val = tab->level * quantizer_scale; + + /* oddification */ + val = (val - 1) | 1; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ vl_vlc_sbits(&bs->vlc, 1)) - vl_vlc_sbits(&bs->vlc, 1); + + dest[i] = val; + + bs->vlc.buf <<= 1; + vl_vlc_needbits(&bs->vlc); + + continue; + + } else if (bs->vlc.buf >= 0x04000000) { + + tab = DCT_B14_8 + (vl_vlc_ubits(&bs->vlc, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS(bs->vlc.buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + val = vl_vlc_sbits(&bs->vlc, 8); + if (! (val & 0x7f)) { + vl_vlc_dumpbits(&bs->vlc, 8); + val = vl_vlc_ubits(&bs->vlc, 8) + 2 * val; + } + val = val * quantizer_scale; + + /* oddification */ + val = (val + ~SBITS (val, 1)) | 1; + + dest[i] = val; + + vl_vlc_dumpbits(&bs->vlc, 8); + vl_vlc_needbits(&bs->vlc); + + continue; + + } else if (bs->vlc.buf >= 0x02000000) { + tab = DCT_B14_10 + (vl_vlc_ubits(&bs->vlc, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00800000) { + tab = DCT_13 + (vl_vlc_ubits(&bs->vlc, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00200000) { + tab = DCT_15 + (vl_vlc_ubits(&bs->vlc, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + vl_vlc_ubits(&bs->vlc, 16); + bs->vlc.buf <<= 16; + vl_vlc_getword(&bs->vlc, bs->vlc.bits + 16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + vl_vlc_dumpbits(&bs->vlc, 2); /* dump end of block code */ +} + +static INLINE void +get_mpeg1_non_intra_block(struct vl_mpg12_bs *bs, int quantizer_scale, short *dest) +{ + int i, val; + const DCTtab * tab; + + i = -1; + + vl_vlc_needbits(&bs->vlc); + if (bs->vlc.buf >= 0x28000000) { + tab = DCT_B14DC_5 + (vl_vlc_ubits(&bs->vlc, 5) - 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bs->vlc.buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (vl_vlc_ubits(&bs->vlc, 5) - 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + bs->vlc.buf <<= tab->len; + bs->vlc.bits += tab->len + 1; + val = ((2*tab->level+1) * quantizer_scale) >> 1; + + /* oddification */ + val = (val - 1) | 1; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ vl_vlc_sbits(&bs->vlc, 1)) - vl_vlc_sbits(&bs->vlc, 1); + + dest[i] = val; + + bs->vlc.buf <<= 1; + vl_vlc_needbits(&bs->vlc); + + continue; + + } + + entry_2: + if (bs->vlc.buf >= 0x04000000) { + + tab = DCT_B14_8 + (vl_vlc_ubits(&bs->vlc, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS(bs->vlc.buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + vl_vlc_dumpbits(&bs->vlc, 12); + vl_vlc_needbits(&bs->vlc); + val = vl_vlc_sbits(&bs->vlc, 8); + if (! (val & 0x7f)) { + vl_vlc_dumpbits(&bs->vlc, 8); + val = vl_vlc_ubits(&bs->vlc, 8) + 2 * val; + } + val = 2 * (val + SBITS (val, 1)) + 1; + val = (val * quantizer_scale) / 2; + + /* oddification */ + val = (val + ~SBITS (val, 1)) | 1; + + dest[i] = val; + + vl_vlc_dumpbits(&bs->vlc, 8); + vl_vlc_needbits(&bs->vlc); + + continue; + + } else if (bs->vlc.buf >= 0x02000000) { + tab = DCT_B14_10 + (vl_vlc_ubits(&bs->vlc, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00800000) { + tab = DCT_13 + (vl_vlc_ubits(&bs->vlc, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bs->vlc.buf >= 0x00200000) { + tab = DCT_15 + (vl_vlc_ubits(&bs->vlc, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + vl_vlc_ubits(&bs->vlc, 16); + bs->vlc.buf <<= 16; + vl_vlc_getword(&bs->vlc, bs->vlc.bits + 16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + vl_vlc_dumpbits(&bs->vlc, 2); /* dump end of block code */ +} + +static INLINE void +slice_intra_DCT(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc * picture, int cc, + unsigned x, unsigned y, enum pipe_mpeg12_dct_type coding, int quantizer_scale, int dc_dct_pred[3]) +{ + short dest[64]; + + bs->ycbcr_stream[cc]->x = x; + bs->ycbcr_stream[cc]->y = y; + bs->ycbcr_stream[cc]->intra = PIPE_MPEG12_DCT_INTRA; + bs->ycbcr_stream[cc]->coding = coding; + + vl_vlc_needbits(&bs->vlc); + + /* Get the intra DC coefficient and inverse quantize it */ + if (cc == 0) + dc_dct_pred[0] += get_luma_dc_dct_diff(bs); + else + dc_dct_pred[cc] += get_chroma_dc_dct_diff(bs); + + memset(dest, 0, sizeof(int16_t) * 64); + dest[0] = dc_dct_pred[cc]; + if (picture->base.profile == PIPE_VIDEO_PROFILE_MPEG1) { + if (picture->picture_coding_type != D_TYPE) + get_mpeg1_intra_block(bs, quantizer_scale, dest); + } else if (picture->intra_vlc_format) + get_intra_block_B15(bs, quantizer_scale, dest); + else + get_intra_block_B14(bs, quantizer_scale, dest); + + memcpy(bs->ycbcr_buffer[cc], dest, sizeof(int16_t) * 64); + + bs->num_ycbcr_blocks[cc]++; + bs->ycbcr_stream[cc]++; + bs->ycbcr_buffer[cc] += 64; +} + +static INLINE void +slice_non_intra_DCT(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc * picture, int cc, + unsigned x, unsigned y, enum pipe_mpeg12_dct_type coding, int quantizer_scale) +{ + short dest[64]; + + bs->ycbcr_stream[cc]->x = x; + bs->ycbcr_stream[cc]->y = y; + bs->ycbcr_stream[cc]->intra = PIPE_MPEG12_DCT_DELTA; + bs->ycbcr_stream[cc]->coding = coding; + + memset(dest, 0, sizeof(int16_t) * 64); + if (picture->base.profile == PIPE_VIDEO_PROFILE_MPEG1) + get_mpeg1_non_intra_block(bs, quantizer_scale, dest); + else + get_non_intra_block(bs, quantizer_scale, dest); + + memcpy(bs->ycbcr_buffer[cc], dest, sizeof(int16_t) * 64); + + bs->num_ycbcr_blocks[cc]++; + bs->ycbcr_stream[cc]++; + bs->ycbcr_buffer[cc] += 64; +} + +static INLINE void +motion_mp1(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + mv->top.field_select = mv->bottom.field_select = PIPE_VIDEO_FRAME; + + vl_vlc_needbits(&bs->vlc); + motion_x = (mv->top.x + (get_motion_delta(bs, f_code[0]) << f_code[1])); + motion_x = bound_motion_vector (motion_x, f_code[0] + f_code[1]); + mv->top.x = mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = (mv->top.y + (get_motion_delta(bs, f_code[0]) << f_code[1])); + motion_y = bound_motion_vector (motion_y, f_code[0] + f_code[1]); + mv->top.y = mv->bottom.y = motion_y; +} + +static INLINE void +motion_fr_frame(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + mv->top.field_select = mv->bottom.field_select = PIPE_VIDEO_FRAME; + + vl_vlc_needbits(&bs->vlc); + motion_x = mv->top.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector(motion_x, f_code[0]); + mv->top.x = mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = mv->top.y + get_motion_delta(bs, f_code[1]); + motion_y = bound_motion_vector(motion_y, f_code[1]); + mv->top.y = mv->bottom.y = motion_y; +} + +static INLINE void +motion_fr_field(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + vl_vlc_needbits(&bs->vlc); + mv->top.field_select = vl_vlc_ubits(&bs->vlc, 1) ? + PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD; + vl_vlc_dumpbits(&bs->vlc, 1); + + motion_x = mv->top.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector (motion_x, f_code[0]); + mv->top.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = (mv->top.y >> 1) + get_motion_delta(bs, f_code[1]); + /* motion_y = bound_motion_vector (motion_y, f_code[1]); */ + mv->top.y = motion_y << 1; + + vl_vlc_needbits(&bs->vlc); + mv->bottom.field_select = vl_vlc_ubits(&bs->vlc, 1) ? + PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD; + vl_vlc_dumpbits(&bs->vlc, 1); + + motion_x = mv->bottom.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector (motion_x, f_code[0]); + mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = (mv->bottom.y >> 1) + get_motion_delta(bs, f_code[1]); + /* motion_y = bound_motion_vector (motion_y, f_code[1]); */ + mv->bottom.y = motion_y << 1; +} + +static INLINE void +motion_fr_dmv(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + // TODO Implement dmv + mv->top.field_select = mv->bottom.field_select = PIPE_VIDEO_FRAME; + + vl_vlc_needbits(&bs->vlc); + motion_x = mv->top.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector(motion_x, f_code[0]); + mv->top.x = mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = (mv->top.y >> 1) + get_motion_delta(bs, f_code[1]); + /* motion_y = bound_motion_vector (motion_y, f_code[1]); */ + mv->top.y = mv->bottom.y = motion_y << 1; +} + +/* like motion_frame, but parsing without actual motion compensation */ +static INLINE void +motion_fr_conceal(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int tmp; + + mv->top.field_select = mv->bottom.field_select = PIPE_VIDEO_FRAME; + + vl_vlc_needbits(&bs->vlc); + tmp = (mv->top.x + get_motion_delta(bs, f_code[0])); + tmp = bound_motion_vector (tmp, f_code[0]); + mv->top.x = mv->bottom.x = tmp; + + vl_vlc_needbits(&bs->vlc); + tmp = (mv->top.y + get_motion_delta(bs, f_code[1])); + tmp = bound_motion_vector (tmp, f_code[1]); + mv->top.y = mv->bottom.y = tmp; + + vl_vlc_dumpbits(&bs->vlc, 1); /* remove marker_bit */ +} + +static INLINE void +motion_fi_field(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + vl_vlc_needbits(&bs->vlc); + + // ref_field + //vl_vlc_ubits(&bs->vlc, 1); + + // TODO field select may need to do something here for bob (weave ok) + mv->top.field_select = mv->bottom.field_select = PIPE_VIDEO_FRAME; + vl_vlc_dumpbits(&bs->vlc, 1); + + motion_x = mv->top.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector (motion_x, f_code[0]); + mv->top.x = mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = mv->top.y + get_motion_delta(bs, f_code[1]); + motion_y = bound_motion_vector (motion_y, f_code[1]); + mv->top.y = mv->bottom.y = motion_y; +} + +static INLINE void +motion_fi_16x8(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + vl_vlc_needbits(&bs->vlc); + + // ref_field + //vl_vlc_ubits(&bs->vlc, 1); + + // TODO field select may need to do something here bob (weave ok) + mv->top.field_select = PIPE_VIDEO_FRAME; + vl_vlc_dumpbits(&bs->vlc, 1); + + motion_x = mv->top.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector (motion_x, f_code[0]); + mv->top.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = mv->top.y + get_motion_delta(bs, f_code[1]); + motion_y = bound_motion_vector (motion_y, f_code[1]); + mv->top.y = motion_y; + + vl_vlc_needbits(&bs->vlc); + // ref_field + //vl_vlc_ubits(&bs->vlc, 1); + + // TODO field select may need to do something here for bob (weave ok) + mv->bottom.field_select = PIPE_VIDEO_FRAME; + vl_vlc_dumpbits(&bs->vlc, 1); + + motion_x = mv->bottom.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector (motion_x, f_code[0]); + mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = mv->bottom.y + get_motion_delta(bs, f_code[1]); + motion_y = bound_motion_vector (motion_y, f_code[1]); + mv->bottom.y = motion_y; +} + +static INLINE void +motion_fi_dmv(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int motion_x, motion_y; + + // TODO field select may need to do something here for bob (weave ok) + mv->top.field_select = mv->bottom.field_select = PIPE_VIDEO_FRAME; + + vl_vlc_needbits(&bs->vlc); + motion_x = mv->top.x + get_motion_delta(bs, f_code[0]); + motion_x = bound_motion_vector (motion_x, f_code[0]); + mv->top.x = mv->bottom.x = motion_x; + + vl_vlc_needbits(&bs->vlc); + motion_y = mv->top.y + get_motion_delta(bs, f_code[1]); + motion_y = bound_motion_vector (motion_y, f_code[1]); + mv->top.y = mv->bottom.y = motion_y; +} + + +static INLINE void +motion_fi_conceal(struct vl_mpg12_bs *bs, unsigned f_code[2], struct pipe_motionvector *mv) +{ + int tmp; + + vl_vlc_needbits(&bs->vlc); + vl_vlc_dumpbits(&bs->vlc, 1); /* remove field_select */ + + tmp = (mv->top.x + get_motion_delta(bs, f_code[0])); + tmp = bound_motion_vector(tmp, f_code[0]); + mv->top.x = mv->bottom.x = tmp; + + vl_vlc_needbits(&bs->vlc); + tmp = (mv->top.y + get_motion_delta(bs, f_code[1])); + tmp = bound_motion_vector(tmp, f_code[1]); + mv->top.y = mv->bottom.y = tmp; + + vl_vlc_dumpbits(&bs->vlc, 1); /* remove marker_bit */ +} + +#define MOTION_CALL(routine, macroblock_modes) \ +do { \ + if ((macroblock_modes) & MACROBLOCK_MOTION_FORWARD) \ + routine(bs, picture->f_code[0], &mv_fwd); \ + if ((macroblock_modes) & MACROBLOCK_MOTION_BACKWARD) \ + routine(bs, picture->f_code[1], &mv_bwd); \ +} while (0) + +static INLINE void +store_motionvectors(struct vl_mpg12_bs *bs, unsigned *mv_pos, + struct pipe_motionvector *mv_fwd, + struct pipe_motionvector *mv_bwd) +{ + bs->mv_stream[0][*mv_pos].top = mv_fwd->top; + bs->mv_stream[0][*mv_pos].bottom = + mv_fwd->top.field_select == PIPE_VIDEO_FRAME ? + mv_fwd->top : mv_fwd->bottom; + + bs->mv_stream[1][*mv_pos].top = mv_bwd->top; + bs->mv_stream[1][*mv_pos].bottom = + mv_bwd->top.field_select == PIPE_VIDEO_FRAME ? + mv_bwd->top : mv_bwd->bottom; + + (*mv_pos)++; +} + +static INLINE bool +slice_init(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc * picture, + int *quantizer_scale, unsigned *x, unsigned *y, unsigned *mv_pos) +{ + const MBAtab * mba; + + vl_vlc_need32bits(&bs->vlc); + while(bs->vlc.buf < 0x101 || bs->vlc.buf > 0x1AF) { + if(!vl_vlc_getbyte(&bs->vlc)) + return false; + } + *y = (bs->vlc.buf & 0xFF) - 1; + vl_vlc_restart(&bs->vlc); + + *quantizer_scale = get_quantizer_scale(bs, picture); + + /* ignore intra_slice and all the extra data */ + while (bs->vlc.buf & 0x80000000) { + vl_vlc_dumpbits(&bs->vlc, 9); + vl_vlc_needbits(&bs->vlc); + } + + /* decode initial macroblock address increment */ + *x = 0; + while (1) { + if (bs->vlc.buf >= 0x08000000) { + mba = MBA_5 + (vl_vlc_ubits(&bs->vlc, 6) - 2); + break; + } else if (bs->vlc.buf >= 0x01800000) { + mba = MBA_11 + (vl_vlc_ubits(&bs->vlc, 12) - 24); + break; + } else switch (vl_vlc_ubits(&bs->vlc, 12)) { + case 8: /* macroblock_escape */ + *x += 33; + vl_vlc_dumpbits(&bs->vlc, 11); + vl_vlc_needbits(&bs->vlc); + continue; + case 15: /* macroblock_stuffing (MPEG1 only) */ + bs->vlc.buf &= 0xfffff; + vl_vlc_dumpbits(&bs->vlc, 11); + vl_vlc_needbits(&bs->vlc); + continue; + default: /* error */ + return false; + } + } + vl_vlc_dumpbits(&bs->vlc, mba->len + 1); + *x += mba->mba; + + while (*x >= bs->width) { + *x -= bs->width; + (*y)++; + } + if (*y > bs->height) + return false; + + *mv_pos = *x + *y * bs->width; + + return true; +} + +static INLINE bool +decode_slice(struct vl_mpg12_bs *bs, struct pipe_mpeg12_picture_desc *picture) +{ + enum pipe_video_field_select default_field_select; + struct pipe_motionvector mv_fwd, mv_bwd; + enum pipe_mpeg12_dct_type dct_type; + + /* predictor for DC coefficients in intra blocks */ + int dc_dct_pred[3] = { 0, 0, 0 }; + int quantizer_scale; + + unsigned x, y, mv_pos; + + switch(picture->picture_structure) { + case TOP_FIELD: + default_field_select = PIPE_VIDEO_TOP_FIELD; + break; + + case BOTTOM_FIELD: + default_field_select = PIPE_VIDEO_BOTTOM_FIELD; + break; + + default: + default_field_select = PIPE_VIDEO_FRAME; + break; + } + + if (!slice_init(bs, picture, &quantizer_scale, &x, &y, &mv_pos)) + return false; + + mv_fwd.top.x = mv_fwd.top.y = mv_fwd.bottom.x = mv_fwd.bottom.y = 0; + mv_fwd.top.field_select = mv_fwd.bottom.field_select = default_field_select; + + mv_bwd.top.x = mv_bwd.top.y = mv_bwd.bottom.x = mv_bwd.bottom.y = 0; + mv_bwd.top.field_select = mv_bwd.bottom.field_select = default_field_select; + + while (1) { + int macroblock_modes; + int mba_inc; + const MBAtab * mba; + + vl_vlc_needbits(&bs->vlc); + + macroblock_modes = get_macroblock_modes(bs, picture); + dct_type = get_dct_type(bs, picture, macroblock_modes); + + switch(macroblock_modes & (MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD)) { + case (MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD): + mv_fwd.top.weight = mv_fwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_HALF; + mv_bwd.top.weight = mv_bwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_HALF; + break; + + default: + mv_fwd.top.field_select = mv_fwd.bottom.field_select = default_field_select; + mv_bwd.top.field_select = mv_bwd.bottom.field_select = default_field_select; + + /* fall through */ + case MACROBLOCK_MOTION_FORWARD: + mv_fwd.top.weight = mv_fwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MAX; + mv_bwd.top.weight = mv_bwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MIN; + break; + + case MACROBLOCK_MOTION_BACKWARD: + mv_fwd.top.weight = mv_fwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MIN; + mv_bwd.top.weight = mv_bwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MAX; + break; + } + + /* maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? */ + if (macroblock_modes & MACROBLOCK_QUANT) + quantizer_scale = get_quantizer_scale(bs, picture); + + if (macroblock_modes & MACROBLOCK_INTRA) { + + if (picture->concealment_motion_vectors) { + if (picture->picture_structure == FRAME_PICTURE) + motion_fr_conceal(bs, picture->f_code[0], &mv_fwd); + else + motion_fi_conceal(bs, picture->f_code[0], &mv_fwd); + + } else { + mv_fwd.top.x = mv_fwd.top.y = mv_fwd.bottom.x = mv_fwd.bottom.y = 0; + mv_bwd.top.x = mv_bwd.top.y = mv_bwd.bottom.x = mv_bwd.bottom.y = 0; + } + mv_fwd.top.weight = mv_fwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MIN; + mv_bwd.top.weight = mv_bwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MIN; + + // unravaled loop of 6 block(i) calls in macroblock() + slice_intra_DCT(bs, picture, 0, x*2+0, y*2+0, dct_type, quantizer_scale, dc_dct_pred); + slice_intra_DCT(bs, picture, 0, x*2+1, y*2+0, dct_type, quantizer_scale, dc_dct_pred); + slice_intra_DCT(bs, picture, 0, x*2+0, y*2+1, dct_type, quantizer_scale, dc_dct_pred); + slice_intra_DCT(bs, picture, 0, x*2+1, y*2+1, dct_type, quantizer_scale, dc_dct_pred); + slice_intra_DCT(bs, picture, 1, x, y, PIPE_MPEG12_DCT_TYPE_FRAME, quantizer_scale, dc_dct_pred); + slice_intra_DCT(bs, picture, 2, x, y, PIPE_MPEG12_DCT_TYPE_FRAME, quantizer_scale, dc_dct_pred); + + if (picture->picture_coding_type == D_TYPE) { + vl_vlc_needbits(&bs->vlc); + vl_vlc_dumpbits(&bs->vlc, 1); + } + + } else { + if (picture->picture_structure == FRAME_PICTURE) + switch (macroblock_modes & MOTION_TYPE_MASK) { + case MC_FRAME: + if (picture->base.profile == PIPE_VIDEO_PROFILE_MPEG1) { + MOTION_CALL(motion_mp1, macroblock_modes); + } else { + MOTION_CALL(motion_fr_frame, macroblock_modes); + } + break; + + case MC_FIELD: + MOTION_CALL (motion_fr_field, macroblock_modes); + break; + + case MC_DMV: + MOTION_CALL (motion_fr_dmv, MACROBLOCK_MOTION_FORWARD); + break; + + case 0: + /* non-intra mb without forward mv in a P picture */ + mv_fwd.top.x = mv_fwd.top.y = mv_fwd.bottom.x = mv_fwd.bottom.y = 0; + mv_bwd.top.x = mv_bwd.top.y = mv_bwd.bottom.x = mv_bwd.bottom.y = 0; + break; + } + else + switch (macroblock_modes & MOTION_TYPE_MASK) { + case MC_FIELD: + MOTION_CALL (motion_fi_field, macroblock_modes); + break; + + case MC_16X8: + MOTION_CALL (motion_fi_16x8, macroblock_modes); + break; + + case MC_DMV: + MOTION_CALL (motion_fi_dmv, MACROBLOCK_MOTION_FORWARD); + break; + + case 0: + /* non-intra mb without forward mv in a P picture */ + mv_fwd.top.x = mv_fwd.top.y = mv_fwd.bottom.x = mv_fwd.bottom.y = 0; + mv_bwd.top.x = mv_bwd.top.y = mv_bwd.bottom.x = mv_bwd.bottom.y = 0; + break; + } + + if (macroblock_modes & MACROBLOCK_PATTERN) { + int coded_block_pattern = get_coded_block_pattern(bs); + + // TODO optimize not fully used for idct accel only mc. + if (coded_block_pattern & 0x20) + slice_non_intra_DCT(bs, picture, 0, x*2+0, y*2+0, dct_type, quantizer_scale); // cc0 luma 0 + if (coded_block_pattern & 0x10) + slice_non_intra_DCT(bs, picture, 0, x*2+1, y*2+0, dct_type, quantizer_scale); // cc0 luma 1 + if (coded_block_pattern & 0x08) + slice_non_intra_DCT(bs, picture, 0, x*2+0, y*2+1, dct_type, quantizer_scale); // cc0 luma 2 + if (coded_block_pattern & 0x04) + slice_non_intra_DCT(bs, picture, 0, x*2+1, y*2+1, dct_type, quantizer_scale); // cc0 luma 3 + if (coded_block_pattern & 0x2) + slice_non_intra_DCT(bs, picture, 1, x, y, PIPE_MPEG12_DCT_TYPE_FRAME, quantizer_scale); // cc1 croma + if (coded_block_pattern & 0x1) + slice_non_intra_DCT(bs, picture, 2, x, y, PIPE_MPEG12_DCT_TYPE_FRAME, quantizer_scale); // cc2 croma + } + + dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0; + } + + store_motionvectors(bs, &mv_pos, &mv_fwd, &mv_bwd); + if (++x >= bs->width) { + ++y; + if (y >= bs->height) + return false; + x -= bs->width; + } + + vl_vlc_needbits(&bs->vlc); + mba_inc = 0; + while (1) { + if (bs->vlc.buf >= 0x10000000) { + mba = MBA_5 + (vl_vlc_ubits(&bs->vlc, 5) - 2); + break; + } else if (bs->vlc.buf >= 0x03000000) { + mba = MBA_11 + (vl_vlc_ubits(&bs->vlc, 11) - 24); + break; + } else switch (vl_vlc_ubits(&bs->vlc, 11)) { + case 8: /* macroblock_escape */ + mba_inc += 33; + /* pass through */ + case 15: /* macroblock_stuffing (MPEG1 only) */ + vl_vlc_dumpbits(&bs->vlc, 11); + vl_vlc_needbits(&bs->vlc); + continue; + default: /* end of slice, or error */ + return true; + } + } + vl_vlc_dumpbits(&bs->vlc, mba->len); + mba_inc += mba->mba; + if (mba_inc) { + //TODO conversion to signed format signed format + dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0; + + mv_fwd.top.field_select = mv_fwd.bottom.field_select = default_field_select; + mv_bwd.top.field_select = mv_bwd.bottom.field_select = default_field_select; + + if (picture->picture_coding_type == P_TYPE) { + mv_fwd.top.x = mv_fwd.top.y = mv_fwd.bottom.x = mv_fwd.bottom.y = 0; + mv_fwd.top.weight = mv_fwd.bottom.weight = PIPE_VIDEO_MV_WEIGHT_MAX; + } + + x += mba_inc; + do { + store_motionvectors(bs, &mv_pos, &mv_fwd, &mv_bwd); + } while (--mba_inc); + } + while (x >= bs->width) { + ++y; + if (y >= bs->height) + return false; + x -= bs->width; + } + } +} + +void +vl_mpg12_bs_init(struct vl_mpg12_bs *bs, unsigned width, unsigned height) +{ + assert(bs); + + memset(bs, 0, sizeof(struct vl_mpg12_bs)); + + bs->width = width; + bs->height = height; +} + +void +vl_mpg12_bs_set_buffers(struct vl_mpg12_bs *bs, struct pipe_ycbcr_block *ycbcr_stream[VL_MAX_PLANES], + short *ycbcr_buffer[VL_MAX_PLANES], struct pipe_motionvector *mv_stream[VL_MAX_REF_FRAMES]) +{ + unsigned i; + + assert(bs); + assert(ycbcr_stream && ycbcr_buffer); + assert(mv_stream); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + bs->ycbcr_stream[i] = ycbcr_stream[i]; + bs->ycbcr_buffer[i] = ycbcr_buffer[i]; + } + for (i = 0; i < VL_MAX_REF_FRAMES; ++i) + bs->mv_stream[i] = mv_stream[i]; + + // TODO + for (i = 0; i < bs->width*bs->height; ++i) { + bs->mv_stream[0][i].top.x = bs->mv_stream[0][i].top.y = 0; + bs->mv_stream[0][i].top.field_select = PIPE_VIDEO_FRAME; + bs->mv_stream[0][i].top.weight = PIPE_VIDEO_MV_WEIGHT_MAX; + bs->mv_stream[0][i].bottom.x = bs->mv_stream[0][i].bottom.y = 0; + bs->mv_stream[0][i].bottom.field_select = PIPE_VIDEO_FRAME; + bs->mv_stream[0][i].bottom.weight = PIPE_VIDEO_MV_WEIGHT_MAX; + + bs->mv_stream[1][i].top.x = bs->mv_stream[1][i].top.y = 0; + bs->mv_stream[1][i].top.field_select = PIPE_VIDEO_FRAME; + bs->mv_stream[1][i].top.weight = PIPE_VIDEO_MV_WEIGHT_MIN; + bs->mv_stream[1][i].bottom.x = bs->mv_stream[1][i].bottom.y = 0; + bs->mv_stream[1][i].bottom.field_select = PIPE_VIDEO_FRAME; + bs->mv_stream[1][i].bottom.weight = PIPE_VIDEO_MV_WEIGHT_MIN; + } +} + +void +vl_mpg12_bs_decode(struct vl_mpg12_bs *bs, unsigned num_bytes, const void *buffer, + struct pipe_mpeg12_picture_desc *picture, unsigned num_ycbcr_blocks[3]) +{ + assert(bs); + assert(num_ycbcr_blocks); + assert(buffer && num_bytes); + + bs->num_ycbcr_blocks = num_ycbcr_blocks; + + vl_vlc_init(&bs->vlc, buffer, num_bytes); + + while(decode_slice(bs, picture)); +} diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.h b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.h new file mode 100644 index 00000000000..4e48a9faa2f --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.h @@ -0,0 +1,59 @@ +/************************************************************************** + * + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_mpeg12_bitstream_h +#define vl_mpeg12_bitstream_h + +#include "vl_defines.h" +#include "vl_vlc.h" + +struct vl_mpg12_bs +{ + unsigned width, height; + + struct vl_vlc vlc; + + unsigned *num_ycbcr_blocks; + + struct pipe_ycbcr_block *ycbcr_stream[VL_MAX_PLANES]; + short *ycbcr_buffer[VL_MAX_PLANES]; + + struct pipe_motionvector *mv_stream[VL_MAX_REF_FRAMES]; +}; + +void +vl_mpg12_bs_init(struct vl_mpg12_bs *bs, unsigned width, unsigned height); + +void +vl_mpg12_bs_set_buffers(struct vl_mpg12_bs *bs, struct pipe_ycbcr_block *ycbcr_stream[VL_MAX_PLANES], + short *ycbcr_buffer[VL_MAX_PLANES], struct pipe_motionvector *mv_stream[VL_MAX_REF_FRAMES]); + +void +vl_mpg12_bs_decode(struct vl_mpg12_bs *bs, unsigned num_bytes, const void *buffer, + struct pipe_mpeg12_picture_desc *picture, unsigned num_ycbcr_blocks[3]); + +#endif /* vl_mpeg12_bitstream_h */ diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c b/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c new file mode 100644 index 00000000000..61d947ca4c8 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mpeg12_decoder.c @@ -0,0 +1,972 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <math.h> +#include <assert.h> + +#include <util/u_memory.h> +#include <util/u_rect.h> +#include <util/u_video.h> + +#include "vl_mpeg12_decoder.h" +#include "vl_defines.h" + +#define SCALE_FACTOR_SNORM (32768.0f / 256.0f) +#define SCALE_FACTOR_SSCALED (1.0f / 256.0f) + +struct format_config { + enum pipe_format zscan_source_format; + enum pipe_format idct_source_format; + enum pipe_format mc_source_format; + + float idct_scale; + float mc_scale; +}; + +static const struct format_config bitstream_format_config[] = { + { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SSCALED }, + { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, 1.0f, SCALE_FACTOR_SSCALED }, + { PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SNORM }, + { PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, 1.0f, SCALE_FACTOR_SNORM } +}; + +static const unsigned num_bitstream_format_configs = + sizeof(bitstream_format_config) / sizeof(struct format_config); + +static const struct format_config idct_format_config[] = { + { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SSCALED }, + { PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, PIPE_FORMAT_R16G16B16A16_SSCALED, 1.0f, SCALE_FACTOR_SSCALED }, + { PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_FLOAT, 1.0f, SCALE_FACTOR_SNORM }, + { PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, 1.0f, SCALE_FACTOR_SNORM } +}; + +static const unsigned num_idct_format_configs = + sizeof(idct_format_config) / sizeof(struct format_config); + +static const struct format_config mc_format_config[] = { + //{ PIPE_FORMAT_R16_SSCALED, PIPE_FORMAT_NONE, PIPE_FORMAT_R16_SSCALED, 0.0f, SCALE_FACTOR_SSCALED }, + { PIPE_FORMAT_R16_SNORM, PIPE_FORMAT_NONE, PIPE_FORMAT_R16_SNORM, 0.0f, SCALE_FACTOR_SNORM } +}; + +static const unsigned num_mc_format_configs = + sizeof(mc_format_config) / sizeof(struct format_config); + +static bool +init_zscan_buffer(struct vl_mpeg12_buffer *buffer) +{ + enum pipe_format formats[3]; + + struct pipe_sampler_view **source; + struct pipe_surface **destination; + + struct vl_mpeg12_decoder *dec; + + unsigned i; + + assert(buffer); + + dec = (struct vl_mpeg12_decoder*)buffer->base.decoder; + + formats[0] = formats[1] = formats[2] = dec->zscan_source_format; + buffer->zscan_source = vl_video_buffer_create_ex + ( + dec->base.context, + dec->blocks_per_line * BLOCK_WIDTH * BLOCK_HEIGHT, + align(dec->num_blocks, dec->blocks_per_line) / dec->blocks_per_line, + 1, PIPE_VIDEO_CHROMA_FORMAT_444, formats, PIPE_USAGE_STATIC + ); + + if (!buffer->zscan_source) + goto error_source; + + source = buffer->zscan_source->get_sampler_view_planes(buffer->zscan_source); + if (!source) + goto error_sampler; + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) + destination = dec->idct_source->get_surfaces(dec->idct_source); + else + destination = dec->mc_source->get_surfaces(dec->mc_source); + + if (!destination) + goto error_surface; + + for (i = 0; i < VL_MAX_PLANES; ++i) + if (!vl_zscan_init_buffer(i == 0 ? &dec->zscan_y : &dec->zscan_c, + &buffer->zscan[i], source[i], destination[i])) + goto error_plane; + + return true; + +error_plane: + for (; i > 0; --i) + vl_zscan_cleanup_buffer(&buffer->zscan[i - 1]); + +error_surface: +error_sampler: + buffer->zscan_source->destroy(buffer->zscan_source); + +error_source: + return false; +} + +static void +cleanup_zscan_buffer(struct vl_mpeg12_buffer *buffer) +{ + unsigned i; + + assert(buffer); + + for (i = 0; i < VL_MAX_PLANES; ++i) + vl_zscan_cleanup_buffer(&buffer->zscan[i]); + buffer->zscan_source->destroy(buffer->zscan_source); +} + +static bool +init_idct_buffer(struct vl_mpeg12_buffer *buffer) +{ + struct pipe_sampler_view **idct_source_sv, **mc_source_sv; + + struct vl_mpeg12_decoder *dec; + + unsigned i; + + assert(buffer); + + dec = (struct vl_mpeg12_decoder*)buffer->base.decoder; + + idct_source_sv = dec->idct_source->get_sampler_view_planes(dec->idct_source); + if (!idct_source_sv) + goto error_source_sv; + + mc_source_sv = dec->mc_source->get_sampler_view_planes(dec->mc_source); + if (!mc_source_sv) + goto error_mc_source_sv; + + for (i = 0; i < 3; ++i) + if (!vl_idct_init_buffer(i == 0 ? &dec->idct_y : &dec->idct_c, + &buffer->idct[i], idct_source_sv[i], + mc_source_sv[i])) + goto error_plane; + + return true; + +error_plane: + for (; i > 0; --i) + vl_idct_cleanup_buffer(&buffer->idct[i - 1]); + +error_mc_source_sv: +error_source_sv: + return false; +} + +static void +cleanup_idct_buffer(struct vl_mpeg12_buffer *buf) +{ + struct vl_mpeg12_decoder *dec; + unsigned i; + + assert(buf); + + dec = (struct vl_mpeg12_decoder*)buf->base.decoder; + assert(dec); + + for (i = 0; i < 3; ++i) + vl_idct_cleanup_buffer(&buf->idct[0]); +} + +static bool +init_mc_buffer(struct vl_mpeg12_buffer *buf) +{ + struct vl_mpeg12_decoder *dec; + + assert(buf); + + dec = (struct vl_mpeg12_decoder*)buf->base.decoder; + assert(dec); + + if(!vl_mc_init_buffer(&dec->mc_y, &buf->mc[0])) + goto error_mc_y; + + if(!vl_mc_init_buffer(&dec->mc_c, &buf->mc[1])) + goto error_mc_cb; + + if(!vl_mc_init_buffer(&dec->mc_c, &buf->mc[2])) + goto error_mc_cr; + + return true; + +error_mc_cr: + vl_mc_cleanup_buffer(&buf->mc[1]); + +error_mc_cb: + vl_mc_cleanup_buffer(&buf->mc[0]); + +error_mc_y: + return false; +} + +static void +cleanup_mc_buffer(struct vl_mpeg12_buffer *buf) +{ + unsigned i; + + assert(buf); + + for (i = 0; i < VL_MAX_PLANES; ++i) + vl_mc_cleanup_buffer(&buf->mc[i]); +} + +static void +vl_mpeg12_buffer_destroy(struct pipe_video_decode_buffer *buffer) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + struct vl_mpeg12_decoder *dec; + + assert(buf); + + dec = (struct vl_mpeg12_decoder*)buf->base.decoder; + assert(dec); + + cleanup_zscan_buffer(buf); + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) + cleanup_idct_buffer(buf); + + cleanup_mc_buffer(buf); + + vl_vb_cleanup(&buf->vertex_stream); + + FREE(buf); +} + +static void +vl_mpeg12_buffer_begin_frame(struct pipe_video_decode_buffer *buffer) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + struct vl_mpeg12_decoder *dec; + + struct pipe_sampler_view **sampler_views; + unsigned i; + + assert(buf); + + dec = (struct vl_mpeg12_decoder *)buf->base.decoder; + assert(dec); + + vl_vb_map(&buf->vertex_stream, dec->base.context); + + sampler_views = buf->zscan_source->get_sampler_view_planes(buf->zscan_source); + + assert(sampler_views); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + struct pipe_resource *tex = sampler_views[i]->texture; + struct pipe_box rect = + { + 0, 0, 0, + tex->width0, + tex->height0, + 1 + }; + + buf->tex_transfer[i] = dec->base.context->get_transfer + ( + dec->base.context, tex, + 0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &rect + ); + + buf->texels[i] = dec->base.context->transfer_map(dec->base.context, buf->tex_transfer[i]); + } + + if (dec->base.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { + struct pipe_ycbcr_block *ycbcr_stream[VL_MAX_PLANES]; + struct pipe_motionvector *mv_stream[VL_MAX_REF_FRAMES]; + + for (i = 0; i < VL_MAX_PLANES; ++i) + ycbcr_stream[i] = vl_vb_get_ycbcr_stream(&buf->vertex_stream, i); + + for (i = 0; i < VL_MAX_REF_FRAMES; ++i) + mv_stream[i] = vl_vb_get_mv_stream(&buf->vertex_stream, i); + + vl_mpg12_bs_set_buffers(&buf->bs, ycbcr_stream, buf->texels, mv_stream); + } else { + + for (i = 0; i < VL_MAX_PLANES; ++i) + vl_zscan_set_layout(&buf->zscan[i], dec->zscan_linear); + } +} + +static void +vl_mpeg12_buffer_set_quant_matrix(struct pipe_video_decode_buffer *buffer, + const uint8_t intra_matrix[64], + const uint8_t non_intra_matrix[64]) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + unsigned i; + + for (i = 0; i < VL_MAX_PLANES; ++i) { + vl_zscan_upload_quant(&buf->zscan[i], intra_matrix, true); + vl_zscan_upload_quant(&buf->zscan[i], non_intra_matrix, false); + } +} + +static struct pipe_ycbcr_block * +vl_mpeg12_buffer_get_ycbcr_stream(struct pipe_video_decode_buffer *buffer, int component) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + + assert(buf); + + return vl_vb_get_ycbcr_stream(&buf->vertex_stream, component); +} + +static short * +vl_mpeg12_buffer_get_ycbcr_buffer(struct pipe_video_decode_buffer *buffer, int component) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + + assert(buf); + assert(component < VL_MAX_PLANES); + + return buf->texels[component]; +} + +static unsigned +vl_mpeg12_buffer_get_mv_stream_stride(struct pipe_video_decode_buffer *buffer) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + + assert(buf); + + return vl_vb_get_mv_stream_stride(&buf->vertex_stream); +} + +static struct pipe_motionvector * +vl_mpeg12_buffer_get_mv_stream(struct pipe_video_decode_buffer *buffer, int ref_frame) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + + assert(buf); + + return vl_vb_get_mv_stream(&buf->vertex_stream, ref_frame); +} + +static void +vl_mpeg12_buffer_decode_bitstream(struct pipe_video_decode_buffer *buffer, + unsigned num_bytes, const void *data, + struct pipe_picture_desc *picture, + unsigned num_ycbcr_blocks[3]) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + struct pipe_mpeg12_picture_desc *pic = (struct pipe_mpeg12_picture_desc *)picture; + + struct vl_mpeg12_decoder *dec; + unsigned i; + + assert(buf); + + dec = (struct vl_mpeg12_decoder *)buf->base.decoder; + assert(dec); + + for (i = 0; i < VL_MAX_PLANES; ++i) + vl_zscan_set_layout(&buf->zscan[i], pic->alternate_scan ? dec->zscan_alternate : dec->zscan_normal); + + vl_mpg12_bs_decode(&buf->bs, num_bytes, data, pic, num_ycbcr_blocks); +} + +static void +vl_mpeg12_buffer_end_frame(struct pipe_video_decode_buffer *buffer) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer*)buffer; + struct vl_mpeg12_decoder *dec; + unsigned i; + + assert(buf); + + dec = (struct vl_mpeg12_decoder *)buf->base.decoder; + assert(dec); + + vl_vb_unmap(&buf->vertex_stream, dec->base.context); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + dec->base.context->transfer_unmap(dec->base.context, buf->tex_transfer[i]); + dec->base.context->transfer_destroy(dec->base.context, buf->tex_transfer[i]); + } +} + +static void +vl_mpeg12_destroy(struct pipe_video_decoder *decoder) +{ + struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder*)decoder; + + assert(decoder); + + /* Asserted in softpipe_delete_fs_state() for some reason */ + dec->base.context->bind_vs_state(dec->base.context, NULL); + dec->base.context->bind_fs_state(dec->base.context, NULL); + + dec->base.context->delete_depth_stencil_alpha_state(dec->base.context, dec->dsa); + dec->base.context->delete_sampler_state(dec->base.context, dec->sampler_ycbcr); + + vl_mc_cleanup(&dec->mc_y); + vl_mc_cleanup(&dec->mc_c); + dec->mc_source->destroy(dec->mc_source); + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { + vl_idct_cleanup(&dec->idct_y); + vl_idct_cleanup(&dec->idct_c); + dec->idct_source->destroy(dec->idct_source); + } + + vl_zscan_cleanup(&dec->zscan_y); + vl_zscan_cleanup(&dec->zscan_c); + + dec->base.context->delete_vertex_elements_state(dec->base.context, dec->ves_ycbcr); + dec->base.context->delete_vertex_elements_state(dec->base.context, dec->ves_mv); + + pipe_resource_reference(&dec->quads.buffer, NULL); + pipe_resource_reference(&dec->pos.buffer, NULL); + pipe_resource_reference(&dec->block_num.buffer, NULL); + + pipe_sampler_view_reference(&dec->zscan_linear, NULL); + pipe_sampler_view_reference(&dec->zscan_normal, NULL); + pipe_sampler_view_reference(&dec->zscan_alternate, NULL); + + FREE(dec); +} + +static struct pipe_video_decode_buffer * +vl_mpeg12_create_buffer(struct pipe_video_decoder *decoder) +{ + struct vl_mpeg12_decoder *dec = (struct vl_mpeg12_decoder*)decoder; + struct vl_mpeg12_buffer *buffer; + + assert(dec); + + buffer = CALLOC_STRUCT(vl_mpeg12_buffer); + if (buffer == NULL) + return NULL; + + buffer->base.decoder = decoder; + buffer->base.destroy = vl_mpeg12_buffer_destroy; + buffer->base.begin_frame = vl_mpeg12_buffer_begin_frame; + buffer->base.set_quant_matrix = vl_mpeg12_buffer_set_quant_matrix; + buffer->base.get_ycbcr_stream = vl_mpeg12_buffer_get_ycbcr_stream; + buffer->base.get_ycbcr_buffer = vl_mpeg12_buffer_get_ycbcr_buffer; + buffer->base.get_mv_stream_stride = vl_mpeg12_buffer_get_mv_stream_stride; + buffer->base.get_mv_stream = vl_mpeg12_buffer_get_mv_stream; + buffer->base.decode_bitstream = vl_mpeg12_buffer_decode_bitstream; + buffer->base.end_frame = vl_mpeg12_buffer_end_frame; + + if (!vl_vb_init(&buffer->vertex_stream, dec->base.context, + dec->base.width / MACROBLOCK_WIDTH, + dec->base.height / MACROBLOCK_HEIGHT)) + goto error_vertex_buffer; + + if (!init_mc_buffer(buffer)) + goto error_mc; + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) + if (!init_idct_buffer(buffer)) + goto error_idct; + + if (!init_zscan_buffer(buffer)) + goto error_zscan; + + if (dec->base.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) + vl_mpg12_bs_init(&buffer->bs, + dec->base.width / MACROBLOCK_WIDTH, + dec->base.height / MACROBLOCK_HEIGHT); + + return &buffer->base; + +error_zscan: + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) + cleanup_idct_buffer(buffer); + +error_idct: + cleanup_mc_buffer(buffer); + +error_mc: + vl_vb_cleanup(&buffer->vertex_stream); + +error_vertex_buffer: + FREE(buffer); + return NULL; +} + +static void +vl_mpeg12_decoder_flush_buffer(struct pipe_video_decode_buffer *buffer, + unsigned num_ycbcr_blocks[3], + struct pipe_video_buffer *refs[2], + struct pipe_video_buffer *dst) +{ + struct vl_mpeg12_buffer *buf = (struct vl_mpeg12_buffer *)buffer; + struct vl_mpeg12_decoder *dec; + + struct pipe_sampler_view **sv[VL_MAX_REF_FRAMES], **mc_source_sv; + struct pipe_surface **surfaces; + + struct pipe_vertex_buffer vb[3]; + + unsigned i, j, component; + unsigned nr_components; + + assert(buf); + + dec = (struct vl_mpeg12_decoder *)buf->base.decoder; + assert(dec); + + for (i = 0; i < 2; ++i) + sv[i] = refs[i] ? refs[i]->get_sampler_view_planes(refs[i]) : NULL; + + vb[0] = dec->quads; + vb[1] = dec->pos; + + surfaces = dst->get_surfaces(dst); + + dec->base.context->bind_vertex_elements_state(dec->base.context, dec->ves_mv); + for (i = 0; i < VL_MAX_PLANES; ++i) { + if (!surfaces[i]) continue; + + vl_mc_set_surface(&buf->mc[i], surfaces[i]); + + for (j = 0; j < VL_MAX_REF_FRAMES; ++j) { + if (!sv[j]) continue; + + vb[2] = vl_vb_get_mv(&buf->vertex_stream, j);; + dec->base.context->set_vertex_buffers(dec->base.context, 3, vb); + + vl_mc_render_ref(&buf->mc[i], sv[j][i]); + } + } + + vb[2] = dec->block_num; + + dec->base.context->bind_vertex_elements_state(dec->base.context, dec->ves_ycbcr); + for (i = 0; i < VL_MAX_PLANES; ++i) { + if (!num_ycbcr_blocks[i]) continue; + + vb[1] = vl_vb_get_ycbcr(&buf->vertex_stream, i); + dec->base.context->set_vertex_buffers(dec->base.context, 3, vb); + + vl_zscan_render(&buf->zscan[i] , num_ycbcr_blocks[i]); + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) + vl_idct_flush(&buf->idct[i], num_ycbcr_blocks[i]); + } + + mc_source_sv = dec->mc_source->get_sampler_view_planes(dec->mc_source); + for (i = 0, component = 0; i < VL_MAX_PLANES; ++i) { + if (!surfaces[i]) continue; + + nr_components = util_format_get_nr_components(surfaces[i]->texture->format); + for (j = 0; j < nr_components; ++j, ++component) { + if (!num_ycbcr_blocks[i]) continue; + + vb[1] = vl_vb_get_ycbcr(&buf->vertex_stream, component); + dec->base.context->set_vertex_buffers(dec->base.context, 3, vb); + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) + vl_idct_prepare_stage2(&buf->idct[component]); + else { + dec->base.context->set_fragment_sampler_views(dec->base.context, 1, &mc_source_sv[component]); + dec->base.context->bind_fragment_sampler_states(dec->base.context, 1, &dec->sampler_ycbcr); + } + vl_mc_render_ycbcr(&buf->mc[i], j, num_ycbcr_blocks[component]); + } + } +} + +static bool +init_pipe_state(struct vl_mpeg12_decoder *dec) +{ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_sampler_state sampler; + unsigned i; + + assert(dec); + + memset(&dsa, 0, sizeof dsa); + dsa.depth.enabled = 0; + dsa.depth.writemask = 0; + dsa.depth.func = PIPE_FUNC_ALWAYS; + for (i = 0; i < 2; ++i) { + dsa.stencil[i].enabled = 0; + dsa.stencil[i].func = PIPE_FUNC_ALWAYS; + dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].valuemask = 0; + dsa.stencil[i].writemask = 0; + } + dsa.alpha.enabled = 0; + dsa.alpha.func = PIPE_FUNC_ALWAYS; + dsa.alpha.ref_value = 0; + dec->dsa = dec->base.context->create_depth_stencil_alpha_state(dec->base.context, &dsa); + dec->base.context->bind_depth_stencil_alpha_state(dec->base.context, dec->dsa); + + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + dec->sampler_ycbcr = dec->base.context->create_sampler_state(dec->base.context, &sampler); + if (!dec->sampler_ycbcr) + return false; + + return true; +} + +static const struct format_config* +find_format_config(struct vl_mpeg12_decoder *dec, const struct format_config configs[], unsigned num_configs) +{ + struct pipe_screen *screen; + unsigned i; + + assert(dec); + + screen = dec->base.context->screen; + + for (i = 0; i < num_configs; ++i) { + if (!screen->is_format_supported(screen, configs[i].zscan_source_format, PIPE_TEXTURE_2D, + 1, PIPE_BIND_SAMPLER_VIEW)) + continue; + + if (configs[i].idct_source_format != PIPE_FORMAT_NONE) { + if (!screen->is_format_supported(screen, configs[i].idct_source_format, PIPE_TEXTURE_2D, + 1, PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET)) + continue; + + if (!screen->is_format_supported(screen, configs[i].mc_source_format, PIPE_TEXTURE_3D, + 1, PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET)) + continue; + } else { + if (!screen->is_format_supported(screen, configs[i].mc_source_format, PIPE_TEXTURE_2D, + 1, PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET)) + continue; + } + return &configs[i]; + } + + return NULL; +} + +static bool +init_zscan(struct vl_mpeg12_decoder *dec, const struct format_config* format_config) +{ + unsigned num_channels; + + assert(dec); + + dec->zscan_source_format = format_config->zscan_source_format; + dec->zscan_linear = vl_zscan_layout(dec->base.context, vl_zscan_linear, dec->blocks_per_line); + dec->zscan_normal = vl_zscan_layout(dec->base.context, vl_zscan_normal, dec->blocks_per_line); + dec->zscan_alternate = vl_zscan_layout(dec->base.context, vl_zscan_alternate, dec->blocks_per_line); + + num_channels = dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT ? 4 : 1; + + if (!vl_zscan_init(&dec->zscan_y, dec->base.context, dec->base.width, dec->base.height, + dec->blocks_per_line, dec->num_blocks, num_channels)) + return false; + + if (!vl_zscan_init(&dec->zscan_c, dec->base.context, dec->chroma_width, dec->chroma_height, + dec->blocks_per_line, dec->num_blocks, num_channels)) + return false; + + return true; +} + +static bool +init_idct(struct vl_mpeg12_decoder *dec, const struct format_config* format_config) +{ + unsigned nr_of_idct_render_targets, max_inst; + enum pipe_format formats[3]; + + struct pipe_sampler_view *matrix = NULL; + + nr_of_idct_render_targets = dec->base.context->screen->get_param + ( + dec->base.context->screen, PIPE_CAP_MAX_RENDER_TARGETS + ); + + max_inst = dec->base.context->screen->get_shader_param + ( + dec->base.context->screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_INSTRUCTIONS + ); + + // Just assume we need 32 inst per render target, not 100% true, but should work in most cases + if (nr_of_idct_render_targets >= 4 && max_inst >= 32*4) + // more than 4 render targets usually doesn't makes any seens + nr_of_idct_render_targets = 4; + else + nr_of_idct_render_targets = 1; + + formats[0] = formats[1] = formats[2] = format_config->idct_source_format; + dec->idct_source = vl_video_buffer_create_ex + ( + dec->base.context, dec->base.width / 4, dec->base.height, 1, + dec->base.chroma_format, formats, PIPE_USAGE_STATIC + ); + + if (!dec->idct_source) + goto error_idct_source; + + formats[0] = formats[1] = formats[2] = format_config->mc_source_format; + dec->mc_source = vl_video_buffer_create_ex + ( + dec->base.context, dec->base.width / nr_of_idct_render_targets, + dec->base.height / 4, nr_of_idct_render_targets, + dec->base.chroma_format, formats, PIPE_USAGE_STATIC + ); + + if (!dec->mc_source) + goto error_mc_source; + + if (!(matrix = vl_idct_upload_matrix(dec->base.context, format_config->idct_scale))) + goto error_matrix; + + if (!vl_idct_init(&dec->idct_y, dec->base.context, dec->base.width, dec->base.height, + nr_of_idct_render_targets, matrix, matrix)) + goto error_y; + + if(!vl_idct_init(&dec->idct_c, dec->base.context, dec->chroma_width, dec->chroma_height, + nr_of_idct_render_targets, matrix, matrix)) + goto error_c; + + pipe_sampler_view_reference(&matrix, NULL); + + return true; + +error_c: + vl_idct_cleanup(&dec->idct_y); + +error_y: + pipe_sampler_view_reference(&matrix, NULL); + +error_matrix: + dec->mc_source->destroy(dec->mc_source); + +error_mc_source: + dec->idct_source->destroy(dec->idct_source); + +error_idct_source: + return false; +} + +static bool +init_mc_source_widthout_idct(struct vl_mpeg12_decoder *dec, const struct format_config* format_config) +{ + enum pipe_format formats[3]; + + formats[0] = formats[1] = formats[2] = format_config->mc_source_format; + dec->mc_source = vl_video_buffer_create_ex + ( + dec->base.context, dec->base.width, dec->base.height, 1, + dec->base.chroma_format, formats, PIPE_USAGE_STATIC + ); + + return dec->mc_source != NULL; +} + +static void +mc_vert_shader_callback(void *priv, struct vl_mc *mc, + struct ureg_program *shader, + unsigned first_output, + struct ureg_dst tex) +{ + struct vl_mpeg12_decoder *dec = priv; + struct ureg_dst o_vtex; + + assert(priv && mc); + assert(shader); + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { + struct vl_idct *idct = mc == &dec->mc_y ? &dec->idct_y : &dec->idct_c; + vl_idct_stage2_vert_shader(idct, shader, first_output, tex); + } else { + o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, first_output); + ureg_MOV(shader, ureg_writemask(o_vtex, TGSI_WRITEMASK_XY), ureg_src(tex)); + } +} + +static void +mc_frag_shader_callback(void *priv, struct vl_mc *mc, + struct ureg_program *shader, + unsigned first_input, + struct ureg_dst dst) +{ + struct vl_mpeg12_decoder *dec = priv; + struct ureg_src src, sampler; + + assert(priv && mc); + assert(shader); + + if (dec->base.entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { + struct vl_idct *idct = mc == &dec->mc_y ? &dec->idct_y : &dec->idct_c; + vl_idct_stage2_frag_shader(idct, shader, first_input, dst); + } else { + src = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, first_input, TGSI_INTERPOLATE_LINEAR); + sampler = ureg_DECL_sampler(shader, 0); + ureg_TEX(shader, dst, TGSI_TEXTURE_2D, src, sampler); + } +} + +struct pipe_video_decoder * +vl_create_mpeg12_decoder(struct pipe_context *context, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height) +{ + const unsigned block_size_pixels = BLOCK_WIDTH * BLOCK_HEIGHT; + const struct format_config *format_config; + struct vl_mpeg12_decoder *dec; + + assert(u_reduce_video_profile(profile) == PIPE_VIDEO_CODEC_MPEG12); + + dec = CALLOC_STRUCT(vl_mpeg12_decoder); + + if (!dec) + return NULL; + + dec->base.context = context; + dec->base.profile = profile; + dec->base.entrypoint = entrypoint; + dec->base.chroma_format = chroma_format; + dec->base.width = width; + dec->base.height = height; + + dec->base.destroy = vl_mpeg12_destroy; + dec->base.create_buffer = vl_mpeg12_create_buffer; + dec->base.flush_buffer = vl_mpeg12_decoder_flush_buffer; + + dec->blocks_per_line = MAX2(util_next_power_of_two(dec->base.width) / block_size_pixels, 4); + dec->num_blocks = (dec->base.width * dec->base.height) / block_size_pixels; + + dec->quads = vl_vb_upload_quads(dec->base.context); + dec->pos = vl_vb_upload_pos( + dec->base.context, + dec->base.width / MACROBLOCK_WIDTH, + dec->base.height / MACROBLOCK_HEIGHT + ); + dec->block_num = vl_vb_upload_block_num(dec->base.context, dec->num_blocks); + + dec->ves_ycbcr = vl_vb_get_ves_ycbcr(dec->base.context); + dec->ves_mv = vl_vb_get_ves_mv(dec->base.context); + + /* TODO: Implement 422, 444 */ + assert(dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420); + + if (dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { + dec->chroma_width = dec->base.width / 2; + dec->chroma_height = dec->base.height / 2; + } else if (dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) { + dec->chroma_width = dec->base.width; + dec->chroma_height = dec->base.height / 2; + } else { + dec->chroma_width = dec->base.width; + dec->chroma_height = dec->base.height; + } + + switch (entrypoint) { + case PIPE_VIDEO_ENTRYPOINT_BITSTREAM: + format_config = find_format_config(dec, bitstream_format_config, num_bitstream_format_configs); + break; + + case PIPE_VIDEO_ENTRYPOINT_IDCT: + format_config = find_format_config(dec, idct_format_config, num_idct_format_configs); + break; + + case PIPE_VIDEO_ENTRYPOINT_MC: + format_config = find_format_config(dec, mc_format_config, num_mc_format_configs); + break; + + default: + assert(0); + return NULL; + } + + if (!format_config) + return NULL; + + if (!init_zscan(dec, format_config)) + goto error_zscan; + + if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { + if (!init_idct(dec, format_config)) + goto error_sources; + } else { + if (!init_mc_source_widthout_idct(dec, format_config)) + goto error_sources; + } + + if (!vl_mc_init(&dec->mc_y, dec->base.context, dec->base.width, dec->base.height, + MACROBLOCK_HEIGHT, format_config->mc_scale, + mc_vert_shader_callback, mc_frag_shader_callback, dec)) + goto error_mc_y; + + // TODO + if (!vl_mc_init(&dec->mc_c, dec->base.context, dec->base.width, dec->base.height, + BLOCK_HEIGHT, format_config->mc_scale, + mc_vert_shader_callback, mc_frag_shader_callback, dec)) + goto error_mc_c; + + if (!init_pipe_state(dec)) + goto error_pipe_state; + + return &dec->base; + +error_pipe_state: + vl_mc_cleanup(&dec->mc_c); + +error_mc_c: + vl_mc_cleanup(&dec->mc_y); + +error_mc_y: + if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { + vl_idct_cleanup(&dec->idct_y); + vl_idct_cleanup(&dec->idct_c); + dec->idct_source->destroy(dec->idct_source); + } + dec->mc_source->destroy(dec->mc_source); + +error_sources: + vl_zscan_cleanup(&dec->zscan_y); + vl_zscan_cleanup(&dec->zscan_c); + +error_zscan: + FREE(dec); + return NULL; +} diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_decoder.h b/src/gallium/auxiliary/vl/vl_mpeg12_decoder.h new file mode 100644 index 00000000000..01265e368a3 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mpeg12_decoder.h @@ -0,0 +1,105 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_mpeg12_decoder_h +#define vl_mpeg12_decoder_h + +#include <pipe/p_video_decoder.h> + +#include "vl_mpeg12_bitstream.h" +#include "vl_zscan.h" +#include "vl_idct.h" +#include "vl_mc.h" + +#include "vl_vertex_buffers.h" +#include "vl_video_buffer.h" + +struct pipe_screen; +struct pipe_context; + +struct vl_mpeg12_decoder +{ + struct pipe_video_decoder base; + + unsigned chroma_width, chroma_height; + + unsigned blocks_per_line; + unsigned num_blocks; + + enum pipe_format zscan_source_format; + + struct pipe_vertex_buffer quads; + struct pipe_vertex_buffer pos; + struct pipe_vertex_buffer block_num; + + void *ves_ycbcr; + void *ves_mv; + + void *sampler_ycbcr; + + struct pipe_sampler_view *zscan_linear; + struct pipe_sampler_view *zscan_normal; + struct pipe_sampler_view *zscan_alternate; + + struct pipe_video_buffer *idct_source; + struct pipe_video_buffer *mc_source; + + struct vl_zscan zscan_y, zscan_c; + struct vl_idct idct_y, idct_c; + struct vl_mc mc_y, mc_c; + + void *dsa; +}; + +struct vl_mpeg12_buffer +{ + struct pipe_video_decode_buffer base; + + struct vl_vertex_buffer vertex_stream; + + struct pipe_video_buffer *zscan_source; + + struct vl_mpg12_bs bs; + struct vl_zscan_buffer zscan[VL_MAX_PLANES]; + struct vl_idct_buffer idct[VL_MAX_PLANES]; + struct vl_mc_buffer mc[VL_MAX_PLANES]; + + struct pipe_transfer *tex_transfer[VL_MAX_PLANES]; + short *texels[VL_MAX_PLANES]; +}; + +/** + * creates a shader based mpeg12 decoder + */ +struct pipe_video_decoder * +vl_create_mpeg12_decoder(struct pipe_context *pipe, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height); + +#endif /* vl_mpeg12_decoder_h */ diff --git a/src/gallium/auxiliary/vl/vl_types.h b/src/gallium/auxiliary/vl/vl_types.h new file mode 100644 index 00000000000..27bb69d67bc --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_types.h @@ -0,0 +1,51 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_types_h +#define vl_types_h + +struct vertex2f +{ + float x, y; +}; + +struct vertex2s +{ + short x, y; +}; + +struct vertex4f +{ + float x, y, z, w; +}; + +struct vertex4s +{ + short x, y, z, w; +}; + +#endif /* vl_types_h */ diff --git a/src/gallium/auxiliary/vl/vl_vertex_buffers.c b/src/gallium/auxiliary/vl/vl_vertex_buffers.c new file mode 100644 index 00000000000..c0f1449bf80 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_vertex_buffers.c @@ -0,0 +1,419 @@ +/************************************************************************** + * + * Copyright 2010 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <util/u_format.h> +#include "vl_vertex_buffers.h" +#include "vl_types.h" + +/* vertices for a quad covering a block */ +static const struct vertex2f block_quad[4] = { + {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} +}; + +struct pipe_vertex_buffer +vl_vb_upload_quads(struct pipe_context *pipe) +{ + struct pipe_vertex_buffer quad; + struct pipe_transfer *buf_transfer; + struct vertex2f *v; + + unsigned i; + + assert(pipe); + + /* create buffer */ + quad.stride = sizeof(struct vertex2f); + quad.buffer_offset = 0; + quad.buffer = pipe_buffer_create + ( + pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STATIC, + sizeof(struct vertex2f) * 4 + ); + + if(!quad.buffer) + return quad; + + /* and fill it */ + v = pipe_buffer_map + ( + pipe, + quad.buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer + ); + + for (i = 0; i < 4; ++i, ++v) { + v->x = block_quad[i].x; + v->y = block_quad[i].y; + } + + pipe_buffer_unmap(pipe, buf_transfer); + + return quad; +} + +struct pipe_vertex_buffer +vl_vb_upload_pos(struct pipe_context *pipe, unsigned width, unsigned height) +{ + struct pipe_vertex_buffer pos; + struct pipe_transfer *buf_transfer; + struct vertex2s *v; + + unsigned x, y; + + assert(pipe); + + /* create buffer */ + pos.stride = sizeof(struct vertex2s); + pos.buffer_offset = 0; + pos.buffer = pipe_buffer_create + ( + pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STATIC, + sizeof(struct vertex2s) * width * height + ); + + if(!pos.buffer) + return pos; + + /* and fill it */ + v = pipe_buffer_map + ( + pipe, + pos.buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer + ); + + for ( y = 0; y < height; ++y) { + for ( x = 0; x < width; ++x, ++v) { + v->x = x; + v->y = y; + } + } + + pipe_buffer_unmap(pipe, buf_transfer); + + return pos; +} + +struct pipe_vertex_buffer +vl_vb_upload_block_num(struct pipe_context *pipe, unsigned num_blocks) +{ + struct pipe_vertex_buffer buf; + struct pipe_transfer *buf_transfer; + struct vertex2s *v; + unsigned i; + + assert(pipe); + + /* create buffer */ + buf.stride = sizeof(struct vertex2s); + buf.buffer_offset = 0; + buf.buffer = pipe_buffer_create + ( + pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STATIC, + sizeof(struct vertex2s) * num_blocks + ); + + if(!buf.buffer) + return buf; + + /* and fill it */ + v = pipe_buffer_map + ( + pipe, + buf.buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer + ); + + for ( i = 0; i < num_blocks; ++i, ++v) { + v->x = i; + v->y = i; + } + + pipe_buffer_unmap(pipe, buf_transfer); + + return buf; +} + +static struct pipe_vertex_element +vl_vb_get_quad_vertex_element(void) +{ + struct pipe_vertex_element element; + + /* setup rectangle element */ + element.src_offset = 0; + element.instance_divisor = 0; + element.vertex_buffer_index = 0; + element.src_format = PIPE_FORMAT_R32G32_FLOAT; + + return element; +} + +static void +vl_vb_element_helper(struct pipe_vertex_element* elements, unsigned num_elements, + unsigned vertex_buffer_index) +{ + unsigned i, offset = 0; + + assert(elements && num_elements); + + for ( i = 0; i < num_elements; ++i ) { + elements[i].src_offset = offset; + elements[i].instance_divisor = 1; + elements[i].vertex_buffer_index = vertex_buffer_index; + offset += util_format_get_blocksize(elements[i].src_format); + } +} + +void * +vl_vb_get_ves_ycbcr(struct pipe_context *pipe) +{ + struct pipe_vertex_element vertex_elems[NUM_VS_INPUTS]; + + assert(pipe); + + memset(&vertex_elems, 0, sizeof(vertex_elems)); + vertex_elems[VS_I_RECT] = vl_vb_get_quad_vertex_element(); + + /* Position element */ + vertex_elems[VS_I_VPOS].src_format = PIPE_FORMAT_R8G8B8A8_USCALED; + + vl_vb_element_helper(&vertex_elems[VS_I_VPOS], 1, 1); + + /* block num element */ + vertex_elems[VS_I_BLOCK_NUM].src_format = PIPE_FORMAT_R16G16_SSCALED; + + vl_vb_element_helper(&vertex_elems[VS_I_BLOCK_NUM], 1, 2); + + return pipe->create_vertex_elements_state(pipe, 3, vertex_elems); +} + +void * +vl_vb_get_ves_mv(struct pipe_context *pipe) +{ + struct pipe_vertex_element vertex_elems[NUM_VS_INPUTS]; + + assert(pipe); + + memset(&vertex_elems, 0, sizeof(vertex_elems)); + vertex_elems[VS_I_RECT] = vl_vb_get_quad_vertex_element(); + + /* Position element */ + vertex_elems[VS_I_VPOS].src_format = PIPE_FORMAT_R16G16_SSCALED; + + vl_vb_element_helper(&vertex_elems[VS_I_VPOS], 1, 1); + + /* motion vector TOP element */ + vertex_elems[VS_I_MV_TOP].src_format = PIPE_FORMAT_R16G16B16A16_SSCALED; + + /* motion vector BOTTOM element */ + vertex_elems[VS_I_MV_BOTTOM].src_format = PIPE_FORMAT_R16G16B16A16_SSCALED; + + vl_vb_element_helper(&vertex_elems[VS_I_MV_TOP], 2, 2); + + return pipe->create_vertex_elements_state(pipe, NUM_VS_INPUTS, vertex_elems); +} + +bool +vl_vb_init(struct vl_vertex_buffer *buffer, struct pipe_context *pipe, + unsigned width, unsigned height) +{ + unsigned i, size; + + assert(buffer); + + buffer->width = width; + buffer->height = height; + + size = width * height; + + for (i = 0; i < VL_MAX_PLANES; ++i) { + buffer->ycbcr[i].resource = pipe_buffer_create + ( + pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + sizeof(struct pipe_ycbcr_block) * size * 4 + ); + if (!buffer->ycbcr[i].resource) + goto error_ycbcr; + } + + for (i = 0; i < VL_MAX_REF_FRAMES; ++i) { + buffer->mv[i].resource = pipe_buffer_create + ( + pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + sizeof(struct pipe_motionvector) * size + ); + if (!buffer->mv[i].resource) + goto error_mv; + } + + vl_vb_map(buffer, pipe); + return true; + +error_mv: + for (i = 0; i < VL_MAX_PLANES; ++i) + pipe_resource_reference(&buffer->mv[i].resource, NULL); + +error_ycbcr: + for (i = 0; i < VL_MAX_PLANES; ++i) + pipe_resource_reference(&buffer->ycbcr[i].resource, NULL); + return false; +} + +unsigned +vl_vb_attributes_per_plock(struct vl_vertex_buffer *buffer) +{ + return 1; +} + +struct pipe_vertex_buffer +vl_vb_get_ycbcr(struct vl_vertex_buffer *buffer, int component) +{ + struct pipe_vertex_buffer buf; + + assert(buffer); + + buf.stride = sizeof(struct pipe_ycbcr_block); + buf.buffer_offset = 0; + buf.buffer = buffer->ycbcr[component].resource; + + return buf; +} + +struct pipe_vertex_buffer +vl_vb_get_mv(struct vl_vertex_buffer *buffer, int motionvector) +{ + struct pipe_vertex_buffer buf; + + assert(buffer); + + buf.stride = sizeof(struct pipe_motionvector); + buf.buffer_offset = 0; + buf.buffer = buffer->mv[motionvector].resource; + + return buf; +} + +void +vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe) +{ + unsigned i; + + assert(buffer && pipe); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + buffer->ycbcr[i].vertex_stream = pipe_buffer_map + ( + pipe, + buffer->ycbcr[i].resource, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buffer->ycbcr[i].transfer + ); + } + + for (i = 0; i < VL_MAX_REF_FRAMES; ++i) { + buffer->mv[i].vertex_stream = pipe_buffer_map + ( + pipe, + buffer->mv[i].resource, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buffer->mv[i].transfer + ); + } + +} + +struct pipe_ycbcr_block * +vl_vb_get_ycbcr_stream(struct vl_vertex_buffer *buffer, int component) +{ + assert(buffer); + assert(component < VL_MAX_PLANES); + + return buffer->ycbcr[component].vertex_stream; +} + +unsigned +vl_vb_get_mv_stream_stride(struct vl_vertex_buffer *buffer) +{ + assert(buffer); + + return buffer->width; +} + +struct pipe_motionvector * +vl_vb_get_mv_stream(struct vl_vertex_buffer *buffer, int ref_frame) +{ + assert(buffer); + assert(ref_frame < VL_MAX_REF_FRAMES); + + return buffer->mv[ref_frame].vertex_stream; +} + +void +vl_vb_unmap(struct vl_vertex_buffer *buffer, struct pipe_context *pipe) +{ + unsigned i; + + assert(buffer && pipe); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + pipe_buffer_unmap(pipe, buffer->ycbcr[i].transfer); + } + + for (i = 0; i < VL_MAX_REF_FRAMES; ++i) { + pipe_buffer_unmap(pipe, buffer->mv[i].transfer); + } +} + +void +vl_vb_cleanup(struct vl_vertex_buffer *buffer) +{ + unsigned i; + + assert(buffer); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + pipe_resource_reference(&buffer->ycbcr[i].resource, NULL); + } + + for (i = 0; i < VL_MAX_REF_FRAMES; ++i) { + pipe_resource_reference(&buffer->mv[i].resource, NULL); + } +} diff --git a/src/gallium/auxiliary/vl/vl_vertex_buffers.h b/src/gallium/auxiliary/vl/vl_vertex_buffers.h new file mode 100644 index 00000000000..74845a42b69 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_vertex_buffers.h @@ -0,0 +1,104 @@ +/************************************************************************** + * + * Copyright 2010 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ +#ifndef vl_vertex_buffers_h +#define vl_vertex_buffers_h + +#include <pipe/p_state.h> +#include <pipe/p_video_state.h> + +#include "vl_defines.h" +#include "vl_types.h" + +/* vertex buffers act as a todo list + * uploading all the usefull informations to video ram + * so a vertex shader can work with them + */ + +/* inputs to the vertex shaders */ +enum VS_INPUT +{ + VS_I_RECT = 0, + VS_I_VPOS = 1, + + VS_I_BLOCK_NUM = 2, + + VS_I_MV_TOP = 2, + VS_I_MV_BOTTOM = 3, + + NUM_VS_INPUTS = 4 +}; + +struct vl_vertex_buffer +{ + unsigned width, height; + + struct { + struct pipe_resource *resource; + struct pipe_transfer *transfer; + struct pipe_ycbcr_block *vertex_stream; + } ycbcr[VL_MAX_PLANES]; + + struct { + struct pipe_resource *resource; + struct pipe_transfer *transfer; + struct pipe_motionvector *vertex_stream; + } mv[VL_MAX_REF_FRAMES]; +}; + +struct pipe_vertex_buffer vl_vb_upload_quads(struct pipe_context *pipe); + +struct pipe_vertex_buffer vl_vb_upload_pos(struct pipe_context *pipe, unsigned width, unsigned height); + +struct pipe_vertex_buffer vl_vb_upload_block_num(struct pipe_context *pipe, unsigned num_blocks); + +void *vl_vb_get_ves_ycbcr(struct pipe_context *pipe); + +void *vl_vb_get_ves_mv(struct pipe_context *pipe); + +bool vl_vb_init(struct vl_vertex_buffer *buffer, + struct pipe_context *pipe, + unsigned width, unsigned height); + +unsigned vl_vb_attributes_per_plock(struct vl_vertex_buffer *buffer); + +void vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe); + +struct pipe_vertex_buffer vl_vb_get_ycbcr(struct vl_vertex_buffer *buffer, int component); + +struct pipe_ycbcr_block *vl_vb_get_ycbcr_stream(struct vl_vertex_buffer *buffer, int component); + +struct pipe_vertex_buffer vl_vb_get_mv(struct vl_vertex_buffer *buffer, int ref_frame); + +unsigned vl_vb_get_mv_stream_stride(struct vl_vertex_buffer *buffer); + +struct pipe_motionvector *vl_vb_get_mv_stream(struct vl_vertex_buffer *buffer, int ref_frame); + +void vl_vb_unmap(struct vl_vertex_buffer *buffer, struct pipe_context *pipe); + +void vl_vb_cleanup(struct vl_vertex_buffer *buffer); + +#endif /* vl_vertex_buffers_h */ diff --git a/src/gallium/auxiliary/vl/vl_video_buffer.c b/src/gallium/auxiliary/vl/vl_video_buffer.c new file mode 100644 index 00000000000..4d8b6649dd2 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_video_buffer.c @@ -0,0 +1,340 @@ +/************************************************************************** + * + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <pipe/p_screen.h> +#include <pipe/p_context.h> +#include <pipe/p_state.h> + +#include <util/u_format.h> +#include <util/u_inlines.h> +#include <util/u_sampler.h> +#include <util/u_memory.h> + +#include "vl_video_buffer.h" + +const enum pipe_format const_resource_formats_YV12[3] = { + PIPE_FORMAT_R8_UNORM, + PIPE_FORMAT_R8_UNORM, + PIPE_FORMAT_R8_UNORM +}; + +const enum pipe_format const_resource_formats_NV12[3] = { + PIPE_FORMAT_R8_UNORM, + PIPE_FORMAT_R8G8_UNORM, + PIPE_FORMAT_NONE +}; + +const enum pipe_format * +vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format) +{ + switch(format) { + case PIPE_FORMAT_YV12: + return const_resource_formats_YV12; + + case PIPE_FORMAT_NV12: + return const_resource_formats_NV12; + + default: + return NULL; + } +} + +boolean +vl_video_buffer_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_video_profile profile) +{ + const enum pipe_format *resource_formats; + unsigned i; + + resource_formats = vl_video_buffer_formats(screen, format); + if (!resource_formats) + return false; + + for(i = 0; i < VL_MAX_PLANES; ++i) { + if (!resource_formats[i]) + continue; + + if (!screen->is_format_supported(screen, resource_formats[i], PIPE_TEXTURE_2D, 0, PIPE_USAGE_STATIC)) + return false; + } + + return true; +} + +unsigned +vl_video_buffer_max_size(struct pipe_screen *screen) +{ + uint32_t max_2d_texture_level; + + max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); + + return 1 << (max_2d_texture_level-1); +} + +static void +vl_video_buffer_destroy(struct pipe_video_buffer *buffer) +{ + struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; + unsigned i; + + assert(buf); + + for (i = 0; i < VL_MAX_PLANES; ++i) { + pipe_surface_reference(&buf->surfaces[i], NULL); + pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL); + pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL); + pipe_resource_reference(&buf->resources[i], NULL); + } + + FREE(buffer); +} + +static struct pipe_sampler_view ** +vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer) +{ + struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; + struct pipe_sampler_view sv_templ; + struct pipe_context *pipe; + unsigned i; + + assert(buf); + + pipe = buf->base.context; + + for (i = 0; i < buf->num_planes; ++i ) { + if (!buf->sampler_view_planes[i]) { + memset(&sv_templ, 0, sizeof(sv_templ)); + u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format); + + if (util_format_get_nr_components(buf->resources[i]->format) == 1) + sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_RED; + + buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ); + if (!buf->sampler_view_planes[i]) + goto error; + } + } + + return buf->sampler_view_planes; + +error: + for (i = 0; i < buf->num_planes; ++i ) + pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL); + + return NULL; +} + +static struct pipe_sampler_view ** +vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer) +{ + struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; + struct pipe_sampler_view sv_templ; + struct pipe_context *pipe; + unsigned i, j, component; + + assert(buf); + + pipe = buf->base.context; + + for (component = 0, i = 0; i < buf->num_planes; ++i ) { + unsigned nr_components = util_format_get_nr_components(buf->resources[i]->format); + + for (j = 0; j < nr_components; ++j, ++component) { + assert(component < VL_MAX_PLANES); + + if (!buf->sampler_view_components[component]) { + memset(&sv_templ, 0, sizeof(sv_templ)); + u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format); + sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j; + sv_templ.swizzle_a = PIPE_SWIZZLE_ONE; + buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ); + if (!buf->sampler_view_components[component]) + goto error; + } + } + } + + return buf->sampler_view_components; + +error: + for (i = 0; i < VL_MAX_PLANES; ++i ) + pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL); + + return NULL; +} + +static struct pipe_surface ** +vl_video_buffer_surfaces(struct pipe_video_buffer *buffer) +{ + struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer; + struct pipe_surface surf_templ; + struct pipe_context *pipe; + unsigned i; + + assert(buf); + + pipe = buf->base.context; + + for (i = 0; i < buf->num_planes; ++i ) { + if (!buf->surfaces[i]) { + memset(&surf_templ, 0, sizeof(surf_templ)); + surf_templ.format = buf->resources[i]->format; + surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + buf->surfaces[i] = pipe->create_surface(pipe, buf->resources[i], &surf_templ); + if (!buf->surfaces[i]) + goto error; + } + } + + return buf->surfaces; + +error: + for (i = 0; i < buf->num_planes; ++i ) + pipe_surface_reference(&buf->surfaces[i], NULL); + + return NULL; +} + +struct pipe_video_buffer * +vl_video_buffer_create(struct pipe_context *pipe, + enum pipe_format buffer_format, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height) +{ + const enum pipe_format *resource_formats; + struct pipe_video_buffer *result; + unsigned buffer_width, buffer_height; + bool pot_buffers; + + assert(pipe); + assert(width > 0 && height > 0); + + pot_buffers = !pipe->screen->get_video_param + ( + pipe->screen, + PIPE_VIDEO_PROFILE_UNKNOWN, + PIPE_VIDEO_CAP_NPOT_TEXTURES + ); + + resource_formats = vl_video_buffer_formats(pipe->screen, buffer_format); + if (!resource_formats) + return NULL; + + buffer_width = pot_buffers ? util_next_power_of_two(width) : align(width, MACROBLOCK_WIDTH); + buffer_height = pot_buffers ? util_next_power_of_two(height) : align(height, MACROBLOCK_HEIGHT); + + result = vl_video_buffer_create_ex + ( + pipe, buffer_width, buffer_height, 1, + chroma_format, resource_formats, PIPE_USAGE_STATIC + ); + if (result) + result->buffer_format = buffer_format; + + return result; +} + +struct pipe_video_buffer * +vl_video_buffer_create_ex(struct pipe_context *pipe, + unsigned width, unsigned height, unsigned depth, + enum pipe_video_chroma_format chroma_format, + const enum pipe_format resource_formats[VL_MAX_PLANES], + unsigned usage) +{ + struct vl_video_buffer *buffer; + struct pipe_resource templ; + unsigned i; + + assert(pipe); + + buffer = CALLOC_STRUCT(vl_video_buffer); + + buffer->base.context = pipe; + buffer->base.destroy = vl_video_buffer_destroy; + buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes; + buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components; + buffer->base.get_surfaces = vl_video_buffer_surfaces; + buffer->base.chroma_format = chroma_format; + buffer->base.width = width; + buffer->base.height = height; + buffer->num_planes = 1; + + memset(&templ, 0, sizeof(templ)); + templ.target = depth > 1 ? PIPE_TEXTURE_3D : PIPE_TEXTURE_2D; + templ.format = resource_formats[0]; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = depth; + templ.array_size = 1; + templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + templ.usage = usage; + + buffer->resources[0] = pipe->screen->resource_create(pipe->screen, &templ); + if (!buffer->resources[0]) + goto error; + + if (resource_formats[1] == PIPE_FORMAT_NONE) { + assert(chroma_format == PIPE_VIDEO_CHROMA_FORMAT_444); + assert(resource_formats[2] == PIPE_FORMAT_NONE); + return &buffer->base; + } else + buffer->num_planes = 2; + + templ.format = resource_formats[1]; + if (chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { + templ.width0 /= 2; + templ.height0 /= 2; + } else if (chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) { + templ.height0 /= 2; + } + + buffer->resources[1] = pipe->screen->resource_create(pipe->screen, &templ); + if (!buffer->resources[1]) + goto error; + + if (resource_formats[2] == PIPE_FORMAT_NONE) + return &buffer->base; + else + buffer->num_planes = 3; + + templ.format = resource_formats[2]; + buffer->resources[2] = pipe->screen->resource_create(pipe->screen, &templ); + if (!buffer->resources[2]) + goto error; + + return &buffer->base; + +error: + for (i = 0; i < VL_MAX_PLANES; ++i) + pipe_resource_reference(&buffer->resources[i], NULL); + FREE(buffer); + + return NULL; +} diff --git a/src/gallium/auxiliary/vl/vl_video_buffer.h b/src/gallium/auxiliary/vl/vl_video_buffer.h new file mode 100644 index 00000000000..291d15c1e9d --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_video_buffer.h @@ -0,0 +1,91 @@ +/************************************************************************** + * + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_ycbcr_buffer_h +#define vl_ycbcr_buffer_h + +#include <pipe/p_context.h> +#include <pipe/p_video_decoder.h> + +#include "vl_defines.h" + +/** + * implementation of a planar ycbcr buffer + */ + +/* planar buffer for vl data upload and manipulation */ +struct vl_video_buffer +{ + struct pipe_video_buffer base; + unsigned num_planes; + struct pipe_resource *resources[VL_MAX_PLANES]; + struct pipe_sampler_view *sampler_view_planes[VL_MAX_PLANES]; + struct pipe_sampler_view *sampler_view_components[VL_MAX_PLANES]; + struct pipe_surface *surfaces[VL_MAX_PLANES]; +}; + +/** + * get subformats for each plane + */ +const enum pipe_format * +vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format); + +/** + * get maximum size of video buffers + */ +unsigned +vl_video_buffer_max_size(struct pipe_screen *screen); + +/** + * check if video buffer format is supported for a codec/profile + * can be used as default implementation of screen->is_video_format_supported + */ +boolean +vl_video_buffer_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_video_profile profile); + +/** + * creates a video buffer, can be used as a standard implementation for pipe->create_video_buffer + */ +struct pipe_video_buffer * +vl_video_buffer_create(struct pipe_context *pipe, + enum pipe_format buffer_format, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height); + +/** + * extended create function, gets depth, usage and formats for each plane seperately + */ +struct pipe_video_buffer * +vl_video_buffer_create_ex(struct pipe_context *pipe, + unsigned width, unsigned height, unsigned depth, + enum pipe_video_chroma_format chroma_format, + const enum pipe_format resource_formats[VL_MAX_PLANES], + unsigned usage); + +#endif /* vl_ycbcr_buffer_h */ diff --git a/src/gallium/auxiliary/vl/vl_vlc.h b/src/gallium/auxiliary/vl/vl_vlc.h new file mode 100644 index 00000000000..e81b1e9afd2 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_vlc.h @@ -0,0 +1,140 @@ +/************************************************************************** + * + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +/** + * This file is based uppon slice_xvmc.c and vlc.h from the xine project, + * which in turn is based on mpeg2dec. The following is the original copyright: + * + * Copyright (C) 2000-2002 Michel Lespinasse <[email protected]> + * Copyright (C) 1999-2000 Aaron Holtzman <[email protected]> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef vl_vlc_h +#define vl_vlc_h + +#include "pipe/p_compiler.h" + +struct vl_vlc +{ + uint32_t buf; /* current 32 bit working set of buffer */ + int bits; /* used bits in working set */ + const uint8_t *ptr; /* buffer with stream data */ + const uint8_t *max; /* ptr+len of buffer */ +}; + +static INLINE void +vl_vlc_restart(struct vl_vlc *vlc) +{ + vlc->buf = (vlc->ptr[0] << 24) | (vlc->ptr[1] << 16) | (vlc->ptr[2] << 8) | vlc->ptr[3]; + vlc->bits = -16; + vlc->ptr += 4; +} + +static INLINE void +vl_vlc_init(struct vl_vlc *vlc, const uint8_t *data, unsigned len) +{ + vlc->ptr = data; + vlc->max = data + len; + vl_vlc_restart(vlc); +} + +static INLINE bool +vl_vlc_getbyte(struct vl_vlc *vlc) +{ + vlc->buf <<= 8; + vlc->buf |= vlc->ptr[0]; + vlc->ptr++; + return vlc->ptr < vlc->max; +} + +#define vl_vlc_getword(vlc, shift) \ +do { \ + (vlc)->buf |= (((vlc)->ptr[0] << 8) | (vlc)->ptr[1]) << (shift); \ + (vlc)->ptr += 2; \ +} while (0) + +/* make sure that there are at least 16 valid bits in bit_buf */ +#define vl_vlc_needbits(vlc) \ +do { \ + if ((vlc)->bits >= 0) { \ + vl_vlc_getword(vlc, (vlc)->bits); \ + (vlc)->bits -= 16; \ + } \ +} while (0) + +/* make sure that the full 32 bit of the buffer are valid */ +static INLINE void +vl_vlc_need32bits(struct vl_vlc *vlc) +{ + vl_vlc_needbits(vlc); + if (vlc->bits > -8) { + unsigned n = -vlc->bits; + vlc->buf <<= n; + vlc->buf |= *vlc->ptr << 8; + vlc->bits = -8; + vlc->ptr++; + } + if (vlc->bits > -16) { + unsigned n = -vlc->bits - 8; + vlc->buf <<= n; + vlc->buf |= *vlc->ptr; + vlc->bits = -16; + vlc->ptr++; + } +} + +/* remove num valid bits from bit_buf */ +#define vl_vlc_dumpbits(vlc, num) \ +do { \ + (vlc)->buf <<= (num); \ + (vlc)->bits += (num); \ +} while (0) + +/* take num bits from the high part of bit_buf and zero extend them */ +#define vl_vlc_ubits(vlc, num) (((uint32_t)((vlc)->buf)) >> (32 - (num))) + +/* take num bits from the high part of bit_buf and sign extend them */ +#define vl_vlc_sbits(vlc, num) (((int32_t)((vlc)->buf)) >> (32 - (num))) + +#endif /* vl_vlc_h */ diff --git a/src/gallium/auxiliary/vl/vl_zscan.c b/src/gallium/auxiliary/vl/vl_zscan.c new file mode 100644 index 00000000000..fde27f396c5 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_zscan.c @@ -0,0 +1,609 @@ +/************************************************************************** + * + * Copyright 2011 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <pipe/p_screen.h> +#include <pipe/p_context.h> + +#include <util/u_draw.h> +#include <util/u_sampler.h> +#include <util/u_inlines.h> +#include <util/u_memory.h> + +#include <tgsi/tgsi_ureg.h> + +#include <vl/vl_defines.h> +#include <vl/vl_types.h> + +#include "vl_zscan.h" +#include "vl_vertex_buffers.h" + +enum VS_OUTPUT +{ + VS_O_VPOS, + VS_O_VTEX +}; + +const int vl_zscan_linear[] = +{ + /* Linear scan pattern */ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23, + 24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39, + 40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55, + 56,57,58,59,60,61,62,63 +}; + +const int vl_zscan_normal[] = +{ + /* Zig-Zag scan pattern */ + 0, 1, 8,16, 9, 2, 3,10, + 17,24,32,25,18,11, 4, 5, + 12,19,26,33,40,48,41,34, + 27,20,13, 6, 7,14,21,28, + 35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46, + 53,60,61,54,47,55,62,63 +}; + +const int vl_zscan_alternate[] = +{ + /* Alternate scan pattern */ + 0, 8,16,24, 1, 9, 2,10, + 17,25,32,40,48,56,57,49, + 41,33,26,18, 3,11, 4,12, + 19,27,34,42,50,58,35,43, + 51,59,20,28, 5,13, 6,14, + 21,29,36,44,52,60,37,45, + 53,61,22,30, 7,15,23,31, + 38,46,54,62,39,47,55,63 +}; + +static void * +create_vert_shader(struct vl_zscan *zscan) +{ + struct ureg_program *shader; + + struct ureg_src scale; + struct ureg_src vrect, vpos, block_num; + + struct ureg_dst tmp; + struct ureg_dst o_vpos; + struct ureg_dst *o_vtex; + + signed i; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return NULL; + + o_vtex = MALLOC(zscan->num_channels * sizeof(struct ureg_dst)); + + scale = ureg_imm2f(shader, + (float)BLOCK_WIDTH / zscan->buffer_width, + (float)BLOCK_HEIGHT / zscan->buffer_height); + + vrect = ureg_DECL_vs_input(shader, VS_I_RECT); + vpos = ureg_DECL_vs_input(shader, VS_I_VPOS); + block_num = ureg_DECL_vs_input(shader, VS_I_BLOCK_NUM); + + tmp = ureg_DECL_temporary(shader); + + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS); + + for (i = 0; i < zscan->num_channels; ++i) + o_vtex[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX + i); + + /* + * o_vpos.xy = (vpos + vrect) * scale + * o_vpos.zw = 1.0f + * + * tmp.xy = InstanceID / blocks_per_line + * tmp.x = frac(tmp.x) + * tmp.y = floor(tmp.y) + * + * o_vtex.x = vrect.x / blocks_per_line + tmp.x + * o_vtex.y = vrect.y + * o_vtex.z = tmp.z * blocks_per_line / blocks_total + */ + ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), vpos, vrect); + ureg_MUL(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(tmp), scale); + ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f)); + + ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XW), ureg_scalar(block_num, TGSI_SWIZZLE_X), + ureg_imm1f(shader, 1.0f / zscan->blocks_per_line)); + + ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X)); + ureg_FLR(shader, ureg_writemask(tmp, TGSI_WRITEMASK_W), ureg_src(tmp)); + + for (i = 0; i < zscan->num_channels; ++i) { + ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), + ureg_imm1f(shader, 1.0f / (zscan->blocks_per_line * BLOCK_WIDTH) * (i - (signed)zscan->num_channels / 2))); + + ureg_MAD(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_X), vrect, + ureg_imm1f(shader, 1.0f / zscan->blocks_per_line), ureg_src(tmp)); + ureg_MOV(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_Y), vrect); + ureg_MOV(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_Z), vpos); + ureg_MUL(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_W), ureg_src(tmp), + ureg_imm1f(shader, (float)zscan->blocks_per_line / zscan->blocks_total)); + } + + ureg_release_temporary(shader, tmp); + ureg_END(shader); + + FREE(o_vtex); + + return ureg_create_shader_and_destroy(shader, zscan->pipe); +} + +static void * +create_frag_shader(struct vl_zscan *zscan) +{ + struct ureg_program *shader; + struct ureg_src *vtex; + + struct ureg_src samp_src, samp_scan, samp_quant; + + struct ureg_dst *tmp; + struct ureg_dst quant, fragment; + + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return NULL; + + vtex = MALLOC(zscan->num_channels * sizeof(struct ureg_src)); + tmp = MALLOC(zscan->num_channels * sizeof(struct ureg_dst)); + + for (i = 0; i < zscan->num_channels; ++i) + vtex[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX + i, TGSI_INTERPOLATE_LINEAR); + + samp_src = ureg_DECL_sampler(shader, 0); + samp_scan = ureg_DECL_sampler(shader, 1); + samp_quant = ureg_DECL_sampler(shader, 2); + + for (i = 0; i < zscan->num_channels; ++i) + tmp[i] = ureg_DECL_temporary(shader); + quant = ureg_DECL_temporary(shader); + + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * tmp.x = tex(vtex, 1) + * tmp.y = vtex.z + * fragment = tex(tmp, 0) * quant + */ + for (i = 0; i < zscan->num_channels; ++i) + ureg_TEX(shader, ureg_writemask(tmp[i], TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, vtex[i], samp_scan); + + for (i = 0; i < zscan->num_channels; ++i) + ureg_MOV(shader, ureg_writemask(tmp[i], TGSI_WRITEMASK_Y), ureg_scalar(vtex[i], TGSI_SWIZZLE_W)); + + for (i = 0; i < zscan->num_channels; ++i) { + ureg_TEX(shader, ureg_writemask(tmp[0], TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, ureg_src(tmp[i]), samp_src); + ureg_TEX(shader, ureg_writemask(quant, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_3D, vtex[i], samp_quant); + } + + ureg_MUL(shader, quant, ureg_src(quant), ureg_imm1f(shader, 16.0f)); + ureg_MUL(shader, fragment, ureg_src(tmp[0]), ureg_src(quant)); + + for (i = 0; i < zscan->num_channels; ++i) + ureg_release_temporary(shader, tmp[i]); + ureg_END(shader); + + FREE(vtex); + FREE(tmp); + + return ureg_create_shader_and_destroy(shader, zscan->pipe); +} + +static bool +init_shaders(struct vl_zscan *zscan) +{ + assert(zscan); + + zscan->vs = create_vert_shader(zscan); + if (!zscan->vs) + goto error_vs; + + zscan->fs = create_frag_shader(zscan); + if (!zscan->fs) + goto error_fs; + + return true; + +error_fs: + zscan->pipe->delete_vs_state(zscan->pipe, zscan->vs); + +error_vs: + return false; +} + +static void +cleanup_shaders(struct vl_zscan *zscan) +{ + assert(zscan); + + zscan->pipe->delete_vs_state(zscan->pipe, zscan->vs); + zscan->pipe->delete_fs_state(zscan->pipe, zscan->fs); +} + +static bool +init_state(struct vl_zscan *zscan) +{ + struct pipe_blend_state blend; + struct pipe_rasterizer_state rs_state; + struct pipe_sampler_state sampler; + unsigned i; + + assert(zscan); + + memset(&rs_state, 0, sizeof(rs_state)); + rs_state.gl_rasterization_rules = true; + zscan->rs_state = zscan->pipe->create_rasterizer_state(zscan->pipe, &rs_state); + if (!zscan->rs_state) + goto error_rs_state; + + memset(&blend, 0, sizeof blend); + + blend.independent_blend_enable = 0; + blend.rt[0].blend_enable = 0; + blend.rt[0].rgb_func = PIPE_BLEND_ADD; + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_func = PIPE_BLEND_ADD; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.logicop_enable = 0; + blend.logicop_func = PIPE_LOGICOP_CLEAR; + /* Needed to allow color writes to FB, even if blending disabled */ + blend.rt[0].colormask = PIPE_MASK_RGBA; + blend.dither = 0; + zscan->blend = zscan->pipe->create_blend_state(zscan->pipe, &blend); + if (!zscan->blend) + goto error_blend; + + for (i = 0; i < 3; ++i) { + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_REPEAT; + sampler.wrap_t = PIPE_TEX_WRAP_REPEAT; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + zscan->samplers[i] = zscan->pipe->create_sampler_state(zscan->pipe, &sampler); + if (!zscan->samplers[i]) + goto error_samplers; + } + + return true; + +error_samplers: + for (i = 0; i < 2; ++i) + if (zscan->samplers[i]) + zscan->pipe->delete_sampler_state(zscan->pipe, zscan->samplers[i]); + + zscan->pipe->delete_rasterizer_state(zscan->pipe, zscan->rs_state); + +error_blend: + zscan->pipe->delete_blend_state(zscan->pipe, zscan->blend); + +error_rs_state: + return false; +} + +static void +cleanup_state(struct vl_zscan *zscan) +{ + unsigned i; + + assert(zscan); + + for (i = 0; i < 3; ++i) + zscan->pipe->delete_sampler_state(zscan->pipe, zscan->samplers[i]); + + zscan->pipe->delete_rasterizer_state(zscan->pipe, zscan->rs_state); + zscan->pipe->delete_blend_state(zscan->pipe, zscan->blend); +} + +struct pipe_sampler_view * +vl_zscan_layout(struct pipe_context *pipe, const int layout[64], unsigned blocks_per_line) +{ + const unsigned total_size = blocks_per_line * BLOCK_WIDTH * BLOCK_HEIGHT; + + int patched_layout[64]; + + struct pipe_resource res_tmpl, *res; + struct pipe_sampler_view sv_tmpl, *sv; + struct pipe_transfer *buf_transfer; + unsigned x, y, i, pitch; + float *f; + + struct pipe_box rect = + { + 0, 0, 0, + BLOCK_WIDTH * blocks_per_line, + BLOCK_HEIGHT, + 1 + }; + + assert(pipe && layout && blocks_per_line); + + for (i = 0; i < 64; ++i) + patched_layout[layout[i]] = i; + + memset(&res_tmpl, 0, sizeof(res_tmpl)); + res_tmpl.target = PIPE_TEXTURE_2D; + res_tmpl.format = PIPE_FORMAT_R32_FLOAT; + res_tmpl.width0 = BLOCK_WIDTH * blocks_per_line; + res_tmpl.height0 = BLOCK_HEIGHT; + res_tmpl.depth0 = 1; + res_tmpl.array_size = 1; + res_tmpl.usage = PIPE_USAGE_IMMUTABLE; + res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW; + + res = pipe->screen->resource_create(pipe->screen, &res_tmpl); + if (!res) + goto error_resource; + + buf_transfer = pipe->get_transfer + ( + pipe, res, + 0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &rect + ); + if (!buf_transfer) + goto error_transfer; + + pitch = buf_transfer->stride / sizeof(float); + + f = pipe->transfer_map(pipe, buf_transfer); + if (!f) + goto error_map; + + for (i = 0; i < blocks_per_line; ++i) + for (y = 0; y < BLOCK_HEIGHT; ++y) + for (x = 0; x < BLOCK_WIDTH; ++x) { + float addr = patched_layout[x + y * BLOCK_WIDTH] + + i * BLOCK_WIDTH * BLOCK_HEIGHT; + + addr /= total_size; + + f[i * BLOCK_WIDTH + y * pitch + x] = addr; + } + + pipe->transfer_unmap(pipe, buf_transfer); + pipe->transfer_destroy(pipe, buf_transfer); + + memset(&sv_tmpl, 0, sizeof(sv_tmpl)); + u_sampler_view_default_template(&sv_tmpl, res, res->format); + sv = pipe->create_sampler_view(pipe, res, &sv_tmpl); + pipe_resource_reference(&res, NULL); + if (!sv) + goto error_map; + + return sv; + +error_map: + pipe->transfer_destroy(pipe, buf_transfer); + +error_transfer: + pipe_resource_reference(&res, NULL); + +error_resource: + return NULL; +} + +bool +vl_zscan_init(struct vl_zscan *zscan, struct pipe_context *pipe, + unsigned buffer_width, unsigned buffer_height, + unsigned blocks_per_line, unsigned blocks_total, + unsigned num_channels) +{ + assert(zscan && pipe); + + zscan->pipe = pipe; + zscan->buffer_width = buffer_width; + zscan->buffer_height = buffer_height; + zscan->num_channels = num_channels; + zscan->blocks_per_line = blocks_per_line; + zscan->blocks_total = blocks_total; + + if(!init_shaders(zscan)) + return false; + + if(!init_state(zscan)) { + cleanup_shaders(zscan); + return false; + } + + return true; +} + +void +vl_zscan_cleanup(struct vl_zscan *zscan) +{ + assert(zscan); + + cleanup_shaders(zscan); + cleanup_state(zscan); +} + +bool +vl_zscan_init_buffer(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer, + struct pipe_sampler_view *src, struct pipe_surface *dst) +{ + struct pipe_resource res_tmpl, *res; + struct pipe_sampler_view sv_tmpl; + + assert(zscan && buffer); + + memset(buffer, 0, sizeof(struct vl_zscan_buffer)); + + buffer->zscan = zscan; + + pipe_sampler_view_reference(&buffer->src, src); + + buffer->viewport.scale[0] = dst->width; + buffer->viewport.scale[1] = dst->height; + buffer->viewport.scale[2] = 1; + buffer->viewport.scale[3] = 1; + buffer->viewport.translate[0] = 0; + buffer->viewport.translate[1] = 0; + buffer->viewport.translate[2] = 0; + buffer->viewport.translate[3] = 0; + + buffer->fb_state.width = dst->width; + buffer->fb_state.height = dst->height; + buffer->fb_state.nr_cbufs = 1; + pipe_surface_reference(&buffer->fb_state.cbufs[0], dst); + + memset(&res_tmpl, 0, sizeof(res_tmpl)); + res_tmpl.target = PIPE_TEXTURE_3D; + res_tmpl.format = PIPE_FORMAT_R8_UNORM; + res_tmpl.width0 = BLOCK_WIDTH * zscan->blocks_per_line; + res_tmpl.height0 = BLOCK_HEIGHT; + res_tmpl.depth0 = 2; + res_tmpl.array_size = 1; + res_tmpl.usage = PIPE_USAGE_IMMUTABLE; + res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW; + + res = zscan->pipe->screen->resource_create(zscan->pipe->screen, &res_tmpl); + if (!res) + return false; + + memset(&sv_tmpl, 0, sizeof(sv_tmpl)); + u_sampler_view_default_template(&sv_tmpl, res, res->format); + sv_tmpl.swizzle_r = sv_tmpl.swizzle_g = sv_tmpl.swizzle_b = sv_tmpl.swizzle_a = TGSI_SWIZZLE_X; + buffer->quant = zscan->pipe->create_sampler_view(zscan->pipe, res, &sv_tmpl); + pipe_resource_reference(&res, NULL); + if (!buffer->quant) + return false; + + return true; +} + +void +vl_zscan_cleanup_buffer(struct vl_zscan_buffer *buffer) +{ + assert(buffer); + + pipe_sampler_view_reference(&buffer->src, NULL); + pipe_sampler_view_reference(&buffer->layout, NULL); + pipe_sampler_view_reference(&buffer->quant, NULL); + pipe_surface_reference(&buffer->fb_state.cbufs[0], NULL); +} + +void +vl_zscan_set_layout(struct vl_zscan_buffer *buffer, struct pipe_sampler_view *layout) +{ + assert(buffer); + assert(layout); + + pipe_sampler_view_reference(&buffer->layout, layout); +} + +void +vl_zscan_upload_quant(struct vl_zscan_buffer *buffer, const uint8_t matrix[64], bool intra) +{ + struct pipe_context *pipe; + struct pipe_transfer *buf_transfer; + unsigned x, y, i, pitch; + uint8_t *data; + + struct pipe_box rect = + { + 0, 0, intra ? 1 : 0, + BLOCK_WIDTH, + BLOCK_HEIGHT, + 1 + }; + + assert(buffer); + assert(matrix); + + pipe = buffer->zscan->pipe; + + rect.width *= buffer->zscan->blocks_per_line; + + buf_transfer = pipe->get_transfer + ( + pipe, buffer->quant->texture, + 0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &rect + ); + if (!buf_transfer) + goto error_transfer; + + pitch = buf_transfer->stride; + + data = pipe->transfer_map(pipe, buf_transfer); + if (!data) + goto error_map; + + for (i = 0; i < buffer->zscan->blocks_per_line; ++i) + for (y = 0; y < BLOCK_HEIGHT; ++y) + for (x = 0; x < BLOCK_WIDTH; ++x) + data[i * BLOCK_WIDTH + y * pitch + x] = matrix[x + y * BLOCK_WIDTH]; + + pipe->transfer_unmap(pipe, buf_transfer); + +error_map: + pipe->transfer_destroy(pipe, buf_transfer); + +error_transfer: + return; +} + +void +vl_zscan_render(struct vl_zscan_buffer *buffer, unsigned num_instances) +{ + struct vl_zscan *zscan; + + assert(buffer); + + zscan = buffer->zscan; + + zscan->pipe->bind_rasterizer_state(zscan->pipe, zscan->rs_state); + zscan->pipe->bind_blend_state(zscan->pipe, zscan->blend); + zscan->pipe->bind_fragment_sampler_states(zscan->pipe, 3, zscan->samplers); + zscan->pipe->set_framebuffer_state(zscan->pipe, &buffer->fb_state); + zscan->pipe->set_viewport_state(zscan->pipe, &buffer->viewport); + zscan->pipe->set_fragment_sampler_views(zscan->pipe, 3, &buffer->src); + zscan->pipe->bind_vs_state(zscan->pipe, zscan->vs); + zscan->pipe->bind_fs_state(zscan->pipe, zscan->fs); + util_draw_arrays_instanced(zscan->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances); +} diff --git a/src/gallium/auxiliary/vl/vl_zscan.h b/src/gallium/auxiliary/vl/vl_zscan.h new file mode 100644 index 00000000000..dd8a943bfb2 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_zscan.h @@ -0,0 +1,101 @@ +/************************************************************************** + * + * Copyright 2011 Christian König + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_zscan_h +#define vl_zscan_h + +#include <pipe/p_compiler.h> +#include <pipe/p_state.h> + +/* + * shader based zscan and quantification + * expect usage of vl_vertex_buffers as a todo list + */ +struct vl_zscan +{ + struct pipe_context *pipe; + + unsigned buffer_width; + unsigned buffer_height; + + unsigned num_channels; + + unsigned blocks_per_line; + unsigned blocks_total; + + void *rs_state; + void *blend; + + void *samplers[3]; + + void *vs, *fs; +}; + +struct vl_zscan_buffer +{ + struct vl_zscan *zscan; + + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state fb_state; + + struct pipe_sampler_view *src, *layout, *quant; + struct pipe_surface *dst; +}; + +extern const int vl_zscan_linear[]; +extern const int vl_zscan_normal[]; +extern const int vl_zscan_alternate[]; + +struct pipe_sampler_view * +vl_zscan_layout(struct pipe_context *pipe, const int layout[64], unsigned blocks_per_line); + +bool +vl_zscan_init(struct vl_zscan *zscan, struct pipe_context *pipe, + unsigned buffer_width, unsigned buffer_height, + unsigned blocks_per_line, unsigned blocks_total, + unsigned num_channels); + +void +vl_zscan_cleanup(struct vl_zscan *zscan); + +bool +vl_zscan_init_buffer(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer, + struct pipe_sampler_view *src, struct pipe_surface *dst); + +void +vl_zscan_cleanup_buffer(struct vl_zscan_buffer *buffer); + +void +vl_zscan_set_layout(struct vl_zscan_buffer *buffer, struct pipe_sampler_view *layout); + +void +vl_zscan_upload_quant(struct vl_zscan_buffer *buffer, const uint8_t matrix[64], bool intra); + +void +vl_zscan_render(struct vl_zscan_buffer *buffer, unsigned num_instances); + +#endif diff --git a/src/gallium/docs/source/context.rst b/src/gallium/docs/source/context.rst index 25a3245066c..3faf801b4b1 100644 --- a/src/gallium/docs/source/context.rst +++ b/src/gallium/docs/source/context.rst @@ -329,8 +329,15 @@ textured quad blitter.. The source and destination may be the same resource, but overlapping blits are not permitted. ``resource_resolve`` resolves a multisampled resource into a non-multisampled -one. Formats and dimensions must match. This function must be present if a driver +one. Their formats must match. This function must be present if a driver supports multisampling. +The region that is to be resolved is described by ``pipe_resolve_info``, which +provides a source and a destination rectangle. +The source rectangle may be vertically flipped, but otherwise the dimensions +of the rectangles must match, unless PIPE_CAP_SCALED_RESOLVE is supported, +in which case scaling and horizontal flipping are allowed as well. +The result of resolving depth/stencil values may be any function of the values at +the sample points, but returning the value of the centermost sample is preferred. The interfaces to these calls are likely to change to make it easier for a driver to batch multiple blits with the same source and diff --git a/src/gallium/drivers/i915/Makefile b/src/gallium/drivers/i915/Makefile index b3f387f9335..36197fbc93b 100644 --- a/src/gallium/drivers/i915/Makefile +++ b/src/gallium/drivers/i915/Makefile @@ -21,11 +21,13 @@ C_SOURCES = \ i915_screen.c \ i915_prim_emit.c \ i915_prim_vbuf.c \ + i915_query.c \ i915_resource.c \ i915_resource_texture.c \ i915_resource_buffer.c \ i915_fpc_emit.c \ i915_fpc_translate.c \ + i915_fpc_optimize.c \ i915_surface.c include ../../Makefile.template diff --git a/src/gallium/drivers/i915/SConscript b/src/gallium/drivers/i915/SConscript index 8f5deed64a9..76f597001fe 100644 --- a/src/gallium/drivers/i915/SConscript +++ b/src/gallium/drivers/i915/SConscript @@ -14,8 +14,10 @@ i915 = env.ConvenienceLibrary( 'i915_flush.c', 'i915_fpc_emit.c', 'i915_fpc_translate.c', + 'i915_fpc_optimize.c', 'i915_prim_emit.c', 'i915_prim_vbuf.c', + 'i915_query.c', 'i915_screen.c', 'i915_state.c', 'i915_state_derived.c', diff --git a/src/gallium/drivers/i915/TODO b/src/gallium/drivers/i915/TODO index fba180064c3..c26db198d20 100644 --- a/src/gallium/drivers/i915/TODO +++ b/src/gallium/drivers/i915/TODO @@ -26,5 +26,20 @@ Random list of problems with i915g: - src/xvmc/i915_structs.h in xf86-video-intel has a few more bits of various commands defined. Scavenge them and see what's useful. +- Do smarter remapping. Right now we send everything onto tex coords 0-7. + We could also use diffuse/specular and pack two sets of 2D coords in a single + 4D. Is it a big problem though? We're more limited by the # of texture + indirections and the # of instructions. + +- Leverage draw to enable more caps: + * PIPE_CAP_TGSI_INSTANCEID + * PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS + +- Finish front/back face. We need to add face support to lp_build_system_values_array and use it in draw_llvm.c. + +- Replace constants and immediates which are 0,1,-1 or a combination of those with a swizzle. + +- i915_delete_fs_state doesn't call draw_delete_fragment_shader. Why? + Other bugs can be found here: https://bugs.freedesktop.org/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&component=Drivers/Gallium/i915g diff --git a/src/gallium/drivers/i915/i915_batch.h b/src/gallium/drivers/i915/i915_batch.h index ce2691b2fd7..a1f8bcae802 100644 --- a/src/gallium/drivers/i915/i915_batch.h +++ b/src/gallium/drivers/i915/i915_batch.h @@ -29,6 +29,7 @@ #define I915_BATCH_H #include "i915_batchbuffer.h" +#include "i915_context.h" #define BEGIN_BATCH(dwords) \ @@ -49,11 +50,26 @@ #define FLUSH_BATCH(fence) \ i915_flush(i915, fence) - /************************************************************************ * i915_flush.c */ void i915_flush(struct i915_context *i915, struct pipe_fence_handle **fence); +/* + * Flush if the current color buf is idle and we have more than 256 vertices + * queued, or if the current color buf is busy and we have more than 4096 + * vertices queued. + */ +static INLINE void i915_flush_heuristically(struct i915_context* i915, + int num_vertex) +{ + struct i915_winsys *iws = i915->iws; + i915->vertices_since_last_flush += num_vertex; + if ( i915->vertices_since_last_flush > 4096 + || ( i915->vertices_since_last_flush > 256 && + !iws->buffer_is_busy(iws, i915->current.cbuf_bo)) ) + FLUSH_BATCH(NULL); +} + #endif diff --git a/src/gallium/drivers/i915/i915_clear.c b/src/gallium/drivers/i915/i915_clear.c index 4a97746e981..e1d6a749cdc 100644 --- a/src/gallium/drivers/i915/i915_clear.c +++ b/src/gallium/drivers/i915/i915_clear.c @@ -66,7 +66,7 @@ i915_clear_emit(struct pipe_context *pipe, unsigned buffers, const float *rgba, else clear_color = (u_color.ui & 0xffff) | (u_color.ui << 16); - util_pack_color(rgba, PIPE_FORMAT_B8G8R8A8_UNORM, &u_color); + util_pack_color(rgba, cbuf->format, &u_color); clear_color8888 = u_color.ui; } else clear_color = clear_color8888 = 0; @@ -120,6 +120,11 @@ i915_clear_emit(struct pipe_context *pipe, unsigned buffers, const float *rgba, OUT_BATCH_F(desty + height); OUT_BATCH_F(destx); OUT_BATCH_F(desty); + + /* Flush after clear, its expected to be a costly operation. + * This is not required, just a heuristic + */ + FLUSH_BATCH(NULL); } /** diff --git a/src/gallium/drivers/i915/i915_context.c b/src/gallium/drivers/i915/i915_context.c index 7a98ef73c1f..1b30309bb58 100644 --- a/src/gallium/drivers/i915/i915_context.c +++ b/src/gallium/drivers/i915/i915_context.c @@ -29,6 +29,7 @@ #include "i915_state.h" #include "i915_screen.h" #include "i915_surface.h" +#include "i915_query.h" #include "i915_batch.h" #include "i915_resource.h" @@ -53,13 +54,11 @@ i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) struct i915_context *i915 = i915_context(pipe); struct draw_context *draw = i915->draw; void *mapped_indices = NULL; - unsigned cbuf_dirty; /* * Ack vs contants here, helps ipers a lot. */ - cbuf_dirty = i915->dirty & I915_NEW_VS_CONSTANTS; i915->dirty &= ~I915_NEW_VS_CONSTANTS; if (i915->dirty) @@ -72,15 +71,13 @@ i915_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) mapped_indices = i915_buffer(i915->index_buffer.buffer)->data; draw_set_mapped_index_buffer(draw, mapped_indices); - if (cbuf_dirty) { - if (i915->constants[PIPE_SHADER_VERTEX]) - draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, - i915_buffer(i915->constants[PIPE_SHADER_VERTEX])->data, - (i915->current.num_user_constants[PIPE_SHADER_VERTEX] * - 4 * sizeof(float))); - else - draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0); - } + if (i915->constants[PIPE_SHADER_VERTEX]) + draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, + i915_buffer(i915->constants[PIPE_SHADER_VERTEX])->data, + (i915->current.num_user_constants[PIPE_SHADER_VERTEX] * + 4 * sizeof(float))); + else + draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0); /* * Do the drawing @@ -102,11 +99,11 @@ static void i915_destroy(struct pipe_context *pipe) struct i915_context *i915 = i915_context(pipe); int i; - draw_destroy(i915->draw); - if (i915->blitter) util_blitter_destroy(i915->blitter); - + + draw_destroy(i915->draw); + if(i915->batch) i915->iws->batchbuffer_destroy(i915->batch); @@ -150,6 +147,8 @@ i915_create_context(struct pipe_screen *screen, void *priv) /* init this before draw */ util_slab_create(&i915->transfer_pool, sizeof(struct pipe_transfer), 16, UTIL_SLAB_SINGLETHREADED); + util_slab_create(&i915->texture_transfer_pool, sizeof(struct i915_transfer), + 16, UTIL_SLAB_SINGLETHREADED); /* Batch stream debugging is a bit hacked up at the moment: */ @@ -170,9 +169,11 @@ i915_create_context(struct pipe_screen *screen, void *priv) i915_init_state_functions(i915); i915_init_flush_functions(i915); i915_init_resource_functions(i915); + i915_init_query_functions(i915); draw_install_aaline_stage(i915->draw, &i915->base); draw_install_aapoint_stage(i915->draw, &i915->base); + draw_enable_point_sprites(i915->draw, TRUE); /* augmented draw pipeline clobbers state functions */ i915_init_fixup_state_functions(i915); diff --git a/src/gallium/drivers/i915/i915_context.h b/src/gallium/drivers/i915/i915_context.h index 964948edc0e..84862351ffe 100644 --- a/src/gallium/drivers/i915/i915_context.h +++ b/src/gallium/drivers/i915/i915_context.h @@ -102,6 +102,8 @@ struct i915_fragment_shader struct tgsi_shader_info info; + struct draw_fragment_shader *draw_data; + uint *program; uint program_len; @@ -260,6 +262,9 @@ struct i915_context { int num_validation_buffers; struct util_slab_mempool transfer_pool; + struct util_slab_mempool texture_transfer_pool; + + int vertices_since_last_flush; /** blitter/hw-clear */ struct blitter_context* blitter; diff --git a/src/gallium/drivers/i915/i915_flush.c b/src/gallium/drivers/i915/i915_flush.c index b4e81147c4f..6d76afa9dbc 100644 --- a/src/gallium/drivers/i915/i915_flush.c +++ b/src/gallium/drivers/i915/i915_flush.c @@ -77,4 +77,5 @@ void i915_flush(struct i915_context *i915, struct pipe_fence_handle **fence) i915->static_dirty = ~0; /* kernel emits flushes in between batchbuffers */ i915->flush_dirty = 0; + i915->vertices_since_last_flush = 0; } diff --git a/src/gallium/drivers/i915/i915_fpc.h b/src/gallium/drivers/i915/i915_fpc.h index 2f0f99d0468..b760bc461a1 100644 --- a/src/gallium/drivers/i915/i915_fpc.h +++ b/src/gallium/drivers/i915/i915_fpc.h @@ -33,10 +33,15 @@ #include "i915_context.h" #include "i915_reg.h" +#include "pipe/p_shader_tokens.h" +#include "tgsi/tgsi_parse.h" #define I915_PROGRAM_SIZE 192 +/* Use those indices for pos/face routing, must be >= I915_TEX_UNITS */ +#define I915_SEMANTIC_POS 10 +#define I915_SEMANTIC_FACE 11 /** @@ -67,13 +72,13 @@ struct i915_fp_compile { uint temp_flag; /**< Tracks temporary regs which are in use */ uint utemp_flag; /**< Tracks TYPE_U temporary regs which are in use */ + uint register_phases[16]; uint nr_tex_indirect; uint nr_tex_insn; uint nr_alu_insn; uint nr_decl_insn; boolean error; /**< Set if i915_program_error() is called */ - uint wpos_tex; uint NumNativeInstructions; uint NumNativeAluInstructions; uint NumNativeTexInstructions; @@ -204,4 +209,90 @@ extern void i915_program_error(struct i915_fp_compile *p, const char *msg, ...); +/*====================================================================== + * i915_fpc_optimize.c + */ + + +struct i915_src_register +{ + unsigned File : 4; /* TGSI_FILE_ */ + unsigned Indirect : 1; /* BOOL */ + unsigned Dimension : 1; /* BOOL */ + int Index : 16; /* SINT */ + unsigned SwizzleX : 3; /* TGSI_SWIZZLE_ */ + unsigned SwizzleY : 3; /* TGSI_SWIZZLE_ */ + unsigned SwizzleZ : 3; /* TGSI_SWIZZLE_ */ + unsigned SwizzleW : 3; /* TGSI_SWIZZLE_ */ + unsigned Absolute : 1; /* BOOL */ + unsigned Negate : 1; /* BOOL */ +}; + +/* Additional swizzle supported in i915 */ +#define TGSI_SWIZZLE_ZERO 4 +#define TGSI_SWIZZLE_ONE 5 + +struct i915_dst_register +{ + unsigned File : 4; /* TGSI_FILE_ */ + unsigned WriteMask : 4; /* TGSI_WRITEMASK_ */ + unsigned Indirect : 1; /* BOOL */ + unsigned Dimension : 1; /* BOOL */ + int Index : 16; /* SINT */ + unsigned Padding : 6; +}; + + +struct i915_full_dst_register +{ + struct i915_dst_register Register; +/* + struct tgsi_src_register Indirect; + struct tgsi_dimension Dimension; + struct tgsi_src_register DimIndirect; +*/ +}; + +struct i915_full_src_register +{ + struct i915_src_register Register; +/* + struct tgsi_src_register Indirect; + struct tgsi_dimension Dimension; + struct tgsi_src_register DimIndirect; +*/ +}; + +struct i915_full_instruction +{ + struct tgsi_instruction Instruction; +/* + struct tgsi_instruction_predicate Predicate; + struct tgsi_instruction_label Label; +*/ + struct tgsi_instruction_texture Texture; + struct i915_full_dst_register Dst[1]; + struct i915_full_src_register Src[3]; +}; + + +union i915_full_token +{ + struct tgsi_token Token; + struct tgsi_full_declaration FullDeclaration; + struct tgsi_full_immediate FullImmediate; + struct i915_full_instruction FullInstruction; + struct tgsi_full_property FullProperty; +}; + +struct i915_token_list +{ + union i915_full_token* Tokens; + unsigned NumTokens; +}; + +extern struct i915_token_list* i915_optimize(const struct tgsi_token *tokens); + +extern void i915_optimize_free(struct i915_token_list* tokens); + #endif diff --git a/src/gallium/drivers/i915/i915_fpc_emit.c b/src/gallium/drivers/i915/i915_fpc_emit.c index 76c24d2b2fd..c4a42df7882 100644 --- a/src/gallium/drivers/i915/i915_fpc_emit.c +++ b/src/gallium/drivers/i915/i915_fpc_emit.c @@ -67,7 +67,7 @@ i915_get_temp(struct i915_fp_compile *p) { int bit = ffs(~p->temp_flag); if (!bit) { - i915_program_error(p, "i915_get_temp: out of temporaries\n"); + i915_program_error(p, "i915_get_temp: out of temporaries"); return 0; } @@ -92,7 +92,7 @@ i915_get_utemp(struct i915_fp_compile * p) { int bit = ffs(~p->utemp_flag); if (!bit) { - i915_program_error(p, "i915_get_utemp: out of temporaries\n"); + i915_program_error(p, "i915_get_utemp: out of temporaries"); return 0; } @@ -128,9 +128,13 @@ i915_emit_decl(struct i915_fp_compile *p, else return reg; - *(p->decl++) = (D0_DCL | D0_DEST(reg) | d0_flags); - *(p->decl++) = D1_MBZ; - *(p->decl++) = D2_MBZ; + if (p->decl< p->declarations + I915_PROGRAM_SIZE) { + *(p->decl++) = (D0_DCL | D0_DEST(reg) | d0_flags); + *(p->decl++) = D1_MBZ; + *(p->decl++) = D2_MBZ; + } + else + i915_program_error(p, "Out of declarations"); p->nr_decl_insn++; return reg; @@ -187,9 +191,16 @@ i915_emit_arith(struct i915_fp_compile * p, p->utemp_flag = old_utemp_flag; /* restore */ } - *(p->csr++) = (op | A0_DEST(dest) | mask | saturate | A0_SRC0(src0)); - *(p->csr++) = (A1_SRC0(src0) | A1_SRC1(src1)); - *(p->csr++) = (A2_SRC1(src1) | A2_SRC2(src2)); + if (p->csr< p->program + I915_PROGRAM_SIZE) { + *(p->csr++) = (op | A0_DEST(dest) | mask | saturate | A0_SRC0(src0)); + *(p->csr++) = (A1_SRC0(src0) | A1_SRC1(src1)); + *(p->csr++) = (A2_SRC1(src1) | A2_SRC2(src2)); + } + else + i915_program_error(p, "Out of instructions"); + + if (GET_UREG_TYPE(dest) == REG_TYPE_R) + p->register_phases[GET_UREG_NR(dest)] = p->nr_tex_indirect; p->nr_alu_insn++; return dest; @@ -245,17 +256,31 @@ uint i915_emit_texld( struct i915_fp_compile *p, assert(GET_UREG_TYPE(dest) != REG_TYPE_CONST); assert(dest == UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest))); - /* is the sampler coord a texcoord input reg? */ - if (GET_UREG_TYPE(coord) != REG_TYPE_T) { - p->nr_tex_indirect++; - } + /* Output register being oC or oD defines a phase boundary */ + if (GET_UREG_TYPE(dest) == REG_TYPE_OC || + GET_UREG_TYPE(dest) == REG_TYPE_OD) + p->nr_tex_indirect++; - *(p->csr++) = (opcode | - T0_DEST( dest ) | - T0_SAMPLER( sampler )); + /* Reading from an r# register whose contents depend on output of the + * current phase defines a phase boundary. + */ + if (GET_UREG_TYPE(coord) == REG_TYPE_R && + p->register_phases[GET_UREG_NR(coord)] == p->nr_tex_indirect) + p->nr_tex_indirect++; + + if (p->csr< p->program + I915_PROGRAM_SIZE) { + *(p->csr++) = (opcode | + T0_DEST( dest ) | + T0_SAMPLER( sampler )); + + *(p->csr++) = T1_ADDRESS_REG( coord ); + *(p->csr++) = T2_MBZ; + } + else + i915_program_error(p, "Out of instructions"); - *(p->csr++) = T1_ADDRESS_REG( coord ); - *(p->csr++) = T2_MBZ; + if (GET_UREG_TYPE(dest) == REG_TYPE_R) + p->register_phases[GET_UREG_NR(dest)] = p->nr_tex_indirect; p->nr_tex_insn++; } @@ -293,7 +318,7 @@ i915_emit_const1f(struct i915_fp_compile * p, float c0) } } - i915_program_error(p, "i915_emit_const1f: out of constants\n"); + i915_program_error(p, "i915_emit_const1f: out of constants"); return 0; } @@ -313,6 +338,8 @@ i915_emit_const2f(struct i915_fp_compile * p, float c0, float c1) if (c1 == 1.0) return swizzle(i915_emit_const1f(p, c0), X, ONE, Z, W); + // XXX emit swizzle here for 0, 1, -1 and any combination thereof + // we can use swizzle + neg for that for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { if (ifs->constant_flags[reg] == 0xf || ifs->constant_flags[reg] == I915_CONSTFLAG_USER) @@ -329,12 +356,10 @@ i915_emit_const2f(struct i915_fp_compile * p, float c0, float c1) } } - i915_program_error(p, "i915_emit_const2f: out of constants\n"); + i915_program_error(p, "i915_emit_const2f: out of constants"); return 0; } - - uint i915_emit_const4f(struct i915_fp_compile * p, float c0, float c1, float c2, float c3) @@ -342,6 +367,8 @@ i915_emit_const4f(struct i915_fp_compile * p, struct i915_fragment_shader *ifs = p->shader; unsigned reg; + // XXX emit swizzle here for 0, 1, -1 and any combination thereof + // we can use swizzle + neg for that for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { if (ifs->constant_flags[reg] == 0xf && ifs->constants[reg][0] == c0 && @@ -363,7 +390,7 @@ i915_emit_const4f(struct i915_fp_compile * p, } } - i915_program_error(p, "i915_emit_const4f: out of constants\n"); + i915_program_error(p, "i915_emit_const4f: out of constants"); return 0; } diff --git a/src/gallium/drivers/i915/i915_fpc_optimize.c b/src/gallium/drivers/i915/i915_fpc_optimize.c new file mode 100644 index 00000000000..2b739e9ccb8 --- /dev/null +++ b/src/gallium/drivers/i915/i915_fpc_optimize.c @@ -0,0 +1,259 @@ +/************************************************************************** + * + * Copyright 2011 The Chromium OS authors. + * 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 GOOGLE AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include "i915_reg.h" +#include "i915_context.h" +#include "i915_fpc.h" + +#include "pipe/p_shader_tokens.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_string.h" +#include "tgsi/tgsi_parse.h" +#include "tgsi/tgsi_dump.h" + +static boolean same_dst_reg(struct i915_full_dst_register* d1, struct i915_full_dst_register* d2) +{ + return (d1->Register.File == d2->Register.File && + d1->Register.Indirect == d2->Register.Indirect && + d1->Register.Dimension == d2->Register.Dimension && + d1->Register.Index == d2->Register.Index); +} + +static boolean same_src_reg(struct i915_full_src_register* d1, struct i915_full_src_register* d2) +{ + return (d1->Register.File == d2->Register.File && + d1->Register.Indirect == d2->Register.Indirect && + d1->Register.Dimension == d2->Register.Dimension && + d1->Register.Index == d2->Register.Index && + d1->Register.Absolute == d2->Register.Absolute && + d1->Register.Negate == d2->Register.Negate); +} + +static boolean is_unswizzled(struct i915_full_src_register* r, + unsigned write_mask) +{ + if ( write_mask & TGSI_WRITEMASK_X && r->Register.SwizzleX != TGSI_SWIZZLE_X) + return FALSE; + if ( write_mask & TGSI_WRITEMASK_Y && r->Register.SwizzleY != TGSI_SWIZZLE_Y) + return FALSE; + if ( write_mask & TGSI_WRITEMASK_Z && r->Register.SwizzleZ != TGSI_SWIZZLE_Z) + return FALSE; + if ( write_mask & TGSI_WRITEMASK_W && r->Register.SwizzleW != TGSI_SWIZZLE_W) + return FALSE; + return TRUE; +} + +static boolean op_commutes(unsigned opcode) +{ + if (opcode == TGSI_OPCODE_ADD) return TRUE; + if (opcode == TGSI_OPCODE_MUL) return TRUE; + return FALSE; +} + +static unsigned op_neutral_element(unsigned opcode) +{ + if (opcode == TGSI_OPCODE_ADD) + return TGSI_SWIZZLE_ZERO; + if (opcode == TGSI_OPCODE_MUL) + return TGSI_SWIZZLE_ONE; + + debug_printf("Unknown opcode %d\n",opcode); + return TGSI_SWIZZLE_ZERO; +} + +/* + * Sets the swizzle to the neutral element for the operation for the bits + * of writemask which are set, swizzle to identity otherwise. + */ +static void set_neutral_element_swizzle(struct i915_full_src_register* r, + unsigned write_mask, + unsigned neutral) +{ + if ( write_mask & TGSI_WRITEMASK_X ) + r->Register.SwizzleX = neutral; + else + r->Register.SwizzleX = TGSI_SWIZZLE_X; + + if ( write_mask & TGSI_WRITEMASK_Y ) + r->Register.SwizzleY = neutral; + else + r->Register.SwizzleY = TGSI_SWIZZLE_Y; + + if ( write_mask & TGSI_WRITEMASK_Z ) + r->Register.SwizzleZ = neutral; + else + r->Register.SwizzleZ = TGSI_SWIZZLE_Z; + + if ( write_mask & TGSI_WRITEMASK_W ) + r->Register.SwizzleW = neutral; + else + r->Register.SwizzleW = TGSI_SWIZZLE_W; +} + +/* + * Optimize away things like: + * MUL OUT[0].xyz, TEMP[1], TEMP[2] + * MOV OUT[0].w, TEMP[2] + * into: + * MUL OUT[0].xyzw, TEMP[1].xyz1, TEMP[2] + * This is useful for optimizing texenv. + */ +static void i915_fpc_optimize_mov_after_alu(union i915_full_token* current, union i915_full_token* next) +{ + if ( current->Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION && + next->Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION && + op_commutes(current->FullInstruction.Instruction.Opcode) && + current->FullInstruction.Instruction.Saturate == next->FullInstruction.Instruction.Saturate && + next->FullInstruction.Instruction.Opcode == TGSI_OPCODE_MOV && + same_dst_reg(&next->FullInstruction.Dst[0], &next->FullInstruction.Dst[0]) && + same_src_reg(&next->FullInstruction.Src[0], ¤t->FullInstruction.Src[1]) && + is_unswizzled(¤t->FullInstruction.Src[0], current->FullInstruction.Dst[0].Register.WriteMask) && + is_unswizzled(¤t->FullInstruction.Src[1], current->FullInstruction.Dst[0].Register.WriteMask) && + is_unswizzled(&next->FullInstruction.Src[0], next->FullInstruction.Dst[0].Register.WriteMask) ) + { + next->FullInstruction.Instruction.Opcode = TGSI_OPCODE_NOP; + + set_neutral_element_swizzle(¤t->FullInstruction.Src[1], 0, 0); + set_neutral_element_swizzle(¤t->FullInstruction.Src[0], + next->FullInstruction.Dst[0].Register.WriteMask, + op_neutral_element(current->FullInstruction.Instruction.Opcode)); + + current->FullInstruction.Dst[0].Register.WriteMask = current->FullInstruction.Dst[0].Register.WriteMask | + next->FullInstruction.Dst[0].Register.WriteMask; + return; + } + + if ( current->Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION && + next->Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION && + op_commutes(current->FullInstruction.Instruction.Opcode) && + current->FullInstruction.Instruction.Saturate == next->FullInstruction.Instruction.Saturate && + next->FullInstruction.Instruction.Opcode == TGSI_OPCODE_MOV && + same_dst_reg(&next->FullInstruction.Dst[0], &next->FullInstruction.Dst[0]) && + same_src_reg(&next->FullInstruction.Src[0], ¤t->FullInstruction.Src[0]) && + is_unswizzled(¤t->FullInstruction.Src[0], current->FullInstruction.Dst[0].Register.WriteMask) && + is_unswizzled(¤t->FullInstruction.Src[1], current->FullInstruction.Dst[0].Register.WriteMask) && + is_unswizzled(&next->FullInstruction.Src[0], next->FullInstruction.Dst[0].Register.WriteMask) ) + { + next->FullInstruction.Instruction.Opcode = TGSI_OPCODE_NOP; + + set_neutral_element_swizzle(¤t->FullInstruction.Src[0], 0, 0); + set_neutral_element_swizzle(¤t->FullInstruction.Src[1], + next->FullInstruction.Dst[0].Register.WriteMask, + op_neutral_element(current->FullInstruction.Instruction.Opcode)); + + current->FullInstruction.Dst[0].Register.WriteMask = current->FullInstruction.Dst[0].Register.WriteMask | + next->FullInstruction.Dst[0].Register.WriteMask; + return; + } +} + +static void copy_src_reg(struct i915_src_register* o, const struct tgsi_src_register* i) +{ + o->File = i->File; + o->Indirect = i->Indirect; + o->Dimension = i->Dimension; + o->Index = i->Index; + o->SwizzleX = i->SwizzleX; + o->SwizzleY = i->SwizzleY; + o->SwizzleZ = i->SwizzleZ; + o->SwizzleW = i->SwizzleW; + o->Absolute = i->Absolute; + o->Negate = i->Negate; +} + +static void copy_dst_reg(struct i915_dst_register* o, const struct tgsi_dst_register* i) +{ + o->File = i->File; + o->WriteMask = i->WriteMask; + o->Indirect = i->Indirect; + o->Dimension = i->Dimension; + o->Index = i->Index; +} + +static void copy_instruction(struct i915_full_instruction* o, const struct tgsi_full_instruction* i) +{ + memcpy(&o->Instruction, &i->Instruction, sizeof(o->Instruction)); + memcpy(&o->Texture, &i->Texture, sizeof(o->Texture)); + + copy_dst_reg(&o->Dst[0].Register, &i->Dst[0].Register); + + copy_src_reg(&o->Src[0].Register, &i->Src[0].Register); + copy_src_reg(&o->Src[1].Register, &i->Src[1].Register); + copy_src_reg(&o->Src[2].Register, &i->Src[2].Register); +} + +static void copy_token(union i915_full_token* o, union tgsi_full_token* i) +{ + if (i->Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION) + memcpy(o, i, sizeof(*o)); + else + copy_instruction(&o->FullInstruction, &i->FullInstruction); + +} + +struct i915_token_list* i915_optimize(const struct tgsi_token *tokens) +{ + struct i915_token_list *out_tokens = MALLOC(sizeof(struct i915_token_list)); + struct tgsi_parse_context parse; + int i = 0; + + out_tokens->NumTokens = 0; + + /* Count the tokens */ + tgsi_parse_init( &parse, tokens ); + while( !tgsi_parse_end_of_tokens( &parse ) ) { + tgsi_parse_token( &parse ); + out_tokens->NumTokens++; + } + tgsi_parse_free (&parse); + + /* Allocate our tokens */ + out_tokens->Tokens = MALLOC(sizeof(union i915_full_token) * out_tokens->NumTokens); + + tgsi_parse_init( &parse, tokens ); + while( !tgsi_parse_end_of_tokens( &parse ) ) { + tgsi_parse_token( &parse ); + copy_token(&out_tokens->Tokens[i] , &parse.FullToken); + + if (i > 0) + i915_fpc_optimize_mov_after_alu(&out_tokens->Tokens[i-1], &out_tokens->Tokens[i]); + + i++; + } + tgsi_parse_free (&parse); + + return out_tokens; +} + +void i915_optimize_free(struct i915_token_list* tokens) +{ + free(tokens->Tokens); + free(tokens); +} + + diff --git a/src/gallium/drivers/i915/i915_fpc_translate.c b/src/gallium/drivers/i915/i915_fpc_translate.c index 27f100843bf..a4ea9127976 100644 --- a/src/gallium/drivers/i915/i915_fpc_translate.c +++ b/src/gallium/drivers/i915/i915_fpc_translate.c @@ -41,6 +41,9 @@ #include "draw/draw_vertex.h" +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /** * Simple pass-through fragment shader to use when we don't have @@ -72,19 +75,33 @@ static unsigned passthrough[] = /* 1, -1/3!, 1/5!, -1/7! */ -static const float sin_constants[4] = { 1.0, +static const float scs_sin_constants[4] = { 1.0, -1.0f / (3 * 2 * 1), 1.0f / (5 * 4 * 3 * 2 * 1), -1.0f / (7 * 6 * 5 * 4 * 3 * 2 * 1) }; /* 1, -1/2!, 1/4!, -1/6! */ -static const float cos_constants[4] = { 1.0, +static const float scs_cos_constants[4] = { 1.0, -1.0f / (2 * 1), 1.0f / (4 * 3 * 2 * 1), -1.0f / (6 * 5 * 4 * 3 * 2 * 1) }; +/* 2*pi, -(2*pi)^3/3!, (2*pi)^5/5!, -(2*pi)^7/7! */ +static const float sin_constants[4] = { 2.0 * M_PI, + -8.0f * M_PI * M_PI * M_PI / (3 * 2 * 1), + 32.0f * M_PI * M_PI * M_PI * M_PI * M_PI / (5 * 4 * 3 * 2 * 1), + -128.0f * M_PI * M_PI * M_PI * M_PI * M_PI * M_PI * M_PI / (7 * 6 * 5 * 4 * 3 * 2 * 1) +}; + +/* 1, -(2*pi)^2/2!, (2*pi)^4/4!, -(2*pi)^6/6! */ +static const float cos_constants[4] = { 1.0, + -4.0f * M_PI * M_PI / (2 * 1), + 16.0f * M_PI * M_PI * M_PI * M_PI / (4 * 3 * 2 * 1), + -64.0f * M_PI * M_PI * M_PI * M_PI * M_PI * M_PI / (6 * 5 * 4 * 3 * 2 * 1) +}; + /** @@ -155,7 +172,7 @@ static uint get_mapping(struct i915_fragment_shader* fs, int unit) */ static uint src_vector(struct i915_fp_compile *p, - const struct tgsi_full_src_register *source, + const struct i915_full_src_register *source, struct i915_fragment_shader* fs) { uint index = source->Register.Index; @@ -185,12 +202,12 @@ src_vector(struct i915_fp_compile *p, switch (sem_name) { case TGSI_SEMANTIC_POSITION: - debug_printf("SKIP SEM POS\n"); - /* - assert(p->wpos_tex != -1); - src = i915_emit_decl(p, REG_TYPE_T, p->wpos_tex, D0_CHANNEL_ALL); - */ - break; + { + /* for fragcoord */ + int real_tex_unit = get_mapping(fs, I915_SEMANTIC_POS); + src = i915_emit_decl(p, REG_TYPE_T, T_TEX0 + real_tex_unit, D0_CHANNEL_ALL); + break; + } case TGSI_SEMANTIC_COLOR: if (sem_ind == 0) { src = i915_emit_decl(p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL); @@ -212,6 +229,13 @@ src_vector(struct i915_fp_compile *p, src = i915_emit_decl(p, REG_TYPE_T, T_TEX0 + real_tex_unit, D0_CHANNEL_ALL); break; } + case TGSI_SEMANTIC_FACE: + { + /* for back/front faces */ + int real_tex_unit = get_mapping(fs, I915_SEMANTIC_FACE); + src = i915_emit_decl(p, REG_TYPE_T, T_TEX0 + real_tex_unit, D0_CHANNEL_X); + break; + } default: i915_program_error(p, "Bad source->Index"); return 0; @@ -237,7 +261,6 @@ src_vector(struct i915_fp_compile *p, source->Register.SwizzleZ, source->Register.SwizzleW); - /* There's both negate-all-components and per-component negation. * Try to handle both here. */ @@ -252,6 +275,9 @@ src_vector(struct i915_fp_compile *p, /* XXX enable these assertions, or fix things */ assert(!source->Register.Absolute); #endif + if (source->Register.Absolute) + debug_printf("Unhandled absolute value\n"); + return src; } @@ -261,7 +287,7 @@ src_vector(struct i915_fp_compile *p, */ static uint get_result_vector(struct i915_fp_compile *p, - const struct tgsi_full_dst_register *dest) + const struct i915_full_dst_register *dest) { switch (dest->Register.File) { case TGSI_FILE_OUTPUT: @@ -290,7 +316,7 @@ get_result_vector(struct i915_fp_compile *p, * Compute flags for saturation and writemask. */ static uint -get_result_flags(const struct tgsi_full_instruction *inst) +get_result_flags(const struct i915_full_instruction *inst) { const uint writeMask = inst->Dst[0].Register.WriteMask; @@ -352,7 +378,7 @@ translate_tex_src_target(struct i915_fp_compile *p, uint tex) */ static void emit_tex(struct i915_fp_compile *p, - const struct tgsi_full_instruction *inst, + const struct i915_full_instruction *inst, uint opcode, struct i915_fragment_shader* fs) { @@ -378,7 +404,7 @@ emit_tex(struct i915_fp_compile *p, */ static void emit_simple_arith(struct i915_fp_compile *p, - const struct tgsi_full_instruction *inst, + const struct i915_full_instruction *inst, uint opcode, uint numArgs, struct i915_fragment_shader* fs) { @@ -403,11 +429,11 @@ emit_simple_arith(struct i915_fp_compile *p, /** As above, but swap the first two src regs */ static void emit_simple_arith_swap2(struct i915_fp_compile *p, - const struct tgsi_full_instruction *inst, + const struct i915_full_instruction *inst, uint opcode, uint numArgs, struct i915_fragment_shader* fs) { - struct tgsi_full_instruction inst2; + struct i915_full_instruction inst2; assert(numArgs == 2); @@ -419,23 +445,19 @@ emit_simple_arith_swap2(struct i915_fp_compile *p, emit_simple_arith(p, &inst2, opcode, numArgs, fs); } - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - /* * Translate TGSI instruction to i915 instruction. * * Possible concerns: * + * DDX, DDY -- return 0 * SIN, COS -- could use another taylor step? * LIT -- results seem a little different to sw mesa * LOG -- different to mesa on negative numbers, but this is conformant. */ static void i915_translate_instruction(struct i915_fp_compile *p, - const struct tgsi_full_instruction *inst, + const struct i915_full_instruction *inst, struct i915_fragment_shader *fs) { uint writemask; @@ -477,13 +499,6 @@ i915_translate_instruction(struct i915_fp_compile *p, i915_emit_arith(p, A0_MOD, tmp, A0_DEST_CHANNEL_X, 0, tmp, 0, 0); - /* By choosing different taylor constants, could get rid of this mul: - */ - i915_emit_arith(p, - A0_MUL, - tmp, A0_DEST_CHANNEL_X, 0, - tmp, i915_emit_const1f(p, (float) (M_PI * 2.0)), 0); - /* * t0.xy = MUL x.xx11, x.x1111 ; x^2, x, 1, 1 * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, 1 @@ -516,6 +531,18 @@ i915_translate_instruction(struct i915_fp_compile *p, i915_emit_const4fv(p, cos_constants), 0); break; + case TGSI_OPCODE_DDX: + case TGSI_OPCODE_DDY: + /* XXX We just output 0 here */ + debug_printf("Punting DDX/DDX\n"); + src0 = get_result_vector(p, &inst->Dst[0]); + i915_emit_arith(p, + A0_MOV, + get_result_vector(p, &inst->Dst[0]), + get_result_flags(inst), 0, + swizzle(src0, ZERO, ZERO, ZERO, ZERO), 0, 0); + break; + case TGSI_OPCODE_DP2: src0 = src_vector(p, &inst->Src[0], fs); src1 = src_vector(p, &inst->Src[1], fs); @@ -701,6 +728,9 @@ i915_translate_instruction(struct i915_fp_compile *p, emit_simple_arith(p, inst, A0_MUL, 2, fs); break; + case TGSI_OPCODE_NOP: + break; + case TGSI_OPCODE_POW: src0 = src_vector(p, &inst->Src[0], fs); src1 = src_vector(p, &inst->Src[1], fs); @@ -754,9 +784,9 @@ i915_translate_instruction(struct i915_fp_compile *p, * t0.xy = MUL x.xx11, x.x1111 ; x^2, x, 1, 1 * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, x * t1 = MUL t0.xyyw t0.yz11 ; x^7 x^5 x^3 x - * scs.x = DP4 t1, sin_constants + * scs.x = DP4 t1, scs_sin_constants * t1 = MUL t0.xxz1 t0.z111 ; x^6 x^4 x^2 1 - * scs.y = DP4 t1, cos_constants + * scs.y = DP4 t1, scs_cos_constants */ i915_emit_arith(p, A0_MUL, @@ -791,7 +821,7 @@ i915_translate_instruction(struct i915_fp_compile *p, get_result_vector(p, &inst->Dst[0]), A0_DEST_CHANNEL_Y, 0, swizzle(tmp1, W, Z, Y, X), - i915_emit_const4fv(p, sin_constants), 0); + i915_emit_const4fv(p, scs_sin_constants), 0); } if (writemask & TGSI_WRITEMASK_X) { @@ -806,7 +836,7 @@ i915_translate_instruction(struct i915_fp_compile *p, get_result_vector(p, &inst->Dst[0]), A0_DEST_CHANNEL_X, 0, swizzle(tmp, ONE, Z, Y, X), - i915_emit_const4fv(p, cos_constants), 0); + i915_emit_const4fv(p, scs_cos_constants), 0); } break; @@ -853,13 +883,6 @@ i915_translate_instruction(struct i915_fp_compile *p, i915_emit_arith(p, A0_MOD, tmp, A0_DEST_CHANNEL_X, 0, tmp, 0, 0); - /* By choosing different taylor constants, could get rid of this mul: - */ - i915_emit_arith(p, - A0_MUL, - tmp, A0_DEST_CHANNEL_X, 0, - tmp, i915_emit_const1f(p, (float) (M_PI * 2.0)), 0); - /* * t0.xy = MUL x.xx11, x.x1111 ; x^2, x, 1, 1 * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, x @@ -907,7 +930,7 @@ i915_translate_instruction(struct i915_fp_compile *p, break; case TGSI_OPCODE_SNE: - /* if we're neither < nor > then we're != */ + /* if we're < or > then we're != */ src0 = src_vector(p, &inst->Src[0], fs); src1 = src_vector(p, &inst->Src[1], fs); tmp = i915_get_utemp(p); @@ -1024,105 +1047,107 @@ i915_translate_instruction(struct i915_fp_compile *p, } -/** - * Translate TGSI fragment shader into i915 hardware instructions. - * \param p the translation state - * \param tokens the TGSI token array - */ -static void -i915_translate_instructions(struct i915_fp_compile *p, - const struct tgsi_token *tokens, - struct i915_fragment_shader *fs) +static void i915_translate_token(struct i915_fp_compile *p, + const union i915_full_token* token, + struct i915_fragment_shader *fs) { struct i915_fragment_shader *ifs = p->shader; - struct tgsi_parse_context parse; - - tgsi_parse_init( &parse, tokens ); - - while( !tgsi_parse_end_of_tokens( &parse ) ) { - - tgsi_parse_token( &parse ); + switch( token->Token.Type ) { + case TGSI_TOKEN_TYPE_PROPERTY: + /* + * We only support one cbuf, but we still need to ignore the property + * correctly so we don't hit the assert at the end of the switch case. + */ + assert(token->FullProperty.Property.PropertyName == + TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS); + break; - switch( parse.FullToken.Token.Type ) { - case TGSI_TOKEN_TYPE_PROPERTY: - /* - * We only support one cbuf, but we still need to ignore the property - * correctly so we don't hit the assert at the end of the switch case. - */ - assert(parse.FullToken.FullProperty.Property.PropertyName == - TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS); - break; - case TGSI_TOKEN_TYPE_DECLARATION: - if (parse.FullToken.FullDeclaration.Declaration.File - == TGSI_FILE_CONSTANT) { - uint i; - for (i = parse.FullToken.FullDeclaration.Range.First; - i <= parse.FullToken.FullDeclaration.Range.Last; - i++) { - assert(ifs->constant_flags[i] == 0x0); - ifs->constant_flags[i] = I915_CONSTFLAG_USER; - ifs->num_constants = MAX2(ifs->num_constants, i + 1); - } + case TGSI_TOKEN_TYPE_DECLARATION: + if (token->FullDeclaration.Declaration.File + == TGSI_FILE_CONSTANT) { + uint i; + for (i = token->FullDeclaration.Range.First; + i <= token->FullDeclaration.Range.Last; + i++) { + assert(ifs->constant_flags[i] == 0x0); + ifs->constant_flags[i] = I915_CONSTFLAG_USER; + ifs->num_constants = MAX2(ifs->num_constants, i + 1); } - else if (parse.FullToken.FullDeclaration.Declaration.File - == TGSI_FILE_TEMPORARY) { - uint i; - for (i = parse.FullToken.FullDeclaration.Range.First; - i <= parse.FullToken.FullDeclaration.Range.Last; - i++) { - assert(i < I915_MAX_TEMPORARY); + } + else if (token->FullDeclaration.Declaration.File + == TGSI_FILE_TEMPORARY) { + uint i; + for (i = token->FullDeclaration.Range.First; + i <= token->FullDeclaration.Range.Last; + i++) { + if (i >= I915_MAX_TEMPORARY) + debug_printf("Too many temps (%d)\n",i); + else /* XXX just use shader->info->file_mask[TGSI_FILE_TEMPORARY] */ p->temp_flag |= (1 << i); /* mark temp as used */ - } } - break; + } + break; - case TGSI_TOKEN_TYPE_IMMEDIATE: - { - const struct tgsi_full_immediate *imm - = &parse.FullToken.FullImmediate; - const uint pos = p->num_immediates++; - uint j; - assert( imm->Immediate.NrTokens <= 4 + 1 ); - for (j = 0; j < imm->Immediate.NrTokens - 1; j++) { - p->immediates[pos][j] = imm->u[j].Float; - } + case TGSI_TOKEN_TYPE_IMMEDIATE: + { + const struct tgsi_full_immediate *imm + = &token->FullImmediate; + const uint pos = p->num_immediates++; + uint j; + assert( imm->Immediate.NrTokens <= 4 + 1 ); + for (j = 0; j < imm->Immediate.NrTokens - 1; j++) { + p->immediates[pos][j] = imm->u[j].Float; } - break; + } + break; - case TGSI_TOKEN_TYPE_INSTRUCTION: - if (p->first_instruction) { - /* resolve location of immediates */ - uint i, j; - for (i = 0; i < p->num_immediates; i++) { - /* find constant slot for this immediate */ - for (j = 0; j < I915_MAX_CONSTANT; j++) { - if (ifs->constant_flags[j] == 0x0) { - memcpy(ifs->constants[j], - p->immediates[i], - 4 * sizeof(float)); - /*printf("immediate %d maps to const %d\n", i, j);*/ - ifs->constant_flags[j] = 0xf; /* all four comps used */ - p->immediates_map[i] = j; - ifs->num_constants = MAX2(ifs->num_constants, j + 1); - break; - } + case TGSI_TOKEN_TYPE_INSTRUCTION: + if (p->first_instruction) { + /* resolve location of immediates */ + uint i, j; + for (i = 0; i < p->num_immediates; i++) { + /* find constant slot for this immediate */ + for (j = 0; j < I915_MAX_CONSTANT; j++) { + if (ifs->constant_flags[j] == 0x0) { + memcpy(ifs->constants[j], + p->immediates[i], + 4 * sizeof(float)); + /*printf("immediate %d maps to const %d\n", i, j);*/ + ifs->constant_flags[j] = 0xf; /* all four comps used */ + p->immediates_map[i] = j; + ifs->num_constants = MAX2(ifs->num_constants, j + 1); + break; } } - - p->first_instruction = FALSE; } - i915_translate_instruction(p, &parse.FullToken.FullInstruction, fs); - break; - - default: - assert( 0 ); + p->first_instruction = FALSE; } - } /* while */ + i915_translate_instruction(p, &token->FullInstruction, fs); + break; + + default: + assert( 0 ); + } - tgsi_parse_free (&parse); +} + +/** + * Translate TGSI fragment shader into i915 hardware instructions. + * \param p the translation state + * \param tokens the TGSI token array + */ +static void +i915_translate_instructions(struct i915_fp_compile *p, + const struct i915_token_list *tokens, + struct i915_fragment_shader *fs) +{ + int i; + for(i = 0; i<tokens->NumTokens; i++) { + i915_translate_token(p, &tokens->Tokens[i], fs); + } } @@ -1144,6 +1169,8 @@ i915_init_compile(struct i915_context *i915, ifs->num_constants = 0; memset(ifs->constant_flags, 0, sizeof(ifs->constant_flags)); + memset(&p->register_phases, 0, sizeof(p->register_phases)); + for (i = 0; i < I915_TEX_UNITS; i++) ifs->generic_mapping[i] = -1; @@ -1161,8 +1188,6 @@ i915_init_compile(struct i915_context *i915, p->temp_flag = ~0x0 << I915_MAX_TEMPORARY; p->utemp_flag = ~0x7; - p->wpos_tex = -1; - /* initialize the first program word */ *(p->decl++) = _3DSTATE_PIXEL_SHADER_PROGRAM; @@ -1181,7 +1206,7 @@ i915_fini_compile(struct i915_context *i915, struct i915_fp_compile *p) unsigned long decl_size = (unsigned long) (p->decl - p->declarations); if (p->nr_tex_indirect > I915_MAX_TEX_INDIRECT) - i915_program_error(p, "Exceeded max nr indirect texture lookups"); + debug_printf("Exceeded max nr indirect texture lookups\n"); if (p->nr_tex_insn > I915_MAX_TEX_INSN) i915_program_error(p, "Exceeded max TEX instructions"); @@ -1234,40 +1259,6 @@ i915_fini_compile(struct i915_context *i915, struct i915_fp_compile *p) } -/** - * Find an unused texture coordinate slot to use for fragment WPOS. - * Update p->fp->wpos_tex with the result (-1 if no used texcoord slot is found). - */ -static void -i915_find_wpos_space(struct i915_fp_compile *p) -{ -#if 0 - const uint inputs - = p->shader->inputs_read | (1 << TGSI_ATTRIB_POS); /*XXX hack*/ - uint i; - - p->wpos_tex = -1; - - if (inputs & (1 << TGSI_ATTRIB_POS)) { - for (i = 0; i < I915_TEX_UNITS; i++) { - if ((inputs & (1 << (TGSI_ATTRIB_TEX0 + i))) == 0) { - p->wpos_tex = i; - return; - } - } - - i915_program_error(p, "No free texcoord for wpos value"); - } -#else - if (p->shader->info.input_semantic_name[0] == TGSI_SEMANTIC_POSITION) { - /* frag shader using the fragment position input */ -#if 0 - assert(0); -#endif - } -#endif -} - @@ -1300,6 +1291,7 @@ i915_translate_fragment_program( struct i915_context *i915, { struct i915_fp_compile *p; const struct tgsi_token *tokens = fs->state.tokens; + struct i915_token_list* i_tokens; #if 0 tgsi_dump(tokens, 0); @@ -1314,10 +1306,11 @@ i915_translate_fragment_program( struct i915_context *i915, } p = i915_init_compile(i915, fs); - i915_find_wpos_space(p); - i915_translate_instructions(p, tokens, fs); + i_tokens = i915_optimize(tokens); + i915_translate_instructions(p, i_tokens, fs); i915_fixup_depth_write(p); i915_fini_compile(i915, p); + i915_optimize_free(i_tokens); } diff --git a/src/gallium/drivers/i915/i915_prim_emit.c b/src/gallium/drivers/i915/i915_prim_emit.c index 85656cd7846..1acde97d4bd 100644 --- a/src/gallium/drivers/i915/i915_prim_emit.c +++ b/src/gallium/drivers/i915/i915_prim_emit.c @@ -166,6 +166,8 @@ emit_prim( struct draw_stage *stage, for (i = 0; i < nr; i++) emit_hw_vertex(i915, prim->v[i]); + + i915_flush_heuristically(i915, nr); } diff --git a/src/gallium/drivers/i915/i915_prim_vbuf.c b/src/gallium/drivers/i915/i915_prim_vbuf.c index 79db3b650eb..d8ae1de2963 100644 --- a/src/gallium/drivers/i915/i915_prim_vbuf.c +++ b/src/gallium/drivers/i915/i915_prim_vbuf.c @@ -487,6 +487,7 @@ draw_arrays_fallback(struct vbuf_render *render, draw_arrays_generate_indices(render, start, nr, i915_render->fallback); + i915_flush_heuristically(i915, nr_indices); out: return; } @@ -534,6 +535,7 @@ i915_vbuf_render_draw_arrays(struct vbuf_render *render, nr); OUT_BATCH(start); /* Beginning vertex index */ + i915_flush_heuristically(i915, nr); out: return; } @@ -657,6 +659,7 @@ i915_vbuf_render_draw_elements(struct vbuf_render *render, save_nr_indices, i915_render->fallback); + i915_flush_heuristically(i915, nr_indices); out: return; } diff --git a/src/gallium/drivers/i915/i915_query.c b/src/gallium/drivers/i915/i915_query.c new file mode 100644 index 00000000000..c886df74bad --- /dev/null +++ b/src/gallium/drivers/i915/i915_query.c @@ -0,0 +1,86 @@ +/************************************************************************** + * + * Copyright 2011 The Chromium OS authors. + * 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 GOOGLE AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +/* Fake occlusion queries which return 0, it's better than crashing */ + +#include "pipe/p_compiler.h" + +#include "util/u_memory.h" + +#include "i915_context.h" +#include "i915_query.h" + +struct i915_query +{ + unsigned query; +}; + +static struct pipe_query *i915_create_query(struct pipe_context *ctx, + unsigned query_type) +{ + struct i915_query *query = CALLOC_STRUCT( i915_query ); + + return (struct pipe_query *)query; +} + +static void i915_destroy_query(struct pipe_context *ctx, + struct pipe_query *query) +{ + FREE(query); +} + +static void i915_begin_query(struct pipe_context *ctx, + struct pipe_query *query) +{ +} + +static void i915_end_query(struct pipe_context *ctx, struct pipe_query *query) +{ +} + +static boolean i915_get_query_result(struct pipe_context *ctx, + struct pipe_query *query, + boolean wait, + void *vresult) +{ + uint64_t *result = (uint64_t*)vresult; + + /* 2* viewport Max */ + *result = 512*1024*1024; + return TRUE; +} + +void +i915_init_query_functions(struct i915_context *i915) +{ + i915->base.create_query = i915_create_query; + i915->base.destroy_query = i915_destroy_query; + i915->base.begin_query = i915_begin_query; + i915->base.end_query = i915_end_query; + i915->base.get_query_result = i915_get_query_result; +} + diff --git a/src/gallium/drivers/i915/i915_query.h b/src/gallium/drivers/i915/i915_query.h new file mode 100644 index 00000000000..2c689ea6b1c --- /dev/null +++ b/src/gallium/drivers/i915/i915_query.h @@ -0,0 +1,36 @@ +/************************************************************************** + * + * Copyright 2011 The Chromium OS authors. + * 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 GOOGLE AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef I915_QUERY_H +#define I915_QUERY_H + +struct i915_context; +struct pipe_context; + +void i915_init_query_functions( struct i915_context *i915 ); + +#endif /* I915_QUERY_H */ diff --git a/src/gallium/drivers/i915/i915_resource.c b/src/gallium/drivers/i915/i915_resource.c index 7f52ba11d61..b4719af1fb6 100644 --- a/src/gallium/drivers/i915/i915_resource.c +++ b/src/gallium/drivers/i915/i915_resource.c @@ -7,12 +7,12 @@ static struct pipe_resource * i915_resource_create(struct pipe_screen *screen, - const struct pipe_resource *template) + const struct pipe_resource *template) { if (template->target == PIPE_BUFFER) return i915_buffer_create(screen, template); else - return i915_texture_create(screen, template); + return i915_texture_create(screen, template, FALSE); } diff --git a/src/gallium/drivers/i915/i915_resource.h b/src/gallium/drivers/i915/i915_resource.h index c15ecdfc22a..14eed2c4a79 100644 --- a/src/gallium/drivers/i915/i915_resource.h +++ b/src/gallium/drivers/i915/i915_resource.h @@ -45,6 +45,15 @@ struct i915_buffer { boolean free_on_destroy; }; + +/* Texture transfer. */ +struct i915_transfer { + /* Base class. */ + struct pipe_transfer b; + struct pipe_resource *staging_texture; +}; + + #define I915_MAX_TEXTURE_2D_LEVELS 12 /* max 2048x2048 */ #define I915_MAX_TEXTURE_3D_LEVELS 9 /* max 256x256x256 */ @@ -101,7 +110,8 @@ static INLINE struct i915_buffer *i915_buffer(struct pipe_resource *resource) struct pipe_resource * i915_texture_create(struct pipe_screen *screen, - const struct pipe_resource *template); + const struct pipe_resource *template, + boolean force_untiled); struct pipe_resource * i915_texture_from_handle(struct pipe_screen * screen, diff --git a/src/gallium/drivers/i915/i915_resource_texture.c b/src/gallium/drivers/i915/i915_resource_texture.c index b74b19d0fe4..0b6424f8d16 100644 --- a/src/gallium/drivers/i915/i915_resource_texture.c +++ b/src/gallium/drivers/i915/i915_resource_texture.c @@ -37,6 +37,7 @@ #include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_rect.h" #include "i915_context.h" #include "i915_resource.h" @@ -710,7 +711,7 @@ i915_texture_destroy(struct pipe_screen *screen, FREE(tex); } -static struct pipe_transfer * +static struct pipe_transfer * i915_texture_get_transfer(struct pipe_context *pipe, struct pipe_resource *resource, unsigned level, @@ -719,19 +720,45 @@ i915_texture_get_transfer(struct pipe_context *pipe, { struct i915_context *i915 = i915_context(pipe); struct i915_texture *tex = i915_texture(resource); - struct pipe_transfer *transfer = util_slab_alloc(&i915->transfer_pool); + struct i915_transfer *transfer = util_slab_alloc(&i915->texture_transfer_pool); + boolean use_staging_texture = FALSE; if (transfer == NULL) return NULL; - transfer->resource = resource; - transfer->level = level; - transfer->usage = usage; - transfer->box = *box; - transfer->stride = tex->stride; - /* FIXME: layer_stride */ + transfer->b.resource = resource; + transfer->b.level = level; + transfer->b.usage = usage; + transfer->b.box = *box; + transfer->b.stride = tex->stride; + transfer->staging_texture = NULL; + /* XXX: handle depth textures everyhwere*/ + transfer->b.layer_stride = 0; + transfer->b.data = NULL; + + /* if we use staging transfers, only support textures we can render to, + * because we need that for u_blitter */ + if (i915->blitter && + i915_is_format_supported(NULL, /* screen */ + transfer->b.resource->format, + 0, /* target */ + 1, /* sample count */ + PIPE_BIND_RENDER_TARGET) && + (usage & PIPE_TRANSFER_WRITE) && + !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED))) + use_staging_texture = TRUE; + + use_staging_texture = FALSE; + + if (use_staging_texture) { + /* + * Allocate the untiled staging texture. + * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map() + */ + transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE); + } - return transfer; + return (struct pipe_transfer*)transfer; } static void @@ -739,17 +766,33 @@ i915_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct i915_context *i915 = i915_context(pipe); - util_slab_free(&i915->transfer_pool, transfer); + struct i915_transfer *itransfer = (struct i915_transfer*)transfer; + + if ((itransfer->staging_texture) && + (transfer->usage & PIPE_TRANSFER_WRITE)) { + struct pipe_box sbox; + + u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox); + pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level, + itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z, + itransfer->staging_texture, + 0, &sbox); + pipe->flush(pipe, NULL); + pipe_resource_reference(&itransfer->staging_texture, NULL); + } + + util_slab_free(&i915->texture_transfer_pool, itransfer); } static void * i915_texture_transfer_map(struct pipe_context *pipe, struct pipe_transfer *transfer) { - struct pipe_resource *resource = transfer->resource; - struct i915_texture *tex = i915_texture(resource); + struct i915_transfer *itransfer = (struct i915_transfer*)transfer; + struct pipe_resource *resource = itransfer->b.resource; + struct i915_texture *tex = NULL; struct i915_winsys *iws = i915_screen(pipe->screen)->iws; - struct pipe_box *box = &transfer->box; + struct pipe_box *box = &itransfer->b.box; enum pipe_format format = resource->format; unsigned offset; char *map; @@ -757,18 +800,25 @@ i915_texture_transfer_map(struct pipe_context *pipe, if (resource->target != PIPE_TEXTURE_3D && resource->target != PIPE_TEXTURE_CUBE) assert(box->z == 0); - offset = i915_texture_offset(tex, transfer->level, box->z); - /* TODO this is a sledgehammer */ - pipe->flush(pipe, NULL); + if (itransfer->staging_texture) { + tex = i915_texture(itransfer->staging_texture); + } else { + /* TODO this is a sledgehammer */ + tex = i915_texture(resource); + pipe->flush(pipe, NULL); + } + + offset = i915_texture_offset(tex, itransfer->b.level, box->z); map = iws->buffer_map(iws, tex->buffer, - (transfer->usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE); - if (map == NULL) + (itransfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE); + if (map == NULL) { return NULL; + } return map + offset + - box->y / util_format_get_blockheight(format) * transfer->stride + + box->y / util_format_get_blockheight(format) * itransfer->b.stride + box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); } @@ -776,14 +826,106 @@ static void i915_texture_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { - struct i915_texture *tex = i915_texture(transfer->resource); + struct i915_transfer *itransfer = (struct i915_transfer*)transfer; + struct i915_texture *tex = i915_texture(itransfer->b.resource); struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; + + if (itransfer->staging_texture) + tex = i915_texture(itransfer->staging_texture); + iws->buffer_unmap(iws, tex->buffer); } +static void i915_transfer_inline_write( struct pipe_context *pipe, + struct pipe_resource *resource, + unsigned level, + unsigned usage, + const struct pipe_box *box, + const void *data, + unsigned stride, + unsigned layer_stride) +{ + struct pipe_transfer *transfer = NULL; + struct i915_transfer *itransfer = NULL; + const uint8_t *src_data = data; + unsigned i; + + transfer = pipe->get_transfer(pipe, + resource, + level, + usage, + box ); + if (transfer == NULL) + goto out; + + itransfer = (struct i915_transfer*)transfer; + + if (itransfer->staging_texture) { + struct i915_texture *tex = i915_texture(itransfer->staging_texture); + enum pipe_format format = tex->b.b.format; + struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; + size_t offset; + size_t size; + + offset = i915_texture_offset(tex, transfer->level, transfer->box.z); + + for (i = 0; i < box->depth; i++) { + if (!tex->b.b.last_level && + tex->b.b.width0 == transfer->box.width) { + unsigned nby = util_format_get_nblocksy(format, transfer->box.y); + assert(!offset); + assert(!transfer->box.x); + assert(tex->stride == transfer->stride); + + offset += tex->stride * nby; + size = util_format_get_2d_size(format, transfer->stride, + transfer->box.height); + iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); + + } else { + unsigned nby = util_format_get_nblocksy(format, transfer->box.y); + int i; + offset += util_format_get_stride(format, transfer->box.x); + size = transfer->stride; + + for (i = 0; i < nby; i++) { + iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); + offset += tex->stride; + } + } + offset += layer_stride; + } + } else { + uint8_t *map = pipe_transfer_map(pipe, &itransfer->b); + if (map == NULL) + goto nomap; + + for (i = 0; i < box->depth; i++) { + util_copy_rect(map, + resource->format, + itransfer->b.stride, /* bytes */ + 0, 0, + box->width, + box->height, + src_data, + stride, /* bytes */ + 0, 0); + map += itransfer->b.layer_stride; + src_data += layer_stride; + } +nomap: + if (map) + pipe_transfer_unmap(pipe, &itransfer->b); + } + +out: + if (itransfer) + pipe_transfer_destroy(pipe, &itransfer->b); +} -struct u_resource_vtbl i915_texture_vtbl = + +struct u_resource_vtbl i915_texture_vtbl = { i915_texture_get_handle, /* get_handle */ i915_texture_destroy, /* resource_destroy */ @@ -792,7 +934,7 @@ struct u_resource_vtbl i915_texture_vtbl = i915_texture_transfer_map, /* transfer_map */ u_default_transfer_flush_region, /* transfer_flush_region */ i915_texture_transfer_unmap, /* transfer_unmap */ - u_default_transfer_inline_write /* transfer_inline_write */ + i915_transfer_inline_write /* transfer_inline_write */ }; @@ -800,7 +942,8 @@ struct u_resource_vtbl i915_texture_vtbl = struct pipe_resource * i915_texture_create(struct pipe_screen *screen, - const struct pipe_resource *template) + const struct pipe_resource *template, + boolean force_untiled) { struct i915_screen *is = i915_screen(screen); struct i915_winsys *iws = is->iws; @@ -815,7 +958,10 @@ i915_texture_create(struct pipe_screen *screen, pipe_reference_init(&tex->b.b.reference, 1); tex->b.b.screen = screen; - tex->tiling = i915_texture_tiling(is, tex); + if (force_untiled) + tex->tiling = I915_TILE_NONE; + else + tex->tiling = i915_texture_tiling(is, tex); if (is->is_i945) { if (!i945_texture_layout(tex)) @@ -836,7 +982,7 @@ i915_texture_create(struct pipe_screen *screen, buf_usage = I915_NEW_TEXTURE; tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy, - &tex->tiling, buf_usage); + &tex->tiling, buf_usage); if (!tex->buffer) goto fail; diff --git a/src/gallium/drivers/i915/i915_screen.c b/src/gallium/drivers/i915/i915_screen.c index 5b3af2519fc..c108c702983 100644 --- a/src/gallium/drivers/i915/i915_screen.c +++ b/src/gallium/drivers/i915/i915_screen.c @@ -109,17 +109,17 @@ i915_get_param(struct pipe_screen *screen, enum pipe_cap cap) case PIPE_CAP_ANISOTROPIC_FILTER: case PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE: case PIPE_CAP_NPOT_TEXTURES: + case PIPE_CAP_POINT_SPRITE: case PIPE_CAP_PRIMITIVE_RESTART: /* draw module */ case PIPE_CAP_TEXTURE_MIRROR_REPEAT: case PIPE_CAP_TEXTURE_SHADOW_MAP: case PIPE_CAP_TWO_SIDED_STENCIL: + case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: return 1; /* Features that should be supported (boolean caps). */ /* XXX: Just test the code */ case PIPE_CAP_BLEND_EQUATION_SEPARATE: - /* XXX: No code but hw supports it */ - case PIPE_CAP_POINT_SPRITE: /* Also lie about these when asked to (needed for GLSL / GL 2.0) */ return is->debug.lie ? 1 : 0; @@ -129,7 +129,6 @@ i915_get_param(struct pipe_screen *screen, enum pipe_cap cap) case PIPE_CAP_INDEP_BLEND_ENABLE: case PIPE_CAP_INDEP_BLEND_FUNC: case PIPE_CAP_TGSI_INSTANCEID: - case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: case PIPE_CAP_SHADER_STENCIL_EXPORT: case PIPE_CAP_TEXTURE_MIRROR_CLAMP: case PIPE_CAP_TEXTURE_SWIZZLE: @@ -256,7 +255,7 @@ i915_get_paramf(struct pipe_screen *screen, enum pipe_cap cap) } } -static boolean +boolean i915_is_format_supported(struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, @@ -266,7 +265,10 @@ i915_is_format_supported(struct pipe_screen *screen, static const enum pipe_format tex_supported[] = { PIPE_FORMAT_B8G8R8A8_UNORM, PIPE_FORMAT_B8G8R8X8_UNORM, + PIPE_FORMAT_R8G8B8A8_UNORM, + PIPE_FORMAT_R8G8B8X8_UNORM, PIPE_FORMAT_B5G6R5_UNORM, + PIPE_FORMAT_B10G10R10A2_UNORM, PIPE_FORMAT_L8_UNORM, PIPE_FORMAT_A8_UNORM, PIPE_FORMAT_I8_UNORM, @@ -285,7 +287,12 @@ i915_is_format_supported(struct pipe_screen *screen, }; static const enum pipe_format render_supported[] = { PIPE_FORMAT_B8G8R8A8_UNORM, + PIPE_FORMAT_R8G8B8A8_UNORM, PIPE_FORMAT_B5G6R5_UNORM, + PIPE_FORMAT_B10G10R10A2_UNORM, + PIPE_FORMAT_L8_UNORM, + PIPE_FORMAT_A8_UNORM, + PIPE_FORMAT_I8_UNORM, PIPE_FORMAT_NONE /* list terminator */ }; static const enum pipe_format depth_supported[] = { diff --git a/src/gallium/drivers/i915/i915_screen.h b/src/gallium/drivers/i915/i915_screen.h index cfc585b5350..9f2004eb942 100644 --- a/src/gallium/drivers/i915/i915_screen.h +++ b/src/gallium/drivers/i915/i915_screen.h @@ -65,5 +65,11 @@ i915_screen(struct pipe_screen *pscreen) return (struct i915_screen *) pscreen; } +boolean +i915_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned tex_usage); #endif /* I915_SCREEN_H */ diff --git a/src/gallium/drivers/i915/i915_state.c b/src/gallium/drivers/i915/i915_state.c index 1b57c5776f2..2812de1fe80 100644 --- a/src/gallium/drivers/i915/i915_state.c +++ b/src/gallium/drivers/i915/i915_state.c @@ -146,6 +146,7 @@ i915_create_blend_state(struct pipe_context *pipe, if (blend->dither) cso_data->LIS5 |= S5_COLOR_DITHER_ENABLE; + /* XXX here take the target fixup into account */ if ((blend->rt[0].colormask & PIPE_MASK_R) == 0) cso_data->LIS5 |= S5_WRITEDISABLE_RED; @@ -243,10 +244,10 @@ i915_create_sampler_state(struct pipe_context *pipe, /* Shadow: */ - if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { cso->state[0] |= (SS2_SHADOW_ENABLE | - i915_translate_compare_func(sampler->compare_func)); + i915_translate_shadow_compare_func(sampler->compare_func)); minFilt = FILTER_4X4_FLAT; magFilt = FILTER_4X4_FLAT; @@ -466,6 +467,7 @@ i915_create_fs_state(struct pipe_context *pipe, if (!ifs) return NULL; + ifs->draw_data = draw_create_fragment_shader(i915->draw, templ); ifs->state.tokens = tgsi_dup_tokens(templ->tokens); tgsi_scan_shader(templ->tokens, &ifs->info); @@ -495,6 +497,8 @@ i915_bind_fs_state(struct pipe_context *pipe, void *shader) i915->fs = (struct i915_fragment_shader*) shader; + draw_bind_fragment_shader(i915->draw, (i915->fs ? i915->fs->draw_data : NULL)); + i915->dirty |= I915_NEW_FS; } @@ -503,12 +507,14 @@ void i915_delete_fs_state(struct pipe_context *pipe, void *shader) { struct i915_fragment_shader *ifs = (struct i915_fragment_shader *) shader; - if (ifs->program) + if (ifs->program) { FREE(ifs->program); + ifs->program = NULL; + FREE((struct tgsi_token *)ifs->state.tokens); + ifs->state.tokens = NULL; + } ifs->program_len = 0; - FREE((struct tgsi_token *)ifs->state.tokens); - FREE(ifs); } diff --git a/src/gallium/drivers/i915/i915_state_derived.c b/src/gallium/drivers/i915/i915_state_derived.c index 392ba191140..e01f16e715c 100644 --- a/src/gallium/drivers/i915/i915_state_derived.c +++ b/src/gallium/drivers/i915/i915_state_derived.c @@ -33,6 +33,7 @@ #include "i915_context.h" #include "i915_state.h" #include "i915_debug.h" +#include "i915_fpc.h" #include "i915_reg.h" static uint find_mapping(const struct i915_fragment_shader* fs, int unit) @@ -58,12 +59,12 @@ static void calculate_vertex_layout(struct i915_context *i915) const struct i915_fragment_shader *fs = i915->fs; const enum interp_mode colorInterp = i915->rasterizer->color_interp; struct vertex_info vinfo; - boolean texCoords[I915_TEX_UNITS], colors[2], fog, needW; + boolean texCoords[I915_TEX_UNITS], colors[2], fog, needW, face; uint i; int src; memset(texCoords, 0, sizeof(texCoords)); - colors[0] = colors[1] = fog = needW = FALSE; + colors[0] = colors[1] = fog = needW = face = FALSE; memset(&vinfo, 0, sizeof(vinfo)); /* Determine which fragment program inputs are needed. Setup HW vertex @@ -72,6 +73,10 @@ static void calculate_vertex_layout(struct i915_context *i915) for (i = 0; i < fs->info.num_inputs; i++) { switch (fs->info.input_semantic_name[i]) { case TGSI_SEMANTIC_POSITION: + { + uint unit = I915_SEMANTIC_POS; + texCoords[find_mapping(fs, unit)] = TRUE; + } break; case TGSI_SEMANTIC_COLOR: assert(fs->info.input_semantic_index[i] < 2); @@ -80,7 +85,6 @@ static void calculate_vertex_layout(struct i915_context *i915) case TGSI_SEMANTIC_GENERIC: { /* texcoords/varyings/other generic */ - /* XXX handle back/front face and point size */ uint unit = fs->info.input_semantic_index[i]; texCoords[find_mapping(fs, unit)] = TRUE; @@ -90,7 +94,11 @@ static void calculate_vertex_layout(struct i915_context *i915) case TGSI_SEMANTIC_FOG: fog = TRUE; break; + case TGSI_SEMANTIC_FACE: + face = TRUE; + break; default: + debug_printf("Unknown input type %d\n", fs->info.input_semantic_name[i]); assert(0); } } @@ -147,6 +155,20 @@ static void calculate_vertex_layout(struct i915_context *i915) vinfo.hwfmt[1] |= hwtc << (i * 4); } + /* front/back face */ + if (face) { + uint slot = find_mapping(fs, I915_SEMANTIC_FACE); + debug_printf("Front/back face is broken\n"); + /* XXX Because of limitations in the draw module, currently src will be 0 + * for SEMANTIC_FACE, so this aliases to POS. We need to fix in the draw + * module by adding an extra shader output. + */ + src = draw_find_shader_output(i915->draw, TGSI_SEMANTIC_FACE, 0); + draw_emit_vertex_attr(&vinfo, EMIT_1F, INTERP_CONSTANT, src); + vinfo.hwfmt[1] &= ~(TEXCOORDFMT_NOT_PRESENT << (slot * 4)); + vinfo.hwfmt[1] |= TEXCOORDFMT_1D << (slot * 4); + } + draw_compute_vertex_size(&vinfo); if (memcmp(&i915->current.vertex_info, &vinfo, sizeof(vinfo))) { diff --git a/src/gallium/drivers/i915/i915_state_emit.c b/src/gallium/drivers/i915/i915_state_emit.c index 0155cd83510..4f447962bb9 100644 --- a/src/gallium/drivers/i915/i915_state_emit.c +++ b/src/gallium/drivers/i915/i915_state_emit.c @@ -34,7 +34,9 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" +#include "pipe/p_format.h" +#include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" @@ -128,7 +130,7 @@ validate_immediate(struct i915_context *i915, unsigned *batch_space) static void emit_immediate(struct i915_context *i915) { - /* remove unwatned bits and S7 */ + /* remove unwanted bits and S7 */ unsigned dirty = (1 << I915_IMMEDIATE_S0 | 1 << I915_IMMEDIATE_S1 | 1 << I915_IMMEDIATE_S2 | 1 << I915_IMMEDIATE_S3 | 1 << I915_IMMEDIATE_S3 | 1 << I915_IMMEDIATE_S4 | @@ -341,21 +343,84 @@ emit_constants(struct i915_context *i915) } } +static const struct +{ + enum pipe_format format; + uint hw_swizzle; +} fixup_formats[] = { + { PIPE_FORMAT_R8G8B8A8_UNORM, 0x21030000 /* BGRA */}, + { PIPE_FORMAT_L8_UNORM, 0x00030000 /* RRRA */}, + { PIPE_FORMAT_I8_UNORM, 0x00030000 /* RRRA */}, + { PIPE_FORMAT_A8_UNORM, 0x33330000 /* AAAA */}, + { PIPE_FORMAT_NONE, 0x00000000}, +}; + +static uint need_target_fixup(struct pipe_surface* p) +{ + enum pipe_format f; + /* if we don't have a surface bound yet, we don't need to fixup the shader */ + if (!p) + return 0; + + f = p->format; + for(int i=0; fixup_formats[i].format != PIPE_FORMAT_NONE; i++) + if (fixup_formats[i].format == f) + return 1; + + return 0; +} + +static uint fixup_swizzle(enum pipe_format f) +{ + for(int i=0; fixup_formats[i].format != PIPE_FORMAT_NONE; i++) + if (fixup_formats[i].format == f) + return fixup_formats[i].hw_swizzle; + + return 0; +} + static void validate_program(struct i915_context *i915, unsigned *batch_space) { - *batch_space = i915->fs->program_len; + struct pipe_surface *cbuf_surface = i915->framebuffer.cbufs[0]; + uint additional_size = need_target_fixup(cbuf_surface); + + /* we need more batch space if we want to emulate rgba framebuffers */ + *batch_space = i915->fs->program_len + 3 * additional_size; } static void emit_program(struct i915_context *i915) { - uint i; - /* we should always have, at least, a pass-through program */ - assert(i915->fs->program_len > 0); - for (i = 0; i < i915->fs->program_len; i++) { - OUT_BATCH(i915->fs->program[i]); - } + struct pipe_surface *cbuf_surface = i915->framebuffer.cbufs[0]; + uint target_fixup = need_target_fixup(cbuf_surface); + uint i; + + /* we should always have, at least, a pass-through program */ + assert(i915->fs->program_len > 0); + + { + /* first word has the size, we have to adjust that */ + uint size = (i915->fs->program[0]); + size += target_fixup * 3; + OUT_BATCH(size); + } + + /* output the declarations of the program */ + for (i=1 ; i < i915->fs->program_len; i++) + OUT_BATCH(i915->fs->program[i]); + + /* we emit an additional mov with swizzle to fake RGBA framebuffers */ + if (target_fixup) { + /* mov out_color, out_color.zyxw */ + OUT_BATCH(A0_MOV | + (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) | + A0_DEST_CHANNEL_ALL | + (REG_TYPE_OC << A0_SRC0_TYPE_SHIFT) | + (T_DIFFUSE << A0_SRC0_NR_SHIFT)); + OUT_BATCH(fixup_swizzle(cbuf_surface->format)); + OUT_BATCH(0); + } } static void diff --git a/src/gallium/drivers/i915/i915_state_inlines.h b/src/gallium/drivers/i915/i915_state_inlines.h index b589117fbfe..aa992f75c51 100644 --- a/src/gallium/drivers/i915/i915_state_inlines.h +++ b/src/gallium/drivers/i915/i915_state_inlines.h @@ -60,6 +60,31 @@ i915_translate_compare_func(unsigned func) } static INLINE unsigned +i915_translate_shadow_compare_func(unsigned func) +{ + switch (func) { + case PIPE_FUNC_NEVER: + return COMPAREFUNC_ALWAYS; + case PIPE_FUNC_LESS: + return COMPAREFUNC_LEQUAL; + case PIPE_FUNC_LEQUAL: + return COMPAREFUNC_LESS; + case PIPE_FUNC_GREATER: + return COMPAREFUNC_GEQUAL; + case PIPE_FUNC_GEQUAL: + return COMPAREFUNC_GREATER; + case PIPE_FUNC_NOTEQUAL: + return COMPAREFUNC_EQUAL; + case PIPE_FUNC_EQUAL: + return COMPAREFUNC_NOTEQUAL; + case PIPE_FUNC_ALWAYS: + return COMPAREFUNC_NEVER; + default: + return COMPAREFUNC_NEVER; + } +} + +static INLINE unsigned i915_translate_stencil_op(unsigned op) { switch (op) { diff --git a/src/gallium/drivers/i915/i915_state_sampler.c b/src/gallium/drivers/i915/i915_state_sampler.c index be70e7a92c9..0103f7c3530 100644 --- a/src/gallium/drivers/i915/i915_state_sampler.c +++ b/src/gallium/drivers/i915/i915_state_sampler.c @@ -62,6 +62,7 @@ static void update_map(struct i915_context *i915, uint unit, const struct i915_texture *tex, const struct i915_sampler_state *sampler, + const struct pipe_sampler_view* view, uint state[2]); @@ -161,9 +162,10 @@ static void update_samplers(struct i915_context *i915) i915->current.sampler[unit]); /* the result */ update_map(i915, unit, - texture, /* texture */ - i915->sampler[unit], /* sampler state */ - i915->current.texbuffer[unit]); /* the result */ + texture, /* texture */ + i915->sampler[unit], /* sampler state */ + i915->fragment_sampler_views[unit], /* sampler view */ + i915->current.texbuffer[unit]); /* the result */ i915->current.sampler_enable_nr++; i915->current.sampler_enable_flags |= (1 << unit); @@ -180,13 +182,21 @@ struct i915_tracked_state i915_hw_samplers = { }; - /*********************************************************************** * Sampler views */ -static uint translate_texture_format(enum pipe_format pipeFormat) +static uint translate_texture_format(enum pipe_format pipeFormat, + const struct pipe_sampler_view* view) { + if ( (view->swizzle_r != PIPE_SWIZZLE_RED || + view->swizzle_g != PIPE_SWIZZLE_GREEN || + view->swizzle_b != PIPE_SWIZZLE_BLUE || + view->swizzle_a != PIPE_SWIZZLE_ALPHA ) && + pipeFormat != PIPE_FORMAT_Z24_UNORM_S8_USCALED && + pipeFormat != PIPE_FORMAT_Z24X8_UNORM ) + debug_printf("i915: unsupported texture swizzle for format %d\n", pipeFormat); + switch (pipeFormat) { case PIPE_FORMAT_L8_UNORM: return MAPSURF_8BIT | MT_8BIT_L8; @@ -202,16 +212,16 @@ static uint translate_texture_format(enum pipe_format pipeFormat) return MAPSURF_16BIT | MT_16BIT_ARGB1555; case PIPE_FORMAT_B4G4R4A4_UNORM: return MAPSURF_16BIT | MT_16BIT_ARGB4444; + case PIPE_FORMAT_B10G10R10A2_UNORM: + return MAPSURF_32BIT | MT_32BIT_ARGB2101010; case PIPE_FORMAT_B8G8R8A8_UNORM: return MAPSURF_32BIT | MT_32BIT_ARGB8888; case PIPE_FORMAT_B8G8R8X8_UNORM: return MAPSURF_32BIT | MT_32BIT_XRGB8888; case PIPE_FORMAT_R8G8B8A8_UNORM: return MAPSURF_32BIT | MT_32BIT_ABGR8888; -#if 0 case PIPE_FORMAT_R8G8B8X8_UNORM: return MAPSURF_32BIT | MT_32BIT_XBGR8888; -#endif case PIPE_FORMAT_YUYV: return (MAPSURF_422 | MT_422_YCRCB_NORMAL); case PIPE_FORMAT_UYVY: @@ -232,7 +242,25 @@ static uint translate_texture_format(enum pipe_format pipeFormat) return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5); case PIPE_FORMAT_Z24_UNORM_S8_USCALED: case PIPE_FORMAT_Z24X8_UNORM: - return (MAPSURF_32BIT | MT_32BIT_xI824); + { + if ( view->swizzle_r == PIPE_SWIZZLE_RED && + view->swizzle_g == PIPE_SWIZZLE_RED && + view->swizzle_b == PIPE_SWIZZLE_RED && + view->swizzle_a == PIPE_SWIZZLE_ONE) + return (MAPSURF_32BIT | MT_32BIT_xA824); + if ( view->swizzle_r == PIPE_SWIZZLE_RED && + view->swizzle_g == PIPE_SWIZZLE_RED && + view->swizzle_b == PIPE_SWIZZLE_RED && + view->swizzle_a == PIPE_SWIZZLE_RED) + return (MAPSURF_32BIT | MT_32BIT_xI824); + if ( view->swizzle_r == PIPE_SWIZZLE_ZERO && + view->swizzle_g == PIPE_SWIZZLE_ZERO && + view->swizzle_b == PIPE_SWIZZLE_ZERO && + view->swizzle_a == PIPE_SWIZZLE_RED) + return (MAPSURF_32BIT | MT_32BIT_xL824); + debug_printf("i915: unsupported depth swizzle\n"); + return (MAPSURF_32BIT | MT_32BIT_xL824); + } default: debug_printf("i915: translate_texture_format() bad image format %x\n", pipeFormat); @@ -262,6 +290,7 @@ static void update_map(struct i915_context *i915, uint unit, const struct i915_texture *tex, const struct i915_sampler_state *sampler, + const struct pipe_sampler_view* view, uint state[2]) { const struct pipe_resource *pt = &tex->b.b; @@ -275,7 +304,7 @@ static void update_map(struct i915_context *i915, assert(height); assert(depth); - format = translate_texture_format(pt->format); + format = translate_texture_format(pt->format, view); pitch = tex->stride; assert(format); @@ -318,8 +347,9 @@ static void update_maps(struct i915_context *i915) update_map(i915, unit, - texture, /* texture */ - i915->sampler[unit], /* sampler state */ + texture, /* texture */ + i915->sampler[unit], /* sampler state */ + i915->fragment_sampler_views[unit], /* sampler view */ i915->current.texbuffer[unit]); } } diff --git a/src/gallium/drivers/i915/i915_state_static.c b/src/gallium/drivers/i915/i915_state_static.c index 2865298318c..0e4000bc2ab 100644 --- a/src/gallium/drivers/i915/i915_state_static.c +++ b/src/gallium/drivers/i915/i915_state_static.c @@ -42,6 +42,18 @@ static unsigned translate_format(enum pipe_format format) return COLOR_BUF_ARGB8888; case PIPE_FORMAT_B5G6R5_UNORM: return COLOR_BUF_RGB565; + case PIPE_FORMAT_B5G5R5A1_UNORM: + return COLOR_BUF_ARGB1555; + case PIPE_FORMAT_R8G8B8A8_UNORM: + return COLOR_BUF_ARGB8888; + case PIPE_FORMAT_B4G4R4A4_UNORM: + return COLOR_BUF_ARGB4444; + case PIPE_FORMAT_B10G10R10A2_UNORM: + return COLOR_BUF_ARGB2101010; + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_I8_UNORM: + return COLOR_BUF_8BIT; default: assert(0); return 0; @@ -137,7 +149,8 @@ static void update_framebuffer(struct i915_context *i915) i915->static_dirty |= I915_DST_RECT; } - i915->hardware_dirty |= I915_HW_STATIC; + /* we also send a new program to make sure the fixup for RGBA surfaces happens */ + i915->hardware_dirty |= I915_HW_STATIC | I915_HW_PROGRAM; /* flush the cache in case we sample from the old renderbuffers */ i915_set_flush_dirty(i915, I915_FLUSH_CACHE); diff --git a/src/gallium/drivers/i915/i915_winsys.h b/src/gallium/drivers/i915/i915_winsys.h index 21cfdc9613e..20438609e07 100644 --- a/src/gallium/drivers/i915/i915_winsys.h +++ b/src/gallium/drivers/i915/i915_winsys.h @@ -207,6 +207,12 @@ struct i915_winsys { void (*buffer_destroy)(struct i915_winsys *iws, struct i915_winsys_buffer *buffer); + + /** + * Check if a buffer is busy. + */ + boolean (*buffer_is_busy)(struct i915_winsys *iws, + struct i915_winsys_buffer *buffer); /*@}*/ diff --git a/src/gallium/drivers/llvmpipe/Makefile b/src/gallium/drivers/llvmpipe/Makefile index ba9705bebee..f9301354fc5 100644 --- a/src/gallium/drivers/llvmpipe/Makefile +++ b/src/gallium/drivers/llvmpipe/Makefile @@ -51,6 +51,7 @@ C_SOURCES = \ CPP_SOURCES = \ PROGS := lp_test_format \ + lp_test_arit \ lp_test_blend \ lp_test_conv \ lp_test_printf \ diff --git a/src/gallium/drivers/llvmpipe/SConscript b/src/gallium/drivers/llvmpipe/SConscript index c10a8cbc12c..2b232a524ae 100644 --- a/src/gallium/drivers/llvmpipe/SConscript +++ b/src/gallium/drivers/llvmpipe/SConscript @@ -79,17 +79,18 @@ llvmpipe = env.ConvenienceLibrary( env.Alias('llvmpipe', llvmpipe) -if env['platform'] != 'embedded': +if not env['embedded']: env = env.Clone() env.Prepend(LIBS = [llvmpipe] + gallium) tests = [ + 'arit', 'format', 'blend', 'conv', - 'printf', - 'sincos', + 'printf', + 'sincos', ] if not env['msvc']: diff --git a/src/gallium/drivers/llvmpipe/lp_jit.c b/src/gallium/drivers/llvmpipe/lp_jit.c index 268f0fa034b..ce92a80721a 100644 --- a/src/gallium/drivers/llvmpipe/lp_jit.c +++ b/src/gallium/drivers/llvmpipe/lp_jit.c @@ -68,10 +68,17 @@ lp_jit_create_types(struct llvmpipe_context *lp) elem_types[LP_JIT_TEXTURE_BORDER_COLOR] = LLVMArrayType(LLVMFloatTypeInContext(lc), 4); +#if HAVE_LLVM >= 0x0300 + texture_type = LLVMStructCreateNamed(gallivm->context, "texture"); + LLVMStructSetBody(texture_type, elem_types, + Elements(elem_types), 0); +#else texture_type = LLVMStructTypeInContext(lc, elem_types, Elements(elem_types), 0); + LLVMAddTypeName(gallivm->module, "texture", texture_type); LLVMInvalidateStructLayout(gallivm->target, texture_type); +#endif LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, width, gallivm->target, texture_type, @@ -112,8 +119,6 @@ lp_jit_create_types(struct llvmpipe_context *lp) LP_CHECK_STRUCT_SIZE(struct lp_jit_texture, gallivm->target, texture_type); - - LLVMAddTypeName(gallivm->module, "texture", texture_type); } /* struct lp_jit_context */ @@ -129,11 +134,19 @@ lp_jit_create_types(struct llvmpipe_context *lp) elem_types[LP_JIT_CTX_TEXTURES] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); +#if HAVE_LLVM >= 0x0300 + context_type = LLVMStructCreateNamed(gallivm->context, "context"); + LLVMStructSetBody(context_type, elem_types, + Elements(elem_types), 0); +#else context_type = LLVMStructTypeInContext(lc, elem_types, Elements(elem_types), 0); LLVMInvalidateStructLayout(gallivm->target, context_type); + LLVMAddTypeName(gallivm->module, "context", context_type); +#endif + LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, constants, gallivm->target, context_type, LP_JIT_CTX_CONSTANTS); @@ -155,8 +168,6 @@ lp_jit_create_types(struct llvmpipe_context *lp) LP_CHECK_STRUCT_SIZE(struct lp_jit_context, gallivm->target, context_type); - LLVMAddTypeName(gallivm->module, "context", context_type); - lp->jit_context_ptr_type = LLVMPointerType(context_type, 0); } diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 036a6e0c379..e3f8c19679f 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -93,7 +93,9 @@ llvmpipe_get_vendor(struct pipe_screen *screen) static const char * llvmpipe_get_name(struct pipe_screen *screen) { - return "llvmpipe"; + static char buf[100]; + snprintf(buf, sizeof(buf), "llvmpipe (LLVM 0x%x)", HAVE_LLVM); + return buf; } @@ -423,7 +425,7 @@ llvmpipe_create_screen(struct sw_winsys *winsys) lp_jit_screen_init(screen); screen->num_threads = util_cpu_caps.nr_cpus > 1 ? util_cpu_caps.nr_cpus : 0; -#ifdef PIPE_OS_EMBEDDED +#ifdef PIPE_SUBSYSTEM_EMBEDDED screen->num_threads = 0; #endif screen->num_threads = debug_get_num_option("LP_NUM_THREADS", screen->num_threads); diff --git a/src/gallium/drivers/llvmpipe/lp_test_arit.c b/src/gallium/drivers/llvmpipe/lp_test_arit.c new file mode 100644 index 00000000000..f0e43e0f9cc --- /dev/null +++ b/src/gallium/drivers/llvmpipe/lp_test_arit.c @@ -0,0 +1,294 @@ +/************************************************************************** + * + * Copyright 2011 VMware, 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 VMWARE AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> + +#include "util/u_pointer.h" +#include "util/u_memory.h" + +#include "gallivm/lp_bld.h" +#include "gallivm/lp_bld_init.h" +#include "gallivm/lp_bld_arit.h" + +#include "lp_test.h" + + +void +write_tsv_header(FILE *fp) +{ + fprintf(fp, + "result\t" + "format\n"); + + fflush(fp); +} + + +typedef float (*unary_func_t)(float); + + +/** + * Describe a test case of one unary function. + */ +struct unary_test_t +{ + /* + * Test name -- name of the mathematical function under test. + */ + + const char *name; + + LLVMValueRef + (*builder)(struct lp_build_context *bld, LLVMValueRef a); + + /* + * Reference (pure-C) function. + */ + float + (*ref)(float a); + + /* + * Test values. + */ + const float *values; + unsigned num_values; +}; + + +const float exp2_values[] = { + -60, + -4, + -2, + -1, + -1e-007, + 0, + 1e-007, + 1, + 2, + 4, + 60 +}; + + +const float log2_values[] = { +#if 0 + /* + * Smallest denormalized number; meant just for experimentation, but not + * validation. + */ + 1.4012984643248171e-45, +#endif + 1e-007, + 0.5, + 1, + 2, + 4, + 100000, + 1e+018 +}; + + +static float rsqrtf(float x) +{ + return 1.0/sqrt(x); +} + + +const float rsqrt_values[] = { + -1, -1e-007, + 1e-007, 1, + -4, -1, + 1, 4, + -1e+035, -100000, + 100000, 1e+035, +}; + + +const float sincos_values[] = { + -5*M_PI/4, + -4*M_PI/4, + -4*M_PI/4, + -3*M_PI/4, + -2*M_PI/4, + -1*M_PI/4, + 1*M_PI/4, + 2*M_PI/4, + 3*M_PI/4, + 4*M_PI/4, + 5*M_PI/4, +}; + + +/* + * Unary test cases. + */ + +static const struct unary_test_t unary_tests[] = { + {"exp2", &lp_build_exp2, &exp2f, exp2_values, Elements(exp2_values)}, + {"log2", &lp_build_log2, &log2f, log2_values, Elements(log2_values)}, + {"exp", &lp_build_exp, &expf, exp2_values, Elements(exp2_values)}, + {"log", &lp_build_log, &logf, log2_values, Elements(log2_values)}, + {"rsqrt", &lp_build_rsqrt, &rsqrtf, rsqrt_values, Elements(rsqrt_values)}, + {"sin", &lp_build_sin, &sinf, sincos_values, Elements(sincos_values)}, + {"cos", &lp_build_cos, &cosf, sincos_values, Elements(sincos_values)}, +}; + + +/* + * Build LLVM function that exercises the unary operator builder. + */ +static LLVMValueRef +build_unary_test_func(struct gallivm_state *gallivm, + LLVMModuleRef module, + LLVMContextRef context, + const struct unary_test_t *test) +{ + LLVMTypeRef i32t = LLVMInt32TypeInContext(context); + LLVMTypeRef f32t = LLVMFloatTypeInContext(context); + LLVMTypeRef v4f32t = LLVMVectorType(f32t, 4); + LLVMTypeRef args[1] = { f32t }; + LLVMValueRef func = LLVMAddFunction(module, test->name, LLVMFunctionType(f32t, args, Elements(args), 0)); + LLVMValueRef arg1 = LLVMGetParam(func, 0); + LLVMBuilderRef builder = gallivm->builder; + LLVMBasicBlockRef block = LLVMAppendBasicBlockInContext(context, func, "entry"); + LLVMValueRef index0 = LLVMConstInt(i32t, 0, 0); + LLVMValueRef ret; + + struct lp_build_context bld; + + lp_build_context_init(&bld, gallivm, lp_float32_vec4_type()); + + LLVMSetFunctionCallConv(func, LLVMCCallConv); + + LLVMPositionBuilderAtEnd(builder, block); + + /* scalar to vector */ + arg1 = LLVMBuildInsertElement(builder, LLVMGetUndef(v4f32t), arg1, index0, ""); + + ret = test->builder(&bld, arg1); + + /* vector to scalar */ + ret = LLVMBuildExtractElement(builder, ret, index0, ""); + + LLVMBuildRet(builder, ret); + return func; +} + + +/* + * Test one LLVM unary arithmetic builder function. + */ +static boolean +test_unary(struct gallivm_state *gallivm, unsigned verbose, FILE *fp, const struct unary_test_t *test) +{ + LLVMModuleRef module = gallivm->module; + LLVMValueRef test_func; + LLVMExecutionEngineRef engine = gallivm->engine; + LLVMContextRef context = gallivm->context; + char *error = NULL; + unary_func_t test_func_jit; + boolean success = TRUE; + int i; + + test_func = build_unary_test_func(gallivm, module, context, test); + + if (LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) { + printf("LLVMVerifyModule: %s\n", error); + LLVMDumpModule(module); + abort(); + } + LLVMDisposeMessage(error); + + test_func_jit = (unary_func_t) pointer_to_func(LLVMGetPointerToGlobal(engine, test_func)); + + for (i = 0; i < test->num_values; ++i) { + float value = test->values[i]; + float ref = test->ref(value); + float src = test_func_jit(value); + + double error = fabs(src - ref); + double precision = error ? -log2(error/fabs(ref)) : FLT_MANT_DIG; + + bool pass = precision >= 20.0; + + if (isnan(ref)) { + continue; + } + + if (!pass || verbose) { + printf("%s(%.9g): ref = %.9g, src = %.9g, precision = %f bits, %s\n", + test->name, value, ref, src, precision, + pass ? "PASS" : "FAIL"); + } + + if (!pass) { + success = FALSE; + } + } + + LLVMFreeMachineCodeForFunction(engine, test_func); + + return success; +} + + +boolean +test_all(struct gallivm_state *gallivm, unsigned verbose, FILE *fp) +{ + boolean success = TRUE; + int i; + + for (i = 0; i < Elements(unary_tests); ++i) { + if (!test_unary(gallivm, verbose, fp, &unary_tests[i])) { + success = FALSE; + } + } + + return success; +} + + +boolean +test_some(struct gallivm_state *gallivm, unsigned verbose, FILE *fp, + unsigned long n) +{ + /* + * Not randomly generated test cases, so test all. + */ + + return test_all(gallivm, verbose, fp); +} + + +boolean +test_single(struct gallivm_state *gallivm, unsigned verbose, FILE *fp) +{ + return TRUE; +} diff --git a/src/gallium/drivers/nouveau/Makefile b/src/gallium/drivers/nouveau/Makefile index 3210d1ff77b..aae6d9889bb 100644 --- a/src/gallium/drivers/nouveau/Makefile +++ b/src/gallium/drivers/nouveau/Makefile @@ -10,6 +10,7 @@ LIBRARY_INCLUDES = \ C_SOURCES = nouveau_screen.c \ nouveau_fence.c \ nouveau_mm.c \ - nouveau_buffer.c + nouveau_buffer.c \ + nouveau_video.c include ../../Makefile.template diff --git a/src/gallium/drivers/nouveau/nouveau_context.h b/src/gallium/drivers/nouveau/nouveau_context.h index 696e0d3f24e..19bf7c84ac7 100644 --- a/src/gallium/drivers/nouveau/nouveau_context.h +++ b/src/gallium/drivers/nouveau/nouveau_context.h @@ -23,4 +23,7 @@ nouveau_context(struct pipe_context *pipe) return (struct nouveau_context *)pipe; } +void +nouveau_context_init_vdec(struct nouveau_context *); + #endif diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c index 401155bba6e..223e7682ccd 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.c +++ b/src/gallium/drivers/nouveau/nouveau_screen.c @@ -81,20 +81,6 @@ nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment, return bo; } -struct nouveau_bo * -nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes) -{ - struct nouveau_device *dev = nouveau_screen(pscreen)->device; - struct nouveau_bo *bo = NULL; - int ret; - - ret = nouveau_bo_user(dev, ptr, bytes, &bo); - if (ret) - return NULL; - - return bo; -} - void * nouveau_screen_bo_map(struct pipe_screen *pscreen, struct nouveau_bo *bo, diff --git a/src/gallium/drivers/nouveau/nouveau_screen.h b/src/gallium/drivers/nouveau/nouveau_screen.h index 186ada39677..cf291c6c595 100644 --- a/src/gallium/drivers/nouveau/nouveau_screen.h +++ b/src/gallium/drivers/nouveau/nouveau_screen.h @@ -47,8 +47,6 @@ nouveau_screen(struct pipe_screen *pscreen) struct nouveau_bo * nouveau_screen_bo_new(struct pipe_screen *pscreen, unsigned alignment, unsigned usage, unsigned bind, unsigned size); -struct nouveau_bo * -nouveau_screen_bo_user(struct pipe_screen *pscreen, void *ptr, unsigned bytes); void * nouveau_screen_bo_map(struct pipe_screen *pscreen, struct nouveau_bo *pb, @@ -78,6 +76,7 @@ nouveau_screen_bo_from_handle(struct pipe_screen *pscreen, int nouveau_screen_init(struct nouveau_screen *, struct nouveau_device *); void nouveau_screen_fini(struct nouveau_screen *); +void nouveau_screen_init_vdec(struct nouveau_screen *); #ifndef NOUVEAU_NVC0 diff --git a/src/gallium/drivers/nouveau/nouveau_video.c b/src/gallium/drivers/nouveau/nouveau_video.c new file mode 100644 index 00000000000..32f038dae61 --- /dev/null +++ b/src/gallium/drivers/nouveau/nouveau_video.c @@ -0,0 +1,39 @@ + +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" + +#include "nouveau/nouveau_screen.h" +#include "nouveau/nouveau_context.h" + +static int +nouveau_screen_get_video_param(struct pipe_screen *pscreen, + enum pipe_video_profile profile, + enum pipe_video_cap param) +{ + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vl_profile_supported(pscreen, profile); + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 1; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vl_video_buffer_max_size(pscreen); + default: + debug_printf("unknown video param: %d\n", param); + return 0; + } +} + +void +nouveau_screen_init_vdec(struct nouveau_screen *screen) +{ + screen->base.get_video_param = nouveau_screen_get_video_param; + screen->base.is_video_format_supported = vl_video_buffer_is_format_supported; +} + +void +nouveau_context_init_vdec(struct nouveau_context *nv) +{ + nv->pipe.create_video_decoder = vl_create_decoder; + nv->pipe.create_video_buffer = vl_video_buffer_create; +} diff --git a/src/gallium/drivers/nv50/nv50_3d.xml.h b/src/gallium/drivers/nv50/nv50_3d.xml.h index 41a380ec2ec..1bde07fa3af 100644 --- a/src/gallium/drivers/nv50/nv50_3d.xml.h +++ b/src/gallium/drivers/nv50/nv50_3d.xml.h @@ -777,7 +777,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_FORMAT_8_8 0x03000000 #define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_FORMAT_16 0x03600000 #define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_FORMAT_8 0x03a00000 -#define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_FORMAT_2_10_10_10 0x06000000 +#define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_FORMAT_10_10_10_2 0x06000000 #define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_TYPE__MASK 0x38000000 #define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_TYPE__SHIFT 27 #define NVA3_3D_VERTEX_ARRAY_ATTRIB_ALT_TYPE_SNORM 0x08000000 @@ -1935,7 +1935,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_8_8 0x00c00000 #define NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_16 0x00d80000 #define NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_8 0x00e80000 -#define NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_2_10_10_10 0x01800000 +#define NV50_3D_VERTEX_ARRAY_ATTRIB_FORMAT_10_10_10_2 0x01800000 #define NV50_3D_VERTEX_ARRAY_ATTRIB_TYPE__MASK 0x7e000000 #define NV50_3D_VERTEX_ARRAY_ATTRIB_TYPE__SHIFT 25 #define NV50_3D_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT 0x7e000000 diff --git a/src/gallium/drivers/nv50/nv50_context.c b/src/gallium/drivers/nv50/nv50_context.c index 632ca4daf74..0d464063b5b 100644 --- a/src/gallium/drivers/nv50/nv50_context.c +++ b/src/gallium/drivers/nv50/nv50_context.c @@ -60,13 +60,13 @@ nv50_texture_barrier(struct pipe_context *pipe) void nv50_default_flush_notify(struct nouveau_channel *chan) { - struct nv50_context *nv50 = chan->user_private; + struct nv50_screen *screen = chan->user_private; - if (!nv50) + if (!screen) return; - nouveau_fence_update(&nv50->screen->base, TRUE); - nouveau_fence_next(&nv50->screen->base); + nouveau_fence_update(&screen->base, TRUE); + nouveau_fence_next(&screen->base); } static void @@ -100,10 +100,8 @@ nv50_destroy(struct pipe_context *pipe) draw_destroy(nv50->draw); - if (nv50->screen->cur_ctx == nv50) { - nv50->screen->base.channel->user_private = NULL; + if (nv50->screen->cur_ctx == nv50) nv50->screen->cur_ctx = NULL; - } FREE(nv50); } @@ -140,7 +138,6 @@ nv50_create(struct pipe_screen *pscreen, void *priv) if (!screen->cur_ctx) screen->cur_ctx = nv50; - screen->base.channel->user_private = nv50; screen->base.channel->flush_notify = nv50_default_flush_notify; nv50_init_query_functions(nv50); @@ -152,6 +149,8 @@ nv50_create(struct pipe_screen *pscreen, void *priv) assert(nv50->draw); draw_set_rasterize_stage(nv50->draw, nv50_draw_render_stage(nv50)); + nouveau_context_init_vdec(&nv50->base); + return pipe; } @@ -168,6 +167,7 @@ nv50_bufctx_add_resident(struct nv50_context *nv50, int ctx, if (!resource->bo) return; + nv50->residents_size += sizeof(struct resident); /* We don't need to reference the resource here, it will be referenced * in the context/state, and bufctx will be reset when state changes. @@ -189,6 +189,7 @@ nv50_bufctx_del_resident(struct nv50_context *nv50, int ctx, top = util_dynarray_pop_ptr(&nv50->residents[ctx], struct resident); if (rsd != top) *rsd = *top; + nv50->residents_size -= sizeof(struct resident); break; } } @@ -201,11 +202,15 @@ nv50_bufctx_emit_relocs(struct nv50_context *nv50) struct util_dynarray *array; unsigned ctx, i, n; + n = nv50->residents_size / sizeof(struct resident); + n += NV50_SCREEN_RESIDENT_BO_COUNT; + + MARK_RING(nv50->screen->base.channel, n, n); + for (ctx = 0; ctx < NV50_BUFCTX_COUNT; ++ctx) { array = &nv50->residents[ctx]; n = array->size / sizeof(struct resident); - MARK_RING(nv50->screen->base.channel, n, n); for (i = 0; i < n; ++i) { rsd = util_dynarray_element(array, struct resident, i); diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h index 3f031994f0a..284db69e312 100644 --- a/src/gallium/drivers/nv50/nv50_context.h +++ b/src/gallium/drivers/nv50/nv50_context.h @@ -18,6 +18,7 @@ #include "nv50_screen.h" #include "nv50_program.h" #include "nv50_resource.h" +#include "nv50_transfer.h" #include "nouveau/nouveau_context.h" #include "nouveau/nv_object.xml.h" @@ -64,6 +65,7 @@ struct nv50_context { struct nv50_screen *screen; struct util_dynarray residents[NV50_BUFCTX_COUNT]; + unsigned residents_size; uint32_t dirty; @@ -129,20 +131,6 @@ nv50_context(struct pipe_context *pipe) return (struct nv50_context *)pipe; } -struct nv50_surface { - struct pipe_surface base; - uint32_t offset; - uint32_t width; - uint16_t height; - uint16_t depth; -}; - -static INLINE struct nv50_surface * -nv50_surface(struct pipe_surface *ps) -{ - return (struct nv50_surface *)ps; -} - /* nv50_context.c */ struct pipe_context *nv50_create(struct pipe_screen *, void *); @@ -156,6 +144,7 @@ void nv50_bufctx_del_resident(struct nv50_context *, int ctx, static INLINE void nv50_bufctx_reset(struct nv50_context *nv50, int ctx) { + nv50->residents_size -= nv50->residents[ctx].size; util_dynarray_resize(&nv50->residents[ctx], 0); } @@ -182,7 +171,8 @@ void nv50_validate_derived_rs(struct nv50_context *); extern void nv50_init_state_functions(struct nv50_context *); /* nv50_state_validate.c */ -extern boolean nv50_state_validate(struct nv50_context *); +/* @words: check for space before emitting relocs */ +extern boolean nv50_state_validate(struct nv50_context *, unsigned words); /* nv50_surface.c */ extern void nv50_clear(struct pipe_context *, unsigned buffers, @@ -200,6 +190,11 @@ nv50_create_sampler_view(struct pipe_context *, /* nv50_transfer.c */ void +nv50_m2mf_transfer_rect(struct pipe_screen *pscreen, + const struct nv50_m2mf_rect *dst, + const struct nv50_m2mf_rect *src, + uint32_t nblocksx, uint32_t nblocksy); +void nv50_sifc_linear_u8(struct nouveau_context *pipe, struct nouveau_bo *dst, unsigned offset, unsigned domain, unsigned size, void *data); diff --git a/src/gallium/drivers/nv50/nv50_defs.xml.h b/src/gallium/drivers/nv50/nv50_defs.xml.h index 1bf2f802b56..27046e9e564 100644 --- a/src/gallium/drivers/nv50/nv50_defs.xml.h +++ b/src/gallium/drivers/nv50/nv50_defs.xml.h @@ -1,5 +1,5 @@ -#ifndef NV50_DEFS_XML -#define NV50_DEFS_XML +#ifndef RNNDB_NV50_DEFS_XML +#define RNNDB_NV50_DEFS_XML /* Autogenerated file, DO NOT EDIT manually! @@ -8,10 +8,11 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng git clone git://0x04.net/rules-ng-ng The rules-ng-ng source files this header was generated from are: -- nv50_defs.xml ( 4482 bytes, from 2010-10-03 13:18:37) -- copyright.xml ( 6498 bytes, from 2010-10-03 13:18:37) +- rnndb/nv50_defs.xml ( 5468 bytes, from 2011-07-09 13:43:58) +- ./rnndb/copyright.xml ( 6452 bytes, from 2011-07-09 13:43:58) +- ./rnndb/nvchipsets.xml ( 3617 bytes, from 2011-07-09 13:43:58) -Copyright (C) 2006-2010 by the following authors: +Copyright (C) 2006-2011 by the following authors: - Artur Huillet <[email protected]> (ahuillet) - Ben Skeggs (darktama, darktama_) - B. R. <[email protected]> (koala_br) @@ -22,7 +23,7 @@ Copyright (C) 2006-2010 by the following authors: - Dmitry Eremin-Solenikov <[email protected]> (lumag) - EdB <[email protected]> (edb_) - Erik Waling <[email protected]> (erikwaling) -- Francisco Jerez <[email protected]> (curro, curro_, currojerez) +- Francisco Jerez <[email protected]> (curro) - imirkin <[email protected]> (imirkin) - jb17bsome <[email protected]> (jb17bsome) - Jeremy Kolb <[email protected]> (kjeremy) @@ -70,44 +71,50 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#define NV50_SURFACE_FORMAT_R32G32B32A32_FLOAT 0x000000c0 -#define NV50_SURFACE_FORMAT_R32G32B32A32_SINT 0x000000c1 -#define NV50_SURFACE_FORMAT_R32G32B32A32_UINT 0x000000c2 -#define NV50_SURFACE_FORMAT_R32G32B32X32_FLOAT 0x000000c3 -#define NV50_SURFACE_FORMAT_R16G16B16A16_UNORM 0x000000c6 -#define NV50_SURFACE_FORMAT_R16G16B16A16_SNORM 0x000000c7 -#define NV50_SURFACE_FORMAT_R16G16B16A16_SINT 0x000000c8 -#define NV50_SURFACE_FORMAT_R16G16B16A16_UINT 0x000000c9 -#define NV50_SURFACE_FORMAT_R16G16B16A16_FLOAT 0x000000ca -#define NV50_SURFACE_FORMAT_R32G32_FLOAT 0x000000cb -#define NV50_SURFACE_FORMAT_R32G32_SINT 0x000000cc -#define NV50_SURFACE_FORMAT_R32G32_UINT 0x000000cd -#define NV50_SURFACE_FORMAT_R16G16B16X16_FLOAT 0x000000ce -#define NV50_SURFACE_FORMAT_A8R8G8B8_UNORM 0x000000cf -#define NV50_SURFACE_FORMAT_A8R8G8B8_SRGB 0x000000d0 -#define NV50_SURFACE_FORMAT_A2B10G10R10_UNORM 0x000000d1 -#define NV50_SURFACE_FORMAT_A2B10G10R10_UINT 0x000000d2 -#define NV50_SURFACE_FORMAT_A8B8G8R8_UNORM 0x000000d5 -#define NV50_SURFACE_FORMAT_A8B8G8R8_SRGB 0x000000d6 -#define NV50_SURFACE_FORMAT_A8B8G8R8_SNORM 0x000000d7 -#define NV50_SURFACE_FORMAT_A8B8G8R8_SINT 0x000000d8 -#define NV50_SURFACE_FORMAT_A8B8G8R8_UINT 0x000000d9 -#define NV50_SURFACE_FORMAT_R16G16_UNORM 0x000000da -#define NV50_SURFACE_FORMAT_R16G16_SNORM 0x000000db -#define NV50_SURFACE_FORMAT_R16G16_SINT 0x000000dc -#define NV50_SURFACE_FORMAT_R16G16_UINT 0x000000dd -#define NV50_SURFACE_FORMAT_R16G16_FLOAT 0x000000de -#define NV50_SURFACE_FORMAT_A2R10G10B10_UNORM 0x000000df -#define NV50_SURFACE_FORMAT_B10G11R11_FLOAT 0x000000e0 +#define NV50_SURFACE_FORMAT_BITMAP 0x0000001c +#define NV50_SURFACE_FORMAT_UNK1D 0x0000001d +#define NV50_SURFACE_FORMAT_RGBA32_FLOAT 0x000000c0 +#define NV50_SURFACE_FORMAT_RGBA32_SINT 0x000000c1 +#define NV50_SURFACE_FORMAT_RGBA32_UINT 0x000000c2 +#define NV50_SURFACE_FORMAT_RGBX32_FLOAT 0x000000c3 +#define NV50_SURFACE_FORMAT_RGBX32_SINT 0x000000c4 +#define NV50_SURFACE_FORMAT_RGBX32_UINT 0x000000c5 +#define NV50_SURFACE_FORMAT_RGBA16_UNORM 0x000000c6 +#define NV50_SURFACE_FORMAT_RGBA16_SNORM 0x000000c7 +#define NV50_SURFACE_FORMAT_RGBA16_SINT 0x000000c8 +#define NV50_SURFACE_FORMAT_RGBA16_UINT 0x000000c9 +#define NV50_SURFACE_FORMAT_RGBA16_FLOAT 0x000000ca +#define NV50_SURFACE_FORMAT_RG32_FLOAT 0x000000cb +#define NV50_SURFACE_FORMAT_RG32_SINT 0x000000cc +#define NV50_SURFACE_FORMAT_RG32_UINT 0x000000cd +#define NV50_SURFACE_FORMAT_RGBX16_FLOAT 0x000000ce +#define NV50_SURFACE_FORMAT_BGRA8_UNORM 0x000000cf +#define NV50_SURFACE_FORMAT_BGRA8_SRGB 0x000000d0 +#define NV50_SURFACE_FORMAT_RGB10_A2_UNORM 0x000000d1 +#define NV50_SURFACE_FORMAT_RGB10_A2_UINT 0x000000d2 +#define NV50_SURFACE_FORMAT_RGBA8_UNORM 0x000000d5 +#define NV50_SURFACE_FORMAT_RGBA8_SRGB 0x000000d6 +#define NV50_SURFACE_FORMAT_RGBA8_SNORM 0x000000d7 +#define NV50_SURFACE_FORMAT_RGBA8_SINT 0x000000d8 +#define NV50_SURFACE_FORMAT_RGBA8_UINT 0x000000d9 +#define NV50_SURFACE_FORMAT_RG16_UNORM 0x000000da +#define NV50_SURFACE_FORMAT_RG16_SNORM 0x000000db +#define NV50_SURFACE_FORMAT_RG16_SINT 0x000000dc +#define NV50_SURFACE_FORMAT_RG16_UINT 0x000000dd +#define NV50_SURFACE_FORMAT_RG16_FLOAT 0x000000de +#define NV50_SURFACE_FORMAT_BGR10_A2_UNORM 0x000000df +#define NV50_SURFACE_FORMAT_R11G11B10_FLOAT 0x000000e0 +#define NV50_SURFACE_FORMAT_R32_SINT 0x000000e3 +#define NV50_SURFACE_FORMAT_R32_UINT 0x000000e4 #define NV50_SURFACE_FORMAT_R32_FLOAT 0x000000e5 -#define NV50_SURFACE_FORMAT_X8R8G8B8_UNORM 0x000000e6 -#define NV50_SURFACE_FORMAT_X8R8G8B8_SRGB 0x000000e7 -#define NV50_SURFACE_FORMAT_R5G6B5_UNORM 0x000000e8 -#define NV50_SURFACE_FORMAT_A1R5G5B5_UNORM 0x000000e9 -#define NV50_SURFACE_FORMAT_R8G8_UNORM 0x000000ea -#define NV50_SURFACE_FORMAT_R8G8_SNORM 0x000000eb -#define NV50_SURFACE_FORMAT_R8G8_SINT 0x000000ec -#define NV50_SURFACE_FORMAT_R8G8_UINT 0x000000ed +#define NV50_SURFACE_FORMAT_BGRX8_UNORM 0x000000e6 +#define NV50_SURFACE_FORMAT_BGRX8_SRGB 0x000000e7 +#define NV50_SURFACE_FORMAT_B5G6R5_UNORM 0x000000e8 +#define NV50_SURFACE_FORMAT_BGR5_A1_UNORM 0x000000e9 +#define NV50_SURFACE_FORMAT_RG8_UNORM 0x000000ea +#define NV50_SURFACE_FORMAT_RG8_SNORM 0x000000eb +#define NV50_SURFACE_FORMAT_RG8_SINT 0x000000ec +#define NV50_SURFACE_FORMAT_RG8_UINT 0x000000ed #define NV50_SURFACE_FORMAT_R16_UNORM 0x000000ee #define NV50_SURFACE_FORMAT_R16_SNORM 0x000000ef #define NV50_SURFACE_FORMAT_R16_SINT 0x000000f0 @@ -118,19 +125,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV50_SURFACE_FORMAT_R8_SINT 0x000000f5 #define NV50_SURFACE_FORMAT_R8_UINT 0x000000f6 #define NV50_SURFACE_FORMAT_A8_UNORM 0x000000f7 -#define NV50_SURFACE_FORMAT_X1R5G5B5_UNORM 0x000000f8 -#define NV50_SURFACE_FORMAT_X8B8G8R8_UNORM 0x000000f9 -#define NV50_SURFACE_FORMAT_X8B8G8R8_SRGB 0x000000fa +#define NV50_SURFACE_FORMAT_BGR5_X1_UNORM 0x000000f8 +#define NV50_SURFACE_FORMAT_RGBX8_UNORM 0x000000f9 +#define NV50_SURFACE_FORMAT_RGBX8_SRGB 0x000000fa +#define NV50_SURFACE_FORMAT_BGR5_X1_UNORM_UNKFB 0x000000fb +#define NV50_SURFACE_FORMAT_BGR5_X1_UNORM_UNKFC 0x000000fc +#define NV50_SURFACE_FORMAT_BGRX8_UNORM_UNKFD 0x000000fd +#define NV50_SURFACE_FORMAT_BGRX8_UNORM_UNKFE 0x000000fe +#define NV50_SURFACE_FORMAT_Y32_UINT_UNKFF 0x000000ff #define NV50_ZETA_FORMAT_Z32_FLOAT 0x0000000a #define NV50_ZETA_FORMAT_Z16_UNORM 0x00000013 -#define NV50_ZETA_FORMAT_Z24S8_UNORM 0x00000014 -#define NV50_ZETA_FORMAT_X8Z24_UNORM 0x00000015 -#define NV50_ZETA_FORMAT_S8Z24_UNORM 0x00000016 -#define NV50_ZETA_FORMAT_UNK18 0x00000018 -#define NV50_ZETA_FORMAT_Z32_FLOAT_X24S8_UNORM 0x00000019 -#define NV50_ZETA_FORMAT_UNK1D 0x0000001d -#define NV50_ZETA_FORMAT_UNK1E 0x0000001e -#define NV50_ZETA_FORMAT_UNK1F 0x0000001f +#define NV50_ZETA_FORMAT_S8_Z24_UNORM 0x00000014 +#define NV50_ZETA_FORMAT_Z24_X8_UNORM 0x00000015 +#define NV50_ZETA_FORMAT_Z24_S8_UNORM 0x00000016 +#define NV50_ZETA_FORMAT_Z24_C8_UNORM 0x00000018 +#define NV50_ZETA_FORMAT_Z32_S8_X24_FLOAT 0x00000019 +#define NV50_ZETA_FORMAT_Z24_X8_S8_C8_X16_UNORM 0x0000001d +#define NV50_ZETA_FORMAT_Z32_X8_C8_X16_FLOAT 0x0000001e +#define NV50_ZETA_FORMAT_Z32_S8_C8_X16_FLOAT 0x0000001f #define NV50_QUERY__SIZE 0x00000010 #define NV50_QUERY_COUNTER 0x00000000 @@ -139,4 +151,4 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV50_QUERY_TIME 0x00000008 -#endif /* NV50_DEFS_XML */ +#endif /* RNNDB_NV50_DEFS_XML */ diff --git a/src/gallium/drivers/nv50/nv50_formats.c b/src/gallium/drivers/nv50/nv50_formats.c index 96ed9a7d6d4..34502d0a397 100644 --- a/src/gallium/drivers/nv50/nv50_formats.c +++ b/src/gallium/drivers/nv50/nv50_formats.c @@ -65,28 +65,32 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = { /* COMMON FORMATS */ - [PIPE_FORMAT_B8G8R8A8_UNORM] = { NV50_SURFACE_FORMAT_A8R8G8B8_UNORM, + [PIPE_FORMAT_B8G8R8A8_UNORM] = { NV50_SURFACE_FORMAT_BGRA8_UNORM, A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B8G8R8X8_UNORM] = { NV50_SURFACE_FORMAT_X8R8G8B8_UNORM, + [PIPE_FORMAT_B8G8R8X8_UNORM] = { NV50_SURFACE_FORMAT_BGRX8_UNORM, A_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B8G8R8A8_SRGB] = { NV50_SURFACE_FORMAT_A8R8G8B8_SRGB, + [PIPE_FORMAT_B8G8R8A8_SRGB] = { NV50_SURFACE_FORMAT_BGRA8_SRGB, A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_B8G8R8X8_SRGB] = { NV50_SURFACE_FORMAT_X8R8G8B8_SRGB, + [PIPE_FORMAT_B8G8R8X8_SRGB] = { NV50_SURFACE_FORMAT_BGRX8_SRGB, A_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_B5G6R5_UNORM] = { NV50_SURFACE_FORMAT_R5G6B5_UNORM, + [PIPE_FORMAT_B5G6R5_UNORM] = { NV50_SURFACE_FORMAT_B5G6R5_UNORM, B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 5_6_5, 1), SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B5G5R5A1_UNORM] = { NV50_SURFACE_FORMAT_A1R5G5B5_UNORM, - B_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 1_5_5_5, 1), + [PIPE_FORMAT_B5G5R5A1_UNORM] = { NV50_SURFACE_FORMAT_BGR5_A1_UNORM, + B_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 5_5_5_1, 1), + SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, + + [PIPE_FORMAT_B5G5R5X1_UNORM] = { NV50_SURFACE_FORMAT_BGR5_X1_UNORM, + B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 5_5_5_1, 1), SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, [PIPE_FORMAT_B4G4R4A4_UNORM] = { 0, @@ -97,12 +101,12 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 4_4_4_4, 1), SAMPLER_VIEW }, - [PIPE_FORMAT_R10G10B10A2_UNORM] = { NV50_SURFACE_FORMAT_A2B10G10R10_UNORM, - A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 2_10_10_10, 0), + [PIPE_FORMAT_R10G10B10A2_UNORM] = { NV50_SURFACE_FORMAT_RGB10_A2_UNORM, + A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 10_10_10_2, 0), SAMPLER_VIEW | RENDER_TARGET | VERTEX_BUFFER | SCANOUT }, - [PIPE_FORMAT_B10G10R10A2_UNORM] = { NV50_SURFACE_FORMAT_A2R10G10B10_UNORM, - A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 2_10_10_10, 1), + [PIPE_FORMAT_B10G10R10A2_UNORM] = { NV50_SURFACE_FORMAT_BGR10_A2_UNORM, + A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 10_10_10_2, 1), SAMPLER_VIEW | RENDER_TARGET | VERTEX_BUFFER }, /* DEPTH/STENCIL FORMATS */ @@ -111,25 +115,24 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, Z16, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_Z24_UNORM_S8_USCALED] = { NV50_ZETA_FORMAT_S8Z24_UNORM, - B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, S8Z24, 0), + [PIPE_FORMAT_Z24_UNORM_S8_USCALED] = { NV50_ZETA_FORMAT_Z24_S8_UNORM, + B_(C0, C1, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, Z24_S8, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_Z24X8_UNORM] = { NV50_ZETA_FORMAT_X8Z24_UNORM, - B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, X8Z24, 0), + [PIPE_FORMAT_Z24X8_UNORM] = { NV50_ZETA_FORMAT_Z24_X8_UNORM, + B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, Z24_X8, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_S8_USCALED_Z24_UNORM] = { NV50_ZETA_FORMAT_Z24S8_UNORM, - B_(C1, C1, C1, ONE_FLOAT, UINT, UNORM, UINT, UINT, Z24S8, 0), + [PIPE_FORMAT_S8_USCALED_Z24_UNORM] = { NV50_ZETA_FORMAT_S8_Z24_UNORM, + B_(C1, C0, C1, ONE_FLOAT, UINT, UNORM, UINT, UINT, S8_Z24, 0), SAMPLER_VIEW | DEPTH_STENCIL }, [PIPE_FORMAT_Z32_FLOAT] = { NV50_ZETA_FORMAT_Z32_FLOAT, B_(C0, C0, C0, ONE_FLOAT, FLOAT, UINT, UINT, UINT, Z32, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED] = { - NV50_ZETA_FORMAT_Z32_FLOAT_X24S8_UNORM, - B_(C0, C0, C0, ONE_FLOAT, FLOAT, UINT, UINT, UINT, X24S8Z32, 0), + [PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED] = { NV50_ZETA_FORMAT_Z32_S8_X24_FLOAT, + B_(C0, C0, C0, ONE_FLOAT, FLOAT, UINT, UINT, UINT, Z32_S8_X24, 0), SAMPLER_VIEW | DEPTH_STENCIL }, /* LUMINANCE, ALPHA, INTENSITY */ @@ -278,15 +281,15 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* FLOAT 16 */ - [PIPE_FORMAT_R16G16B16A16_FLOAT] = { NV50_SURFACE_FORMAT_R16G16B16A16_FLOAT, + [PIPE_FORMAT_R16G16B16A16_FLOAT] = { NV50_SURFACE_FORMAT_RGBA16_FLOAT, A_(C0, C1, C2, C3, FLOAT, FLOAT, FLOAT, FLOAT, 16_16_16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R16G16B16_FLOAT] = { NV50_SURFACE_FORMAT_R16G16B16X16_FLOAT, + [PIPE_FORMAT_R16G16B16_FLOAT] = { NV50_SURFACE_FORMAT_RGBX16_FLOAT, A_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 16_16_16, 0), - VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R16G16_FLOAT] = { NV50_SURFACE_FORMAT_R16G16_FLOAT, + [PIPE_FORMAT_R16G16_FLOAT] = { NV50_SURFACE_FORMAT_RG16_FLOAT, A_(C0, C1, ZERO, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -296,15 +299,15 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* FLOAT 32 */ - [PIPE_FORMAT_R32G32B32A32_FLOAT] = { NV50_SURFACE_FORMAT_R32G32B32A32_FLOAT, + [PIPE_FORMAT_R32G32B32A32_FLOAT] = { NV50_SURFACE_FORMAT_RGBA32_FLOAT, A_(C0, C1, C2, C3, FLOAT, FLOAT, FLOAT, FLOAT, 32_32_32_32, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R32G32B32_FLOAT] = { NV50_SURFACE_FORMAT_R32G32B32X32_FLOAT, + [PIPE_FORMAT_R32G32B32_FLOAT] = { NV50_SURFACE_FORMAT_RGBX32_FLOAT, A_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 32_32_32, 0), - VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R32G32_FLOAT] = { NV50_SURFACE_FORMAT_R32G32_FLOAT, + [PIPE_FORMAT_R32G32_FLOAT] = { NV50_SURFACE_FORMAT_RG32_FLOAT, A_(C0, C1, ZERO, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 32_32, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -314,12 +317,12 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* ODD FORMATS */ - [PIPE_FORMAT_R11G11B10_FLOAT] = { NV50_SURFACE_FORMAT_B10G11R11_FLOAT, - B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 10_11_11, 0), + [PIPE_FORMAT_R11G11B10_FLOAT] = { NV50_SURFACE_FORMAT_R11G11B10_FLOAT, + B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 11_11_10, 0), SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R9G9B9E5_FLOAT] = { 0, - B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, E5_9_9_9, 0), + B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 9_9_9_E5, 0), SAMPLER_VIEW }, /* SNORM 32 */ @@ -330,7 +333,7 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = [PIPE_FORMAT_R32G32B32_SNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 32_32_32, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, [PIPE_FORMAT_R32G32_SNORM] = { 0, A_(C0, C1, ZERO, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 32_32, 0), @@ -348,7 +351,7 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = [PIPE_FORMAT_R32G32B32_UNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 32_32_32, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, [PIPE_FORMAT_R32G32_UNORM] = { 0, A_(C0, C1, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 32_32, 0), @@ -360,15 +363,15 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* SNORM 16 */ - [PIPE_FORMAT_R16G16B16A16_SNORM] = { NV50_SURFACE_FORMAT_R16G16B16A16_SNORM, + [PIPE_FORMAT_R16G16B16A16_SNORM] = { NV50_SURFACE_FORMAT_RGBA16_SNORM, A_(C0, C1, C2, C3, SNORM, SNORM, SNORM, SNORM, 16_16_16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R16G16B16_SNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 16_16_16, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R16G16_SNORM] = { NV50_SURFACE_FORMAT_R16G16_SNORM, + [PIPE_FORMAT_R16G16_SNORM] = { NV50_SURFACE_FORMAT_RG16_SNORM, A_(C0, C1, ZERO, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -378,15 +381,15 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* UNORM 16 */ - [PIPE_FORMAT_R16G16B16A16_UNORM] = { NV50_SURFACE_FORMAT_R16G16B16A16_UNORM, + [PIPE_FORMAT_R16G16B16A16_UNORM] = { NV50_SURFACE_FORMAT_RGBA16_UNORM, A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 16_16_16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R16G16B16_UNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 16_16_16, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R16G16_UNORM] = { NV50_SURFACE_FORMAT_R16G16_UNORM, + [PIPE_FORMAT_R16G16_UNORM] = { NV50_SURFACE_FORMAT_RG16_UNORM, A_(C0, C1, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -396,15 +399,15 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* SNORM 8 */ - [PIPE_FORMAT_R8G8B8A8_SNORM] = { NV50_SURFACE_FORMAT_A8B8G8R8_SNORM, + [PIPE_FORMAT_R8G8B8A8_SNORM] = { NV50_SURFACE_FORMAT_RGBA8_SNORM, A_(C0, C1, C2, C3, SNORM, SNORM, SNORM, SNORM, 8_8_8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R8G8B8_SNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 8_8_8, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R8G8_SNORM] = { NV50_SURFACE_FORMAT_R8G8_SNORM, + [PIPE_FORMAT_R8G8_SNORM] = { NV50_SURFACE_FORMAT_RG8_SNORM, A_(C0, C1, ZERO, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -414,23 +417,23 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* UNORM 8 */ - [PIPE_FORMAT_R8G8B8A8_UNORM] = { NV50_SURFACE_FORMAT_A8B8G8R8_UNORM, + [PIPE_FORMAT_R8G8B8A8_UNORM] = { NV50_SURFACE_FORMAT_RGBA8_UNORM, A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R8G8B8A8_SRGB] = { NV50_SURFACE_FORMAT_A8B8G8R8_SRGB, - A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), + [PIPE_FORMAT_R8G8B8A8_SRGB] = { NV50_SURFACE_FORMAT_RGBA8_SRGB, + B_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R8G8B8_UNORM] = { NV50_SURFACE_FORMAT_X8B8G8R8_UNORM, - A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8, 0), - VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, + [PIPE_FORMAT_R8G8B8X8_UNORM] = { NV50_SURFACE_FORMAT_RGBX8_UNORM, + B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), + SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R8G8B8_SRGB] = { NV50_SURFACE_FORMAT_X8B8G8R8_SRGB, + [PIPE_FORMAT_R8G8B8_UNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8, 0), - SAMPLER_VIEW | RENDER_TARGET }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R8G8_UNORM] = { NV50_SURFACE_FORMAT_R8G8_UNORM, + [PIPE_FORMAT_R8G8_UNORM] = { NV50_SURFACE_FORMAT_RG8_UNORM, A_(C0, C1, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -549,11 +552,11 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = /* OTHER FORMATS */ [PIPE_FORMAT_R8G8_B8G8_UNORM] = { 0, - B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, C1_C2_C1_C0, 0), + B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, U8_YA8_V8_YB8, 0), SAMPLER_VIEW }, [PIPE_FORMAT_G8R8_G8B8_UNORM] = { 0, - B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, C2_C1_C0_C1, 0), + B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, YA8_U8_YB8_V8, 0), SAMPLER_VIEW }, [PIPE_FORMAT_R8SG8SB8UX8U_NORM] = { 0, @@ -561,11 +564,11 @@ const struct nv50_format nv50_format_table[PIPE_FORMAT_COUNT] = SAMPLER_VIEW }, [PIPE_FORMAT_R5SG5SB6U_NORM] = { 0, - B_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, UNORM, UNORM, 6_5_5, 0), + B_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, UNORM, UNORM, 5_5_6, 0), SAMPLER_VIEW }, - [PIPE_FORMAT_R1_UNORM] = { 0, - B_(C0, ZERO, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, BITMAP_8X8, 0), + [PIPE_FORMAT_R1_UNORM] = { NV50_SURFACE_FORMAT_BITMAP, + B_(C0, ZERO, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, BITMAP, 0), SAMPLER_VIEW }, [PIPE_FORMAT_A8B8G8R8_UNORM] = { 0, diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c index 486b368ae98..bc81604508b 100644 --- a/src/gallium/drivers/nv50/nv50_miptree.c +++ b/src/gallium/drivers/nv50/nv50_miptree.c @@ -27,52 +27,90 @@ #include "nv50_context.h" #include "nv50_resource.h" -#include "nv50_transfer.h" static INLINE uint32_t -get_tile_dims(unsigned nx, unsigned ny, unsigned nz) +nv50_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz) { - uint32_t tile_mode = 0x00; - - if (ny > 32) tile_mode = 0x04; /* height 128 tiles */ - else - if (ny > 16) tile_mode = 0x03; /* height 64 tiles */ - else - if (ny > 8) tile_mode = 0x02; /* height 32 tiles */ - else - if (ny > 4) tile_mode = 0x01; /* height 16 tiles */ - - if (nz == 1) - return tile_mode; - else - if (tile_mode > 0x02) - tile_mode = 0x02; - - if (nz > 16 && tile_mode < 0x02) - return tile_mode | 0x50; /* depth 32 tiles */ - if (nz > 8) return tile_mode | 0x40; /* depth 16 tiles */ - if (nz > 4) return tile_mode | 0x30; /* depth 8 tiles */ - if (nz > 2) return tile_mode | 0x20; /* depth 4 tiles */ - - return tile_mode | 0x10; + return nvc0_tex_choose_tile_dims(nx, ny * 2, nz) >> 4; } -static INLINE unsigned -calc_zslice_offset(uint32_t tile_mode, unsigned z, unsigned pitch, unsigned nbh) +static uint32_t +nv50_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed) { - unsigned tile_h = NV50_TILE_HEIGHT(tile_mode); - unsigned tile_d_shift = NV50_TILE_DIM_SHIFT(tile_mode, 1); - unsigned tile_d = 1 << tile_d_shift; + const unsigned ms = util_logbase2(mt->base.base.nr_samples); - /* stride_2d == to next slice within this volume tile */ - /* stride_3d == size (in bytes) of a volume tile */ - unsigned stride_2d = tile_h * NV50_TILE_PITCH(tile_mode); - unsigned stride_3d = tile_d * align(nbh, tile_h) * pitch; + uint32_t tile_flags; + + if (mt->base.base.bind & PIPE_BIND_CURSOR) + return NOUVEAU_BO_TILE_SCANOUT; + + switch (mt->base.base.format) { + case PIPE_FORMAT_Z16_UNORM: + tile_flags = 0x6c00 + (ms << 8); + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + tile_flags = 0x1800 + (ms << 8); + break; + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + tile_flags = 0x22800 + (ms << 8); + break; + case PIPE_FORMAT_Z32_FLOAT: + tile_flags = 0x4000 + (ms << 8); + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + tile_flags = 0x6000 + (ms << 8); + break; + default: + switch (util_format_get_blocksizebits(mt->base.base.format)) { + case 128: + assert(ms < 3); + tile_flags = 0x7400; + break; + case 64: + switch (ms) { + case 2: tile_flags = 0x17c00; break; + case 3: tile_flags = 0x17d00; break; + default: + tile_flags = 0x7000; + break; + } + break; + case 32: + if (mt->base.base.bind & PIPE_BIND_SCANOUT) { + assert(ms == 0); + tile_flags = 0x7a00; + } else { + switch (ms) { + case 2: tile_flags = 0x17800; break; + case 3: tile_flags = 0x17900; break; + default: + tile_flags = 0x7000; + break; + } + } + break; + case 16: + case 8: + tile_flags = 0x7000; + break; + default: + return 0; + } + if (mt->base.base.bind & PIPE_BIND_CURSOR) + tile_flags = 0; + } + + if (mt->base.base.bind & (PIPE_BIND_SCANOUT | PIPE_BIND_CURSOR)) + tile_flags |= NOUVEAU_BO_TILE_SCANOUT; + + if (!compressed) + tile_flags &= ~0x30000; - return (z & (tile_d - 1)) * stride_2d + (z >> tile_d_shift) * stride_3d; + return tile_flags; } -static void +void nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) { struct nv50_miptree *mt = nv50_miptree(pt); @@ -82,7 +120,7 @@ nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) FREE(mt); } -static boolean +boolean nv50_miptree_get_handle(struct pipe_screen *pscreen, struct pipe_resource *pt, struct winsys_handle *whandle) @@ -108,88 +146,95 @@ const struct u_resource_vtbl nv50_miptree_vtbl = nv50_miptree_destroy, /* resource_destroy */ nv50_miptree_transfer_new, /* get_transfer */ nv50_miptree_transfer_del, /* transfer_destroy */ - nv50_miptree_transfer_map, /* transfer_map */ + nv50_miptree_transfer_map, /* transfer_map */ u_default_transfer_flush_region, /* transfer_flush_region */ nv50_miptree_transfer_unmap, /* transfer_unmap */ u_default_transfer_inline_write /* transfer_inline_write */ }; -struct pipe_resource * -nv50_miptree_create(struct pipe_screen *pscreen, - const struct pipe_resource *templ) +static INLINE boolean +nv50_miptree_init_ms_mode(struct nv50_miptree *mt) { - struct nouveau_device *dev = nouveau_screen(pscreen)->device; - struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree); - struct pipe_resource *pt = &mt->base.base; - int ret; - unsigned w, h, d, l, alloc_size; - uint32_t tile_flags; - - if (!mt) - return NULL; - - mt->base.vtbl = &nv50_miptree_vtbl; - *pt = *templ; - pipe_reference_init(&pt->reference, 1); - pt->screen = pscreen; - - mt->layout_3d = pt->target == PIPE_TEXTURE_3D; - - w = pt->width0; - h = pt->height0; - d = mt->layout_3d ? pt->depth0 : 1; - - switch (pt->format) { - case PIPE_FORMAT_Z16_UNORM: - tile_flags = 0x6c00; + switch (mt->base.base.nr_samples) { + case 8: + mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS8; + mt->ms_x = 2; + mt->ms_y = 1; break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - tile_flags = 0x1800; - break; - case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - tile_flags = 0x2800; + case 4: + mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS4; + mt->ms_x = 1; + mt->ms_y = 1; break; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - case PIPE_FORMAT_R32G32B32_FLOAT: - tile_flags = 0x7400; + case 2: + mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS2; + mt->ms_x = 1; break; - case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: - tile_flags = 0x6000; + case 1: + case 0: + mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1; break; default: - if (pt->bind & PIPE_BIND_CURSOR) - tile_flags = 0; - else - if ((pt->bind & PIPE_BIND_SCANOUT) && - util_format_get_blocksizebits(pt->format) == 32) - tile_flags = 0x7a00; - else - tile_flags = 0x7000; - break; + NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples); + return FALSE; } - if (pt->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_CURSOR)) - tile_flags |= NOUVEAU_BO_TILE_SCANOUT; + return TRUE; +} + +boolean +nv50_miptree_init_layout_linear(struct nv50_miptree *mt) +{ + struct pipe_resource *pt = &mt->base.base; + + if (util_format_is_depth_or_stencil(pt->format)) + return FALSE; + + if ((pt->last_level > 0) || (pt->depth0 > 1) || (pt->array_size > 1)) + return FALSE; + if (mt->ms_x | mt->ms_y) + return FALSE; + + mt->level[0].pitch = align(pt->width0, 64); + + mt->total_size = mt->level[0].pitch * pt->height0; + + return TRUE; +} + +static void +nv50_miptree_init_layout_tiled(struct nv50_miptree *mt) +{ + struct pipe_resource *pt = &mt->base.base; + unsigned w, h, d, l; + const unsigned blocksize = util_format_get_blocksize(pt->format); + + mt->layout_3d = pt->target == PIPE_TEXTURE_3D; + + w = pt->width0 << mt->ms_x; + h = pt->height0 << mt->ms_y; /* For 3D textures, a mipmap is spanned by all the layers, for array * textures and cube maps, each layer contains its own mipmaps. */ + d = mt->layout_3d ? pt->depth0 : 1; + for (l = 0; l <= pt->last_level; ++l) { struct nv50_miptree_level *lvl = &mt->level[l]; + unsigned tsx, tsy, tsz; unsigned nbx = util_format_get_nblocksx(pt->format, w); unsigned nby = util_format_get_nblocksy(pt->format, h); - unsigned blocksize = util_format_get_blocksize(pt->format); lvl->offset = mt->total_size; - if (tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK) - lvl->tile_mode = get_tile_dims(nbx, nby, d); + lvl->tile_mode = nv50_tex_choose_tile_dims(nbx, nby, d); - lvl->pitch = align(nbx * blocksize, NV50_TILE_PITCH(lvl->tile_mode)); + tsx = NV50_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */ + tsy = NV50_TILE_SIZE_Y(lvl->tile_mode); + tsz = NV50_TILE_SIZE_Z(lvl->tile_mode); - mt->total_size += lvl->pitch * - align(nby, NV50_TILE_HEIGHT(lvl->tile_mode)) * - align(d, NV50_TILE_DEPTH(lvl->tile_mode)); + lvl->pitch = align(nbx * blocksize, tsx); + + mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz); w = u_minify(w, 1); h = u_minify(h, 1); @@ -201,10 +246,43 @@ nv50_miptree_create(struct pipe_screen *pscreen, NV50_TILE_SIZE(mt->level[0].tile_mode)); mt->total_size = mt->layer_stride * pt->array_size; } +} + +struct pipe_resource * +nv50_miptree_create(struct pipe_screen *pscreen, + const struct pipe_resource *templ) +{ + struct nouveau_device *dev = nouveau_screen(pscreen)->device; + struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree); + struct pipe_resource *pt = &mt->base.base; + int ret; + uint32_t tile_flags; + + if (!mt) + return NULL; + + mt->base.vtbl = &nv50_miptree_vtbl; + *pt = *templ; + pipe_reference_init(&pt->reference, 1); + pt->screen = pscreen; - alloc_size = mt->total_size; + tile_flags = nv50_mt_choose_storage_type(mt, TRUE); - ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 256, alloc_size, + if (!nv50_miptree_init_ms_mode(mt)) { + FREE(mt); + return NULL; + } + + if (tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK) { + nv50_miptree_init_layout_tiled(mt); + } else + if (!nv50_miptree_init_layout_linear(mt)) { + FREE(mt); + return NULL; + } + + ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 4096, + mt->total_size, mt->level[0].tile_mode, tile_flags, &mt->base.bo); if (ret) { @@ -255,58 +333,92 @@ nv50_miptree_from_handle(struct pipe_screen *pscreen, } +/* Offset of zslice @z from start of level @l. */ +INLINE unsigned +nv50_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z) +{ + const struct pipe_resource *pt = &mt->base.base; + + unsigned tds = NV50_TILE_SHIFT_Z(mt->level[l].tile_mode); + unsigned ths = NV50_TILE_SHIFT_Y(mt->level[l].tile_mode); + + unsigned nby = util_format_get_nblocksy(pt->format, + u_minify(pt->height0, l)); + + /* to next 2D tile slice within a 3D tile */ + unsigned stride_2d = NV50_TILE_SIZE_2D(mt->level[l].tile_mode); + + /* to slice in the next (in z direction) 3D tile */ + unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds; + + return (z & ((1 << tds) - 1)) * stride_2d + (z >> tds) * stride_3d; +} + /* Surface functions. */ -struct pipe_surface * -nv50_miptree_surface_new(struct pipe_context *pipe, - struct pipe_resource *pt, - const struct pipe_surface *templ) +struct nv50_surface * +nv50_surface_from_miptree(struct nv50_miptree *mt, + const struct pipe_surface *templ) { - struct nv50_miptree *mt = nv50_miptree(pt); /* guaranteed */ - struct nv50_surface *ns; struct pipe_surface *ps; - struct nv50_miptree_level *lvl = &mt->level[templ->u.tex.level]; - - ns = CALLOC_STRUCT(nv50_surface); + struct nv50_surface *ns = CALLOC_STRUCT(nv50_surface); if (!ns) return NULL; ps = &ns->base; pipe_reference_init(&ps->reference, 1); - pipe_resource_reference(&ps->texture, pt); - ps->context = pipe; + pipe_resource_reference(&ps->texture, &mt->base.base); + ps->format = templ->format; ps->usage = templ->usage; ps->u.tex.level = templ->u.tex.level; ps->u.tex.first_layer = templ->u.tex.first_layer; ps->u.tex.last_layer = templ->u.tex.last_layer; - ns->width = u_minify(pt->width0, ps->u.tex.level); - ns->height = u_minify(pt->height0, ps->u.tex.level); + ns->width = u_minify(mt->base.base.width0, ps->u.tex.level); + ns->height = u_minify(mt->base.base.height0, ps->u.tex.level); ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1; - ns->offset = lvl->offset; + ns->offset = mt->level[templ->u.tex.level].offset; /* comment says there are going to be removed, but they're used by the st */ ps->width = ns->width; ps->height = ns->height; - if (mt->layout_3d) { - unsigned zslice = ps->u.tex.first_layer; + ns->width <<= mt->ms_x; + ns->height <<= mt->ms_y; - /* TODO: re-layout the texture to use only depth 1 tiles in this case: */ - if (ns->depth > 1 && (zslice & (NV50_TILE_DEPTH(lvl->tile_mode) - 1))) - NOUVEAU_ERR("Creating unsupported 3D surface of slices [%u:%u].\n", - zslice, ps->u.tex.last_layer); + return ns; +} - ns->offset += calc_zslice_offset(lvl->tile_mode, zslice, lvl->pitch, - util_format_get_nblocksy(pt->format, - ns->height)); - } else { - ns->offset += mt->layer_stride * ps->u.tex.first_layer; +struct pipe_surface * +nv50_miptree_surface_new(struct pipe_context *pipe, + struct pipe_resource *pt, + const struct pipe_surface *templ) +{ + struct nv50_miptree *mt = nv50_miptree(pt); + struct nv50_surface *ns = nv50_surface_from_miptree(mt, templ); + if (!ns) + return NULL; + ns->base.context = pipe; + + if (ns->base.u.tex.first_layer) { + const unsigned l = ns->base.u.tex.level; + const unsigned z = ns->base.u.tex.first_layer; + + if (mt->layout_3d) { + ns->offset += nv50_mt_zslice_offset(mt, l, z); + + /* TODO: switch to depth 1 tiles; but actually this shouldn't happen */ + if (ns->depth > 1 && + (z & (NV50_TILE_SIZE_Z(mt->level[l].tile_mode) - 1))) + NOUVEAU_ERR("Creating unsupported 3D surface !\n"); + } else { + ns->offset += mt->layer_stride * z; + } } - return ps; + return &ns->base; } void diff --git a/src/gallium/drivers/nv50/nv50_resource.h b/src/gallium/drivers/nv50/nv50_resource.h index 0e9f0a2557e..66d21209be2 100644 --- a/src/gallium/drivers/nv50/nv50_resource.h +++ b/src/gallium/drivers/nv50/nv50_resource.h @@ -9,22 +9,32 @@ #include "nouveau/nouveau_buffer.h" #undef NOUVEAU_NVC0 +#ifndef __NVC0_RESOURCE_H__ /* make sure we don't use these in nvc0: */ + void nv50_init_resource_functions(struct pipe_context *pcontext); void nv50_screen_init_resource_functions(struct pipe_screen *pscreen); -#define NV50_TILE_DIM_SHIFT(m, d) (((m) >> (d * 4)) & 0xf) -#define NV50_TILE_PITCH(m) (64 << 0) -#define NV50_TILE_HEIGHT(m) ( 4 << NV50_TILE_DIM_SHIFT(m, 0)) -#define NV50_TILE_DEPTH(m) ( 1 << NV50_TILE_DIM_SHIFT(m, 1)) +#define NV50_TILE_SHIFT_X(m) 6 +#define NV50_TILE_SHIFT_Y(m) ((((m) >> 0) & 0xf) + 2) +#define NV50_TILE_SHIFT_Z(m) ((((m) >> 4) & 0xf) + 0) + +#define NV50_TILE_SIZE_X(m) 64 +#define NV50_TILE_SIZE_Y(m) ( 4 << (((m) >> 0) & 0xf)) +#define NV50_TILE_SIZE_Z(m) ( 1 << (((m) >> 4) & 0xf)) + +#define NV50_TILE_SIZE_2D(m) (NV50_TILE_SIZE_X(m) << NV50_TILE_SHIFT_Y(m)) -#define NV50_TILE_SIZE_2D(m) ((64 * 4) << \ - NV50_TILE_DIM_SHIFT(m, 0)) +#define NV50_TILE_SIZE(m) (NV50_TILE_SIZE_2D(m) << NV50_TILE_SHIFT_Z(m)) + +#endif /* __NVC0_RESOURCE_H__ */ + +uint32_t +nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz); -#define NV50_TILE_SIZE(m) (NV50_TILE_SIZE_2D(m) << NV50_TILE_DIM_SHIFT(m, 1)) struct nv50_miptree_level { uint32_t offset; @@ -40,6 +50,9 @@ struct nv50_miptree { uint32_t total_size; uint32_t layer_stride; boolean layout_3d; /* TRUE if layer count varies with mip level */ + uint8_t ms_x; /* log2 of number of samples in x/y dimension */ + uint8_t ms_y; + uint8_t ms_mode; }; static INLINE struct nv50_miptree * @@ -50,21 +63,73 @@ nv50_miptree(struct pipe_resource *pt) /* Internal functions: */ +boolean +nv50_miptree_init_layout_linear(struct nv50_miptree *mt); + struct pipe_resource * nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *tmp); +void +nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt); + struct pipe_resource * nv50_miptree_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *template, struct winsys_handle *whandle); +boolean +nv50_miptree_get_handle(struct pipe_screen *pscreen, + struct pipe_resource *pt, + struct winsys_handle *whandle); + +struct nv50_surface { + struct pipe_surface base; + uint32_t offset; + uint32_t width; + uint16_t height; + uint16_t depth; +}; + +static INLINE struct nv50_surface * +nv50_surface(struct pipe_surface *ps) +{ + return (struct nv50_surface *)ps; +} + +#ifndef __NVC0_RESOURCE_H__ + +unsigned +nv50_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z); + struct pipe_surface * nv50_miptree_surface_new(struct pipe_context *, struct pipe_resource *, const struct pipe_surface *templ); +struct pipe_transfer * +nv50_miptree_transfer_new(struct pipe_context *pcontext, + struct pipe_resource *pt, + unsigned level, + unsigned usage, + const struct pipe_box *box); +void +nv50_miptree_transfer_del(struct pipe_context *pcontext, + struct pipe_transfer *ptx); +void * +nv50_miptree_transfer_map(struct pipe_context *pcontext, + struct pipe_transfer *ptx); +void +nv50_miptree_transfer_unmap(struct pipe_context *pcontext, + struct pipe_transfer *ptx); + +#endif /* __NVC0_RESOURCE_H__ */ + +struct nv50_surface * +nv50_surface_from_miptree(struct nv50_miptree *mt, + const struct pipe_surface *templ); + void nv50_miptree_surface_del(struct pipe_context *, struct pipe_surface *); -#endif +#endif /* __NV50_RESOURCE_H__ */ diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c index 7e436fd47d8..581aad19627 100644 --- a/src/gallium/drivers/nv50/nv50_screen.c +++ b/src/gallium/drivers/nv50/nv50_screen.c @@ -43,7 +43,9 @@ nv50_screen_is_format_supported(struct pipe_screen *pscreen, unsigned sample_count, unsigned bindings) { - if (sample_count > 1) + if (sample_count > 2 && sample_count != 4 && sample_count != 8) + return FALSE; + if (sample_count == 8 && util_format_get_blocksizebits(format) >= 128) return FALSE; if (!util_format_is_supported(format, bindings)) @@ -89,6 +91,7 @@ nv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_TEXTURE_SHADOW_MAP: case PIPE_CAP_NPOT_TEXTURES: case PIPE_CAP_ANISOTROPIC_FILTER: + case PIPE_CAP_SCALED_RESOLVE: return 1; case PIPE_CAP_SEAMLESS_CUBE_MAP: return nv50_screen(pscreen)->tesla->grclass >= NVA0_3D; @@ -217,6 +220,7 @@ nv50_screen_destroy(struct pipe_screen *pscreen) nouveau_fence_wait(screen->base.fence.current); nouveau_fence_ref (NULL, &screen->base.fence.current); } + screen->base.channel->user_private = NULL; nouveau_bo_ref(NULL, &screen->code); nouveau_bo_ref(NULL, &screen->tls_bo); @@ -302,6 +306,7 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) FAIL_SCREEN_INIT("nouveau_screen_init failed: %d\n", ret); chan = screen->base.channel; + chan->user_private = screen; pscreen->winsys = ws; pscreen->destroy = nv50_screen_destroy; @@ -313,6 +318,8 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) nv50_screen_init_resource_functions(pscreen); + nouveau_screen_init_vdec(&screen->base); + ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096, &screen->fence.bo); if (ret) @@ -600,6 +607,9 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) screen->mm_VRAM_fe0 = nouveau_mm_create(dev, NOUVEAU_BO_VRAM, 0xfe0); + if (!nv50_blitctx_create(screen)) + goto fail; + nouveau_fence_new(&screen->base, &screen->base.fence.current, FALSE); return pscreen; diff --git a/src/gallium/drivers/nv50/nv50_screen.h b/src/gallium/drivers/nv50/nv50_screen.h index aea434b8679..315ca80c0d2 100644 --- a/src/gallium/drivers/nv50/nv50_screen.h +++ b/src/gallium/drivers/nv50/nv50_screen.h @@ -19,6 +19,10 @@ struct nv50_context; #define NV50_SCRATCH_SIZE (2 << 20) #define NV50_SCRATCH_NR_BUFFERS 2 +#define NV50_SCREEN_RESIDENT_BO_COUNT 5 + +struct nv50_blitctx; + struct nv50_screen { struct nouveau_screen base; struct nouveau_winsys *nvws; @@ -37,6 +41,8 @@ struct nv50_screen { struct nouveau_resource *gp_code_heap; struct nouveau_resource *fp_code_heap; + struct nv50_blitctx *blitctx; + struct { void **entries; int next; @@ -69,6 +75,8 @@ nv50_screen(struct pipe_screen *screen) return (struct nv50_screen *)screen; } +boolean nv50_blitctx_create(struct nv50_screen *); + void nv50_screen_make_buffers_resident(struct nv50_screen *); int nv50_screen_tic_alloc(struct nv50_screen *, void *); diff --git a/src/gallium/drivers/nv50/nv50_shader_state.c b/src/gallium/drivers/nv50/nv50_shader_state.c index e5b10c37bef..d73f7c7f213 100644 --- a/src/gallium/drivers/nv50/nv50_shader_state.c +++ b/src/gallium/drivers/nv50/nv50_shader_state.c @@ -130,13 +130,14 @@ nv50_program_validate(struct nv50_context *nv50, struct nv50_program *prog) int ret; unsigned size; - if (prog->translated) + if (!prog->translated) { + prog->translated = nv50_program_translate(prog); + if (!prog->translated) + return FALSE; + } else + if (prog->res) return TRUE; - prog->translated = nv50_program_translate(prog); - if (!prog->translated) - return FALSE; - if (prog->type == PIPE_SHADER_FRAGMENT) heap = nv50->screen->fp_code_heap; else if (prog->type == PIPE_SHADER_GEOMETRY) heap = nv50->screen->gp_code_heap; diff --git a/src/gallium/drivers/nv50/nv50_state.c b/src/gallium/drivers/nv50/nv50_state.c index fb125f3a8d8..49ea646c77c 100644 --- a/src/gallium/drivers/nv50/nv50_state.c +++ b/src/gallium/drivers/nv50/nv50_state.c @@ -119,6 +119,7 @@ nv50_blend_state_create(struct pipe_context *pipe, struct nv50_blend_stateobj *so = CALLOC_STRUCT(nv50_blend_stateobj); int i; boolean emit_common_func = cso->rt[0].blend_enable; + uint32_t ms; if (nv50_context(pipe)->screen->tesla->grclass >= NVA3_3D) { SB_BEGIN_3D(so, BLEND_INDEPENDENT, 1); @@ -190,6 +191,15 @@ nv50_blend_state_create(struct pipe_context *pipe, SB_DATA (so, nv50_colormask(cso->rt[0].colormask)); } + ms = 0; + if (cso->alpha_to_coverage) + ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; + if (cso->alpha_to_one) + ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; + + SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1); + SB_DATA (so, ms); + assert(so->size <= (sizeof(so->state) / sizeof(so->state[0]))); return so; } @@ -237,6 +247,9 @@ nv50_rasterizer_state_create(struct pipe_context *pipe, SB_BEGIN_3D(so, FRAG_COLOR_CLAMP_EN, 1); SB_DATA (so, cso->clamp_fragment_color ? 0x11111111 : 0x00000000); + SB_BEGIN_3D(so, MULTISAMPLE_ENABLE, 1); + SB_DATA (so, cso->multisample); + SB_BEGIN_3D(so, LINE_WIDTH, 1); SB_DATA (so, fui(cso->line_width)); SB_BEGIN_3D(so, LINE_SMOOTH_ENABLE, 1); diff --git a/src/gallium/drivers/nv50/nv50_state_validate.c b/src/gallium/drivers/nv50/nv50_state_validate.c index 11561f5a8e6..44f2d25c1a7 100644 --- a/src/gallium/drivers/nv50/nv50_state_validate.c +++ b/src/gallium/drivers/nv50/nv50_state_validate.c @@ -8,6 +8,7 @@ nv50_validate_fb(struct nv50_context *nv50) struct nouveau_channel *chan = nv50->screen->base.channel; struct pipe_framebuffer_state *fb = &nv50->framebuffer; unsigned i; + unsigned ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1; boolean serialize = FALSE; nv50_bufctx_reset(nv50, NV50_BUFCTX_FRAME); @@ -38,6 +39,8 @@ nv50_validate_fb(struct nv50_context *nv50) BEGIN_RING(chan, RING_3D(RT_ARRAY_MODE), 1); OUT_RING (chan, sf->depth); + ms_mode = mt->ms_mode; + if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) serialize = TRUE; mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; @@ -69,6 +72,8 @@ nv50_validate_fb(struct nv50_context *nv50) OUT_RING (chan, sf->height); OUT_RING (chan, (unk << 16) | sf->depth); + ms_mode = mt->ms_mode; + if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) serialize = TRUE; mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; @@ -81,6 +86,9 @@ nv50_validate_fb(struct nv50_context *nv50) OUT_RING (chan, 0); } + BEGIN_RING(chan, RING_3D(MULTISAMPLE_MODE), 1); + OUT_RING (chan, ms_mode); + BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2); OUT_RING (chan, fb->width << 16); OUT_RING (chan, fb->height << 16); @@ -258,6 +266,26 @@ nv50_validate_rasterizer(struct nv50_context *nv50) } static void +nv50_validate_sample_mask(struct nv50_context *nv50) +{ + struct nouveau_channel *chan = nv50->screen->base.channel; + + unsigned mask[4] = + { + nv50->sample_mask & 0xffff, + nv50->sample_mask & 0xffff, + nv50->sample_mask & 0xffff, + nv50->sample_mask & 0xffff + }; + + BEGIN_RING(chan, RING_3D(MSAA_MASK(0)), 4); + OUT_RING (chan, mask[0]); + OUT_RING (chan, mask[1]); + OUT_RING (chan, mask[2]); + OUT_RING (chan, mask[3]); +} + +static void nv50_switch_pipe_context(struct nv50_context *ctx_to) { struct nv50_context *ctx_from = ctx_to->screen->cur_ctx; @@ -282,8 +310,7 @@ nv50_switch_pipe_context(struct nv50_context *ctx_to) if (!ctx_to->zsa) ctx_to->dirty &= ~NV50_NEW_ZSA; - ctx_to->screen->base.channel->user_private = ctx_to->screen->cur_ctx = - ctx_to; + ctx_to->screen->cur_ctx = ctx_to; } static struct state_validate { @@ -293,6 +320,7 @@ static struct state_validate { { nv50_validate_fb, NV50_NEW_FRAMEBUFFER }, { nv50_validate_blend, NV50_NEW_BLEND }, { nv50_validate_zsa, NV50_NEW_ZSA }, + { nv50_validate_sample_mask, NV50_NEW_SAMPLE_MASK }, { nv50_validate_rasterizer, NV50_NEW_RASTERIZER }, { nv50_validate_blend_colour, NV50_NEW_BLEND_COLOUR }, { nv50_validate_stencil_ref, NV50_NEW_STENCIL_REF }, @@ -322,7 +350,7 @@ static struct state_validate { #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0])) boolean -nv50_state_validate(struct nv50_context *nv50) +nv50_state_validate(struct nv50_context *nv50, unsigned words) { unsigned i; @@ -339,6 +367,8 @@ nv50_state_validate(struct nv50_context *nv50) nv50->dirty = 0; } + MARK_RING(nv50->screen->base.channel, words, 0); + nv50_bufctx_emit_relocs(nv50); return TRUE; diff --git a/src/gallium/drivers/nv50/nv50_stateobj.h b/src/gallium/drivers/nv50/nv50_stateobj.h index 4c98c7e46fc..d367a064d61 100644 --- a/src/gallium/drivers/nv50/nv50_stateobj.h +++ b/src/gallium/drivers/nv50/nv50_stateobj.h @@ -21,13 +21,13 @@ struct nv50_blend_stateobj { struct pipe_blend_state pipe; int size; - uint32_t state[82]; // TODO: allocate less if !independent_blend_enable + uint32_t state[84]; // TODO: allocate less if !independent_blend_enable }; struct nv50_rasterizer_stateobj { struct pipe_rasterizer_state pipe; int size; - uint32_t state[42]; + uint32_t state[44]; }; struct nv50_zsa_stateobj { diff --git a/src/gallium/drivers/nv50/nv50_surface.c b/src/gallium/drivers/nv50/nv50_surface.c index 3d7e880ccce..1a5077e970b 100644 --- a/src/gallium/drivers/nv50/nv50_surface.c +++ b/src/gallium/drivers/nv50/nv50_surface.c @@ -34,25 +34,16 @@ #include "nv50_defs.xml.h" +#define NV50_ENG2D_SUPPORTED_FORMATS 0xff0843e080608409ULL + /* return TRUE for formats that can be converted among each other by NV50_2D */ static INLINE boolean nv50_2d_format_faithful(enum pipe_format format) { - switch (format) { - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_B8G8R8A8_SRGB: - case PIPE_FORMAT_B8G8R8X8_SRGB: - case PIPE_FORMAT_B5G6R5_UNORM: - case PIPE_FORMAT_B5G5R5A1_UNORM: - case PIPE_FORMAT_B10G10R10A2_UNORM: - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R32G32B32A32_FLOAT: - case PIPE_FORMAT_R32G32B32_FLOAT: - return TRUE; - default: - return FALSE; - } + uint8_t id = nv50_format_table[format].rt; + + return (id >= 0xc0) && + (NV50_ENG2D_SUPPORTED_FORMATS & (1ULL << (id - 0xc0))); } static INLINE uint8_t @@ -63,7 +54,7 @@ nv50_2d_format(enum pipe_format format) /* Hardware values for color formats range from 0xc0 to 0xff, * but the 2D engine doesn't support all of them. */ - if ((id >= 0xc0) && (0xff0843e080608409ULL & (1ULL << (id - 0xc0)))) + if ((id >= 0xc0) && (NV50_ENG2D_SUPPORTED_FORMATS & (1ULL << (id - 0xc0)))) return id; switch (util_format_get_blocksize(format)) { @@ -72,7 +63,7 @@ nv50_2d_format(enum pipe_format format) case 2: return NV50_SURFACE_FORMAT_R16_UNORM; case 4: - return NV50_SURFACE_FORMAT_A8R8G8B8_UNORM; + return NV50_SURFACE_FORMAT_BGRA8_UNORM; default: return 0; } @@ -96,8 +87,8 @@ nv50_2d_texture_set(struct nouveau_channel *chan, int dst, return 1; } - width = u_minify(mt->base.base.width0, level); - height = u_minify(mt->base.base.height0, level); + width = u_minify(mt->base.base.width0, level) << mt->ms_x; + height = u_minify(mt->base.base.height0, level) << mt->ms_y; offset = mt->level[level].offset; if (!mt->layout_3d) { @@ -152,7 +143,13 @@ nv50_2d_texture_do_copy(struct nouveau_channel *chan, unsigned sx, unsigned sy, unsigned sz, unsigned w, unsigned h) { + static const uint32_t duvdxy[5] = + { + 0x40000000, 0x80000000, 0x00000001, 0x00000002, 0x00000004 + }; + int ret; + uint32_t ctrl; ret = MARK_RING(chan, 2 * 16 + 32, 4); if (ret) @@ -166,24 +163,28 @@ nv50_2d_texture_do_copy(struct nouveau_channel *chan, if (ret) return ret; - /* 0/1 = CENTER/CORNER, 10/00 = POINT/BILINEAR */ + /* NOTE: 2D engine doesn't work for MS8 */ + if (src->ms_x) + ctrl = 0x11; + + /* 0/1 = CENTER/CORNER, 00/10 = POINT/BILINEAR */ BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1); - OUT_RING (chan, 0); + OUT_RING (chan, ctrl); BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4); - OUT_RING (chan, dx); - OUT_RING (chan, dy); - OUT_RING (chan, w); - OUT_RING (chan, h); + OUT_RING (chan, dx << dst->ms_x); + OUT_RING (chan, dy << dst->ms_y); + OUT_RING (chan, w << dst->ms_x); + OUT_RING (chan, h << dst->ms_y); BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4); - OUT_RING (chan, 0); - OUT_RING (chan, 1); - OUT_RING (chan, 0); - OUT_RING (chan, 1); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0xf0000000); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0x0000000f); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0xf0000000); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0x0000000f); BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4); OUT_RING (chan, 0); - OUT_RING (chan, sx); + OUT_RING (chan, sx << src->ms_x); OUT_RING (chan, 0); - OUT_RING (chan, sy); + OUT_RING (chan, sy << src->ms_y); return 0; } @@ -206,6 +207,34 @@ nv50_resource_copy_region(struct pipe_context *pipe, return; } + nv04_resource(dst)->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; + + if (src->format == dst->format && src->nr_samples == dst->nr_samples) { + struct nv50_m2mf_rect drect, srect; + unsigned i; + unsigned nx = util_format_get_nblocksx(src->format, src_box->width); + unsigned ny = util_format_get_nblocksy(src->format, src_box->height); + + nv50_m2mf_rect_setup(&drect, dst, dst_level, dstx, dsty, dstz); + nv50_m2mf_rect_setup(&srect, src, src_level, + src_box->x, src_box->y, src_box->z); + + for (i = 0; i < src_box->depth; ++i) { + nv50_m2mf_transfer_rect(&screen->base.base, &drect, &srect, nx, ny); + + if (nv50_miptree(dst)->layout_3d) + drect.z++; + else + drect.base += nv50_miptree(dst)->layer_stride; + + if (nv50_miptree(src)->layout_3d) + srect.z++; + else + srect.base += nv50_miptree(src)->layer_stride; + } + return; + } + assert((src->format == dst->format) || (nv50_2d_format_faithful(src->format) && nv50_2d_format_faithful(dst->format))); @@ -339,7 +368,7 @@ nv50_clear(struct pipe_context *pipe, unsigned buffers, /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */ nv50->dirty &= NV50_NEW_FRAMEBUFFER; - if (!nv50_state_validate(nv50)) + if (!nv50_state_validate(nv50, 9 + (fb->nr_cbufs * 2))) return; if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { @@ -376,12 +405,546 @@ nv50_clear(struct pipe_context *pipe, unsigned buffers, nv50->dirty = dirty & ~NV50_NEW_FRAMEBUFFER; } + +struct nv50_blitctx +{ + struct nv50_screen *screen; + struct { + struct pipe_framebuffer_state fb; + struct nv50_program *vp; + struct nv50_program *gp; + struct nv50_program *fp; + unsigned num_textures[3]; + unsigned num_samplers[3]; + struct pipe_sampler_view *texture; + struct nv50_tsc_entry *sampler; + unsigned dirty; + unsigned clip_nr; + } saved; + struct nv50_program vp; + struct nv50_program fp; + struct nv50_tsc_entry sampler[2]; /* nearest, bilinear */ + uint32_t fp_offset; + uint16_t color_mask; + uint8_t filter; +}; + +static void +nv50_blitctx_make_vp(struct nv50_blitctx *blit) +{ + static const uint32_t code[] = + { + 0x10000001, /* mov b32 o[0x00] s[0x00] */ /* HPOS.x */ + 0x0423c788, + 0x10000205, /* mov b32 o[0x04] s[0x04] */ /* HPOS.y */ + 0x0423c788, + 0x10000409, /* mov b32 o[0x08] s[0x08] */ /* TEXC.x */ + 0x0423c788, + 0x1000060d, /* mov b32 o[0x0c] s[0x0c] */ /* TEXC.y */ + 0x0423c788, + 0x10000811, /* exit mov b32 o[0x10] s[0x10] */ /* TEXC.z */ + 0x0423c789, + }; + + blit->vp.type = PIPE_SHADER_VERTEX; + blit->vp.translated = TRUE; + blit->vp.code = (uint32_t *)code; /* const_cast */ + blit->vp.code_size = sizeof(code); + blit->vp.max_gpr = 4; + blit->vp.max_out = 5; + blit->vp.out_nr = 2; + blit->vp.out[0].mask = 0x3; + blit->vp.out[0].sn = TGSI_SEMANTIC_POSITION; + blit->vp.out[1].hw = 2; + blit->vp.out[1].mask = 0x7; + blit->vp.out[1].sn = TGSI_SEMANTIC_GENERIC; + blit->vp.vp.attrs[0] = 0x73; + blit->vp.vp.psiz = 0x40; + blit->vp.vp.edgeflag = 0x40; +} + +static void +nv50_blitctx_make_fp(struct nv50_blitctx *blit) +{ + static const uint32_t code[] = + { + /* 3 coords RGBA in, RGBA out, also for Z32_FLOAT(_S8X24_USCALED) */ + 0x80000000, /* interp $r0 v[0x0] */ + 0x80010004, /* interp $r1 v[0x4] */ + 0x80020009, /* interp $r2 flat v[0x8] */ + 0x00040780, + 0xf6800001, /* texauto live { $r0,1,2,3 } $t0 $s0 { $r0,1,2 } */ + 0x0000c785, /* exit */ + + /* 3 coords ZS in, S encoded in R, Z encoded in GBA (8_UNORM) */ + 0x80000000, /* interp $r0 v[0x00] */ + 0x80010004, /* interp $r1 v[0x04] */ + 0x80020009, /* interp $r2 flat v[0x8] */ + 0x00040780, + 0xf6800001, /* texauto live { $r0,1,#,# } $t0 $s0 { $r0,1,2 } */ + 0x00000784, + 0xc03f0009, /* mul f32 $r2 $r0 (2^24 - 1) */ + 0x04b7ffff, + 0xa0000201, /* cvt f32 $r0 s32 $r1 */ + 0x44014780, + 0xa0000409, /* cvt rni s32 $r2 f32 $r2 */ + 0x8c004780, + 0xc0010001, /* mul f32 $r0 $r0 1/0xff */ + 0x03b8080b, + 0xd03f0405, /* and b32 $r1 $r2 0x0000ff */ + 0x0000000f, + 0xd000040d, /* and b32 $r3 $r2 0xff0000 */ + 0x000ff003, + 0xd0000409, /* and b32 $r2 $r2 0x00ff00 */ + 0x00000ff3, + 0xa0000205, /* cvt f32 $r1 s32 $r1 */ + 0x44014780, + 0xa000060d, /* cvt f32 $r3 s32 $r3 */ + 0x44014780, + 0xa0000409, /* cvt f32 $r2 s32 $r2 */ + 0x44014780, + 0xc0010205, /* mul f32 $r1 $r1 1/0x0000ff */ + 0x03b8080b, + 0xc001060d, /* mul f32 $r3 $r3 1/0x00ff00 */ + 0x0338080b, + 0xc0010409, /* mul f32 $r2 $r2 1/0xff0000 */ + 0x0378080b, + 0xf0000001, /* exit never nop */ + 0xe0000001, + + /* 3 coords ZS in, Z encoded in RGB, S encoded in A (U8_UNORM) */ + 0x80000000, /* interp $r0 v[0x00] */ + 0x80010004, /* interp $r1 v[0x04] */ + 0x80020009, /* interp $r2 flat v[0x8] */ + 0x00040780, + 0xf6800001, /* texauto live { $r0,1,#,# } $t0 $s0 { $r0,1,2 } */ + 0x00000784, + 0xc03f0009, /* mul f32 $r2 $r0 (2^24 - 1) */ + 0x04b7ffff, + 0xa0000281, /* cvt f32 $r3 s32 $r1 */ + 0x44014780, + 0xa0000409, /* cvt rni s32 $r2 f32 $r2 */ + 0x8c004780, + 0xc001060d, /* mul f32 $r3 $r3 1/0xff */ + 0x03b8080b, + 0xd03f0401, /* and b32 $r0 $r2 0x0000ff */ + 0x0000000f, + 0xd0000405, /* and b32 $r1 $r2 0x00ff00 */ + 0x00000ff3, + 0xd0000409, /* and b32 $r2 $r2 0xff0000 */ + 0x000ff003, + 0xa0000001, /* cvt f32 $r0 s32 $r0 */ + 0x44014780, + 0xa0000205, /* cvt f32 $r1 s32 $r1 */ + 0x44014780, + 0xa0000409, /* cvt f32 $r2 s32 $r2 */ + 0x44014780, + 0xc0010001, /* mul f32 $r0 $r0 1/0x0000ff */ + 0x03b8080b, + 0xc0010205, /* mul f32 $r1 $r1 1/0x00ff00 */ + 0x0378080b, + 0xc0010409, /* mul f32 $r2 $r2 1/0xff0000 */ + 0x0338080b, + 0xf0000001, /* exit never nop */ + 0xe0000001 + }; + + blit->fp.type = PIPE_SHADER_FRAGMENT; + blit->fp.translated = TRUE; + blit->fp.code = (uint32_t *)code; /* const_cast */ + blit->fp.code_size = sizeof(code); + blit->fp.max_gpr = 4; + blit->fp.max_out = 4; + blit->fp.in_nr = 1; + blit->fp.in[0].mask = 0x7; /* last component flat */ + blit->fp.in[0].linear = 1; + blit->fp.in[0].sn = TGSI_SEMANTIC_GENERIC; + blit->fp.out_nr = 1; + blit->fp.out[0].mask = 0xf; + blit->fp.out[0].sn = TGSI_SEMANTIC_COLOR; + blit->fp.fp.interp = 0x00020403; + blit->fp.gp.primid = 0x80; +} + +static void +nv50_blitctx_make_sampler(struct nv50_blitctx *blit) +{ + /* clamp to edge, min/max lod = 0, nearest filtering */ + + blit->sampler[0].id = -1; + + blit->sampler[0].tsc[0] = 0x00000092; + blit->sampler[0].tsc[1] = 0x00000051; + + /* clamp to edge, min/max lod = 0, bilinear filtering */ + + blit->sampler[1].id = -1; + + blit->sampler[1].tsc[0] = 0x00000092; + blit->sampler[1].tsc[1] = 0x00000062; +} + +/* Since shaders cannot export stencil, we cannot copy stencil values when + * rendering to ZETA, so we attach the ZS surface to a colour render target. + */ +static INLINE enum pipe_format +nv50_blit_zeta_to_colour_format(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_Z16_UNORM: return PIPE_FORMAT_R16_UNORM; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + case PIPE_FORMAT_Z24X8_UNORM: return PIPE_FORMAT_R8G8B8A8_UNORM; + case PIPE_FORMAT_Z32_FLOAT: return PIPE_FORMAT_R32_FLOAT; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: return PIPE_FORMAT_R32G32_FLOAT; + default: + assert(0); + return PIPE_FORMAT_NONE; + } +} + +static void +nv50_blitctx_get_color_mask_and_fp(struct nv50_blitctx *blit, + enum pipe_format format, uint8_t mask) +{ + blit->color_mask = 0; + + switch (format) { + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + blit->fp_offset = 160; + if (mask & PIPE_MASK_Z) + blit->color_mask |= 0x0111; + if (mask & PIPE_MASK_S) + blit->color_mask |= 0x1000; + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + blit->fp_offset = 24; + if (mask & PIPE_MASK_Z) + blit->color_mask |= 0x1110; + if (mask & PIPE_MASK_S) + blit->color_mask |= 0x0001; + break; + default: + blit->fp_offset = 0; + if (mask & (PIPE_MASK_R | PIPE_MASK_Z)) blit->color_mask |= 0x0001; + if (mask & (PIPE_MASK_G | PIPE_MASK_S)) blit->color_mask |= 0x0010; + if (mask & PIPE_MASK_B) blit->color_mask |= 0x0100; + if (mask & PIPE_MASK_A) blit->color_mask |= 0x1000; + break; + } +} + +static void +nv50_blit_set_dst(struct nv50_context *nv50, + struct pipe_resource *res, unsigned level, unsigned layer) +{ + struct pipe_context *pipe = &nv50->base.pipe; + struct pipe_surface templ; + + if (util_format_is_depth_or_stencil(res->format)) + templ.format = nv50_blit_zeta_to_colour_format(res->format); + else + templ.format = res->format; + + templ.usage = PIPE_USAGE_STREAM; + templ.u.tex.level = level; + templ.u.tex.first_layer = templ.u.tex.last_layer = layer; + + nv50->framebuffer.cbufs[0] = nv50_miptree_surface_new(pipe, res, &templ); + nv50->framebuffer.nr_cbufs = 1; + nv50->framebuffer.zsbuf = NULL; + nv50->framebuffer.width = nv50->framebuffer.cbufs[0]->width; + nv50->framebuffer.height = nv50->framebuffer.cbufs[0]->height; +} + +static INLINE void +nv50_blit_fixup_tic_entry(struct pipe_sampler_view *view) +{ + struct nv50_tic_entry *ent = nv50_tic_entry(view); + + ent->tic[2] &= ~(1 << 31); /* scaled coordinates, ok with 3d textures ? */ + + /* magic: */ + + ent->tic[3] = 0x20000000; /* affects quality of near vertical edges in MS8 */ +} + +static void +nv50_blit_set_src(struct nv50_context *nv50, + struct pipe_resource *res, unsigned level, unsigned layer) +{ + struct pipe_context *pipe = &nv50->base.pipe; + struct pipe_sampler_view templ; + + templ.format = res->format; + templ.u.tex.first_layer = templ.u.tex.last_layer = layer; + templ.u.tex.first_level = templ.u.tex.last_level = level; + templ.swizzle_r = PIPE_SWIZZLE_RED; + templ.swizzle_g = PIPE_SWIZZLE_GREEN; + templ.swizzle_b = PIPE_SWIZZLE_BLUE; + templ.swizzle_a = PIPE_SWIZZLE_ALPHA; + + nv50->textures[2][0] = nv50_create_sampler_view(pipe, res, &templ); + + nv50_blit_fixup_tic_entry(nv50->textures[2][0]); + + nv50->num_textures[0] = nv50->num_textures[1] = 0; + nv50->num_textures[2] = 1; +} + +static void +nv50_blitctx_prepare_state(struct nv50_blitctx *blit) +{ + struct nouveau_channel *chan = blit->screen->base.channel; + + /* blend state */ + BEGIN_RING(chan, RING_3D(COLOR_MASK(0)), 1); + OUT_RING (chan, blit->color_mask); + BEGIN_RING(chan, RING_3D(BLEND_ENABLE(0)), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(LOGIC_OP_ENABLE), 1); + OUT_RING (chan, 0); + + /* rasterizer state */ +#ifndef NV50_SCISSORS_CLIPPING + BEGIN_RING(chan, RING_3D(SCISSOR_ENABLE(0)), 1); + OUT_RING (chan, 1); +#endif + BEGIN_RING(chan, RING_3D(VERTEX_TWO_SIDE_ENABLE), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(FRAG_COLOR_CLAMP_EN), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(MULTISAMPLE_ENABLE), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(MSAA_MASK(0)), 4); + OUT_RING (chan, 0xffff); + OUT_RING (chan, 0xffff); + OUT_RING (chan, 0xffff); + OUT_RING (chan, 0xffff); + BEGIN_RING(chan, RING_3D(POLYGON_MODE_FRONT), 3); + OUT_RING (chan, NV50_3D_POLYGON_MODE_FRONT_FILL); + OUT_RING (chan, NV50_3D_POLYGON_MODE_BACK_FILL); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(CULL_FACE_ENABLE), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(POLYGON_STIPPLE_ENABLE), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(POLYGON_OFFSET_FILL_ENABLE), 1); + OUT_RING (chan, 0); + + /* zsa state */ + BEGIN_RING(chan, RING_3D(DEPTH_TEST_ENABLE), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(STENCIL_ENABLE), 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, RING_3D(ALPHA_TEST_ENABLE), 1); + OUT_RING (chan, 0); +} + +static void +nv50_blitctx_pre_blit(struct nv50_blitctx *blit, struct nv50_context *nv50) +{ + int s; + + blit->saved.fb.width = nv50->framebuffer.width; + blit->saved.fb.height = nv50->framebuffer.height; + blit->saved.fb.nr_cbufs = nv50->framebuffer.nr_cbufs; + blit->saved.fb.cbufs[0] = nv50->framebuffer.cbufs[0]; + blit->saved.fb.zsbuf = nv50->framebuffer.zsbuf; + + blit->saved.vp = nv50->vertprog; + blit->saved.gp = nv50->gmtyprog; + blit->saved.fp = nv50->fragprog; + + nv50->vertprog = &blit->vp; + nv50->gmtyprog = NULL; + nv50->fragprog = &blit->fp; + + blit->saved.clip_nr = nv50->clip.nr; + + nv50->clip.nr = 0; + + for (s = 0; s < 3; ++s) { + blit->saved.num_textures[s] = nv50->num_textures[s]; + blit->saved.num_samplers[s] = nv50->num_samplers[s]; + } + blit->saved.texture = nv50->textures[2][0]; + blit->saved.sampler = nv50->samplers[2][0]; + + nv50->samplers[2][0] = &blit->sampler[blit->filter]; + + nv50->num_samplers[0] = nv50->num_samplers[1] = 0; + nv50->num_samplers[2] = 1; + + blit->saved.dirty = nv50->dirty; + + nv50->dirty = + NV50_NEW_FRAMEBUFFER | + NV50_NEW_VERTPROG | NV50_NEW_FRAGPROG | NV50_NEW_GMTYPROG | + NV50_NEW_TEXTURES | NV50_NEW_SAMPLERS; +} + +static void +nv50_blitctx_post_blit(struct nv50_context *nv50, struct nv50_blitctx *blit) +{ + int s; + + pipe_surface_reference(&nv50->framebuffer.cbufs[0], NULL); + + nv50->framebuffer.width = blit->saved.fb.width; + nv50->framebuffer.height = blit->saved.fb.height; + nv50->framebuffer.nr_cbufs = blit->saved.fb.nr_cbufs; + nv50->framebuffer.cbufs[0] = blit->saved.fb.cbufs[0]; + nv50->framebuffer.zsbuf = blit->saved.fb.zsbuf; + + nv50->vertprog = blit->saved.vp; + nv50->gmtyprog = blit->saved.gp; + nv50->fragprog = blit->saved.fp; + + nv50->clip.nr = blit->saved.clip_nr; + + pipe_sampler_view_reference(&nv50->textures[2][0], NULL); + + for (s = 0; s < 3; ++s) { + nv50->num_textures[s] = blit->saved.num_textures[s]; + nv50->num_samplers[s] = blit->saved.num_samplers[s]; + } + nv50->textures[2][0] = blit->saved.texture; + nv50->samplers[2][0] = blit->saved.sampler; + + nv50->dirty = blit->saved.dirty | + (NV50_NEW_FRAMEBUFFER | NV50_NEW_SCISSOR | NV50_NEW_SAMPLE_MASK | + NV50_NEW_RASTERIZER | NV50_NEW_ZSA | NV50_NEW_BLEND | + NV50_NEW_TEXTURES | NV50_NEW_SAMPLERS | + NV50_NEW_VERTPROG | NV50_NEW_GMTYPROG | NV50_NEW_FRAGPROG); +} + +static void +nv50_resource_resolve(struct pipe_context *pipe, + const struct pipe_resolve_info *info) +{ + struct nv50_context *nv50 = nv50_context(pipe); + struct nv50_screen *screen = nv50->screen; + struct nv50_blitctx *blit = screen->blitctx; + struct nouveau_channel *chan = screen->base.channel; + struct pipe_resource *src = info->src.res; + struct pipe_resource *dst = info->dst.res; + float x0, x1, y0, y1, z; + float x_range, y_range; + + nv50_blitctx_get_color_mask_and_fp(blit, dst->format, info->mask); + + blit->filter = util_format_is_depth_or_stencil(dst->format) ? 0 : 1; + + nv50_blitctx_pre_blit(blit, nv50); + + nv50_blit_set_dst(nv50, dst, info->dst.level, info->dst.layer); + nv50_blit_set_src(nv50, src, 0, info->src.layer); + + nv50_blitctx_prepare_state(blit); + + nv50_state_validate(nv50, 36); + + x_range = + (float)(info->src.x1 - info->src.x0) / + (float)(info->dst.x1 - info->dst.x0); + y_range = + (float)(info->src.y1 - info->src.y0) / + (float)(info->dst.y1 - info->dst.y0); + + x0 = (float)info->src.x0 - x_range * (float)info->dst.x0; + y0 = (float)info->src.y0 - y_range * (float)info->dst.y0; + + x1 = x0 + 16384.0f * x_range; + y1 = y0 + 16384.0f * y_range; + + x0 *= (float)(1 << nv50_miptree(src)->ms_x); + x1 *= (float)(1 << nv50_miptree(src)->ms_x); + y0 *= (float)(1 << nv50_miptree(src)->ms_y); + y1 *= (float)(1 << nv50_miptree(src)->ms_y); + + z = (float)info->src.layer; + + BEGIN_RING(chan, RING_3D(FP_START_ID), 1); + OUT_RING (chan, + blit->fp.code_base + blit->fp_offset); + + BEGIN_RING(chan, RING_3D(VIEWPORT_TRANSFORM_EN), 1); + OUT_RING (chan, 0); + + /* Draw a large triangle in screen coordinates covering the whole + * render target, with scissors defining the destination region. + * The vertex is supplied with non-normalized texture coordinates + * arranged in a way to yield the desired offset and scale. + */ + + BEGIN_RING(chan, RING_3D(SCISSOR_HORIZ(0)), 2); + OUT_RING (chan, (info->dst.x1 << 16) | info->dst.x0); + OUT_RING (chan, (info->dst.y1 << 16) | info->dst.y0); + + BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1); + OUT_RING (chan, NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES); + BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(1)), 3); + OUT_RINGf (chan, x0); + OUT_RINGf (chan, y0); + OUT_RINGf (chan, z); + BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(0)), 2); + OUT_RINGf (chan, 0.0f); + OUT_RINGf (chan, 0.0f); + BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(1)), 3); + OUT_RINGf (chan, x1); + OUT_RINGf (chan, y0); + OUT_RINGf (chan, z); + BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(0)), 2); + OUT_RINGf (chan, 16384 << nv50_miptree(dst)->ms_x); + OUT_RINGf (chan, 0.0f); + BEGIN_RING(chan, RING_3D(VTX_ATTR_3F_X(1)), 3); + OUT_RINGf (chan, x0); + OUT_RINGf (chan, y1); + OUT_RINGf (chan, z); + BEGIN_RING(chan, RING_3D(VTX_ATTR_2F_X(0)), 2); + OUT_RINGf (chan, 0.0f); + OUT_RINGf (chan, 16384 << nv50_miptree(dst)->ms_y); + BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1); + OUT_RING (chan, 0); + + /* re-enable normally constant state */ + + BEGIN_RING(chan, RING_3D(VIEWPORT_TRANSFORM_EN), 1); + OUT_RING (chan, 1); + + nv50_blitctx_post_blit(nv50, blit); +} + +boolean +nv50_blitctx_create(struct nv50_screen *screen) +{ + screen->blitctx = CALLOC_STRUCT(nv50_blitctx); + if (!screen->blitctx) { + NOUVEAU_ERR("failed to allocate blit context\n"); + return FALSE; + } + + screen->blitctx->screen = screen; + + nv50_blitctx_make_vp(screen->blitctx); + nv50_blitctx_make_fp(screen->blitctx); + + nv50_blitctx_make_sampler(screen->blitctx); + + screen->blitctx->color_mask = 0x1111; + + return TRUE; +} + void nv50_init_surface_functions(struct nv50_context *nv50) { struct pipe_context *pipe = &nv50->base.pipe; pipe->resource_copy_region = nv50_resource_copy_region; + pipe->resource_resolve = nv50_resource_resolve; pipe->clear_render_target = nv50_clear_render_target; pipe->clear_depth_stencil = nv50_clear_depth_stencil; } diff --git a/src/gallium/drivers/nv50/nv50_tex.c b/src/gallium/drivers/nv50/nv50_tex.c index 9192d2e2590..73db9ca4fd1 100644 --- a/src/gallium/drivers/nv50/nv50_tex.c +++ b/src/gallium/drivers/nv50/nv50_tex.c @@ -159,13 +159,13 @@ nv50_create_sampler_view(struct pipe_context *pipe, else tic[3] = 0x00300000; - tic[4] = (1 << 31) | mt->base.base.width0; + tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x); - tic[5] = mt->base.base.height0 & 0xffff; + tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff; tic[5] |= depth << 16; tic[5] |= mt->base.base.last_level << 28; - tic[6] = 0x03000000; + tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */ tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level; diff --git a/src/gallium/drivers/nv50/nv50_texture.xml.h b/src/gallium/drivers/nv50/nv50_texture.xml.h index e0cbbdf0d7b..08f6efdd7bf 100644 --- a/src/gallium/drivers/nv50/nv50_texture.xml.h +++ b/src/gallium/drivers/nv50/nv50_texture.xml.h @@ -1,5 +1,5 @@ -#ifndef NV50_TEXTURE_XML -#define NV50_TEXTURE_XML +#ifndef RNNDB_NV50_TEXTURE_XML +#define RNNDB_NV50_TEXTURE_XML /* Autogenerated file, DO NOT EDIT manually! @@ -8,8 +8,10 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng git clone git://0x04.net/rules-ng-ng The rules-ng-ng source files this header was generated from are: -- nv50_texture.xml ( 8377 bytes, from 2011-02-12 12:05:21) -- copyright.xml ( 6452 bytes, from 2010-11-25 23:28:20) +- rnndb/nv50_texture.xml ( 7947 bytes, from 2011-07-09 13:43:58) +- ./rnndb/copyright.xml ( 6452 bytes, from 2011-07-09 13:43:58) +- ./rnndb/nvchipsets.xml ( 3617 bytes, from 2011-07-09 13:43:58) +- ./rnndb/nv50_defs.xml ( 5468 bytes, from 2011-07-09 13:43:58) Copyright (C) 2006-2011 by the following authors: - Artur Huillet <[email protected]> (ahuillet) @@ -115,52 +117,52 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV50_TIC_0_FMT_32_32_32_32 0x00000001 #define NV50_TIC_0_FMT_16_16_16_16 0x00000003 #define NV50_TIC_0_FMT_32_32 0x00000004 -#define NV50_TIC_0_FMT_32_8 0x00000005 +#define NV50_TIC_0_FMT_32_8_X24 0x00000005 #define NV50_TIC_0_FMT_8_8_8_8 0x00000008 -#define NV50_TIC_0_FMT_2_10_10_10 0x00000009 +#define NV50_TIC_0_FMT_10_10_10_2 0x00000009 #define NV50_TIC_0_FMT_16_16 0x0000000c -#define NV50_TIC_0_FMT_8_24 0x0000000d -#define NV50_TIC_0_FMT_24_8 0x0000000e +#define NV50_TIC_0_FMT_24_8 0x0000000d +#define NV50_TIC_0_FMT_8_24 0x0000000e #define NV50_TIC_0_FMT_32 0x0000000f #define NV50_TIC_0_FMT_BPTC_FLOAT 0x00000010 #define NV50_TIC_0_FMT_BPTC_UFLOAT 0x00000011 #define NV50_TIC_0_FMT_4_4_4_4 0x00000012 -#define NV50_TIC_0_FMT_5_5_5_1 0x00000013 -#define NV50_TIC_0_FMT_1_5_5_5 0x00000014 +#define NV50_TIC_0_FMT_1_5_5_5 0x00000013 +#define NV50_TIC_0_FMT_5_5_5_1 0x00000014 #define NV50_TIC_0_FMT_5_6_5 0x00000015 -#define NV50_TIC_0_FMT_6_5_5 0x00000016 +#define NV50_TIC_0_FMT_5_5_6 0x00000016 #define NV50_TIC_0_FMT_BPTC 0x00000017 #define NV50_TIC_0_FMT_8_8 0x00000018 #define NV50_TIC_0_FMT_16 0x0000001b #define NV50_TIC_0_FMT_8 0x0000001d #define NV50_TIC_0_FMT_4_4 0x0000001e -#define NV50_TIC_0_FMT_BITMAP_8X8 0x0000001f -#define NV50_TIC_0_FMT_E5_9_9_9 0x00000020 -#define NV50_TIC_0_FMT_10_11_11 0x00000021 -#define NV50_TIC_0_FMT_C1_C2_C1_C0 0x00000022 -#define NV50_TIC_0_FMT_C2_C1_C0_C1 0x00000023 +#define NV50_TIC_0_FMT_BITMAP 0x0000001f +#define NV50_TIC_0_FMT_9_9_9_E5 0x00000020 +#define NV50_TIC_0_FMT_11_11_10 0x00000021 +#define NV50_TIC_0_FMT_U8_YA8_V8_YB8 0x00000022 +#define NV50_TIC_0_FMT_YA8_U8_YB8_V8 0x00000023 #define NV50_TIC_0_FMT_DXT1 0x00000024 #define NV50_TIC_0_FMT_DXT3 0x00000025 #define NV50_TIC_0_FMT_DXT5 0x00000026 #define NV50_TIC_0_FMT_RGTC1 0x00000027 #define NV50_TIC_0_FMT_RGTC2 0x00000028 -#define NV50_TIC_0_FMT_Z24S8 0x00000029 -#define NV50_TIC_0_FMT_S8Z24 0x0000002a -#define NV50_TIC_0_FMT_X8Z24 0x0000002b -#define NV50_TIC_0_FMT_C8Z24_MS4_CS4 0x0000002c -#define NV50_TIC_0_FMT_C8Z24_MS8_CS8 0x0000002d -#define NV50_TIC_0_FMT_C8Z24_MS4_CS12 0x0000002e +#define NV50_TIC_0_FMT_S8_Z24 0x00000029 +#define NV50_TIC_0_FMT_Z24_S8 0x0000002a +#define NV50_TIC_0_FMT_Z24_X8 0x0000002b +#define NV50_TIC_0_FMT_Z24_C8_MS4_CS4 0x0000002c +#define NV50_TIC_0_FMT_Z24_C8_MS8_CS8 0x0000002d +#define NV50_TIC_0_FMT_Z24_C8_MS4_CS12 0x0000002e #define NV50_TIC_0_FMT_Z32 0x0000002f -#define NV50_TIC_0_FMT_X24S8Z32 0x00000030 -#define NV50_TIC_0_FMT_X16C8S8X8Z24_MS4_CS4 0x00000031 -#define NV50_TIC_0_FMT_X16C8S8X8Z24_MS8_CS8 0x00000032 -#define NV50_TIC_0_FMT_X16C8X8Z32_MS4_CS4 0x00000033 -#define NV50_TIC_0_FMT_X16C8X8Z32_MS8_CS8 0x00000034 -#define NV50_TIC_0_FMT_X16C8S8Z32_MS4_CS4 0x00000035 -#define NV50_TIC_0_FMT_X16C8S8Z32_MS8_CS8 0x00000036 -#define NV50_TIC_0_FMT_X16C8S8X8Z24_MS4_CS12 0x00000037 -#define NV50_TIC_0_FMT_X16C8X8Z32_MS4_CS12 0x00000038 -#define NV50_TIC_0_FMT_X16C8S8Z32_MS4_CS12 0x00000039 +#define NV50_TIC_0_FMT_Z32_S8_X24 0x00000030 +#define NV50_TIC_0_FMT_Z24_X8_S8_C8_X16_MS4_CS4 0x00000031 +#define NV50_TIC_0_FMT_Z24_X8_S8_C8_X16_MS8_CS8 0x00000032 +#define NV50_TIC_0_FMT_Z32_X8_C8_X16_MS4_CS4 0x00000033 +#define NV50_TIC_0_FMT_Z32_X8_C8_X16_MS8_CS8 0x00000034 +#define NV50_TIC_0_FMT_Z32_S8_C8_X16_MS4_CS4 0x00000035 +#define NV50_TIC_0_FMT_Z32_S8_C8_X16_MS8_CS8 0x00000036 +#define NV50_TIC_0_FMT_Z24_X8_S8_C8_X16_MS4_CS12 0x00000037 +#define NV50_TIC_0_FMT_Z32_X8_C8_X16_MS4_CS12 0x00000038 +#define NV50_TIC_0_FMT_Z32_S8_C8_X16_MS4_CS12 0x00000039 #define NV50_TIC_0_FMT_Z16 0x0000003a #define NV50_TIC_1 0x00000004 @@ -215,6 +217,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV50_TIC_7_BASE_LEVEL__SHIFT 0 #define NV50_TIC_7_MAX_LEVEL__MASK 0x000000f0 #define NV50_TIC_7_MAX_LEVEL__SHIFT 4 +#define NV50_TIC_7_MS_MODE__MASK 0x0000f000 +#define NV50_TIC_7_MS_MODE__SHIFT 12 +#define NV50_TIC_7_MS_MODE_MS1 0x00000000 +#define NV50_TIC_7_MS_MODE_MS2 0x00001000 +#define NV50_TIC_7_MS_MODE_MS4 0x00002000 +#define NV50_TIC_7_MS_MODE_MS8 0x00003000 +#define NVA3_TIC_7_MS_MODE_MS8_ALT 0x00004000 +#define NVA3_TIC_7_MS_MODE_MS2_ALT 0x00005000 +#define NVC0_TIC_7_MS_MODE_UNK6 0x00006000 +#define NV50_TIC_7_MS_MODE_MS4_CS4 0x00008000 +#define NV50_TIC_7_MS_MODE_MS4_CS12 0x00009000 +#define NV50_TIC_7_MS_MODE_MS8_CS8 0x0000a000 +#define NVC0_TIC_7_MS_MODE_MS8_CS24 0x0000b000 #define NV50_TSC__SIZE 0x00000020 #define NV50_TSC_0 0x00000000 @@ -276,4 +291,4 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV50_TSC_7_BORDER_COLOR_ALPHA__SHIFT 0 -#endif /* NV50_TEXTURE_XML */ +#endif /* RNNDB_NV50_TEXTURE_XML */ diff --git a/src/gallium/drivers/nv50/nv50_transfer.c b/src/gallium/drivers/nv50/nv50_transfer.c index d9fb22aa673..0ff79eb908a 100644 --- a/src/gallium/drivers/nv50/nv50_transfer.c +++ b/src/gallium/drivers/nv50/nv50_transfer.c @@ -2,7 +2,6 @@ #include "util/u_format.h" #include "nv50_context.h" -#include "nv50_transfer.h" #include "nv50_defs.xml.h" @@ -13,7 +12,44 @@ struct nv50_transfer { uint32_t nblocksy; }; -static void +void +nv50_m2mf_rect_setup(struct nv50_m2mf_rect *rect, + struct pipe_resource *restrict res, unsigned l, + unsigned x, unsigned y, unsigned z) +{ + struct nv50_miptree *mt = nv50_miptree(res); + const unsigned w = u_minify(res->width0, l); + const unsigned h = u_minify(res->height0, l); + + rect->bo = mt->base.bo; + rect->domain = mt->base.domain; + rect->base = mt->level[l].offset; + rect->pitch = mt->level[l].pitch; + if (util_format_is_plain(res->format)) { + rect->width = w << mt->ms_x; + rect->height = h << mt->ms_y; + rect->x = x << mt->ms_x; + rect->y = y << mt->ms_y; + } else { + rect->width = util_format_get_nblocksx(res->format, w); + rect->height = util_format_get_nblocksy(res->format, h); + rect->x = util_format_get_nblocksx(res->format, x); + rect->y = util_format_get_nblocksy(res->format, y); + } + rect->tile_mode = mt->level[l].tile_mode; + rect->cpp = util_format_get_blocksize(res->format); + + if (mt->layout_3d) { + rect->z = z; + rect->depth = u_minify(res->depth0, l); + } else { + rect->base += z * mt->layer_stride; + rect->z = 0; + rect->depth = 1; + } +} + +void nv50_m2mf_transfer_rect(struct pipe_screen *pscreen, const struct nv50_m2mf_rect *dst, const struct nv50_m2mf_rect *src, @@ -202,26 +238,14 @@ nv50_miptree_transfer_new(struct pipe_context *pctx, struct nv50_context *nv50 = nv50_context(pctx); struct pipe_screen *pscreen = pctx->screen; struct nouveau_device *dev = nv50->screen->base.device; - struct nv50_miptree *mt = nv50_miptree(res); - struct nv50_miptree_level *lvl = &mt->level[level]; + const struct nv50_miptree *mt = nv50_miptree(res); struct nv50_transfer *tx; uint32_t size; - uint32_t w, h, d, z, layer; int ret; if (usage & PIPE_TRANSFER_MAP_DIRECTLY) return NULL; - if (mt->layout_3d) { - z = box->z; - d = u_minify(res->depth0, level); - layer = 0; - } else { - z = 0; - d = 1; - layer = box->z; - } - tx = CALLOC_STRUCT(nv50_transfer); if (!tx) return NULL; @@ -232,28 +256,18 @@ nv50_miptree_transfer_new(struct pipe_context *pctx, tx->base.usage = usage; tx->base.box = *box; - tx->nblocksx = util_format_get_nblocksx(res->format, box->width); - tx->nblocksy = util_format_get_nblocksy(res->format, box->height); + if (util_format_is_plain(res->format)) { + tx->nblocksx = box->width << mt->ms_x; + tx->nblocksy = box->height << mt->ms_x; + } else { + tx->nblocksx = util_format_get_nblocksx(res->format, box->width); + tx->nblocksy = util_format_get_nblocksy(res->format, box->height); + } tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format); tx->base.layer_stride = tx->nblocksy * tx->base.stride; - w = u_minify(res->width0, level); - h = u_minify(res->height0, level); - - tx->rect[0].cpp = tx->rect[1].cpp = util_format_get_blocksize(res->format); - - tx->rect[0].bo = mt->base.bo; - tx->rect[0].base = lvl->offset + layer * mt->layer_stride; - tx->rect[0].tile_mode = lvl->tile_mode; - tx->rect[0].x = util_format_get_nblocksx(res->format, box->x); - tx->rect[0].y = util_format_get_nblocksy(res->format, box->y); - tx->rect[0].z = z; - tx->rect[0].width = util_format_get_nblocksx(res->format, w); - tx->rect[0].height = util_format_get_nblocksy(res->format, h); - tx->rect[0].depth = d; - tx->rect[0].pitch = lvl->pitch; - tx->rect[0].domain = NOUVEAU_BO_VRAM; + nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z); size = tx->base.layer_stride; @@ -264,6 +278,7 @@ nv50_miptree_transfer_new(struct pipe_context *pctx, return NULL; } + tx->rect[1].cpp = tx->rect[0].cpp; tx->rect[1].width = tx->nblocksx; tx->rect[1].height = tx->nblocksy; tx->rect[1].depth = 1; @@ -272,6 +287,7 @@ nv50_miptree_transfer_new(struct pipe_context *pctx, if (usage & PIPE_TRANSFER_READ) { unsigned base = tx->rect[0].base; + unsigned z = tx->rect[0].z; unsigned i; for (i = 0; i < box->depth; ++i) { nv50_m2mf_transfer_rect(pscreen, &tx->rect[1], &tx->rect[0], diff --git a/src/gallium/drivers/nv50/nv50_transfer.h b/src/gallium/drivers/nv50/nv50_transfer.h index d3259ef4a5d..c58cb0008df 100644 --- a/src/gallium/drivers/nv50/nv50_transfer.h +++ b/src/gallium/drivers/nv50/nv50_transfer.h @@ -4,22 +4,6 @@ #include "pipe/p_state.h" -struct pipe_transfer * -nv50_miptree_transfer_new(struct pipe_context *pcontext, - struct pipe_resource *pt, - unsigned level, - unsigned usage, - const struct pipe_box *box); -void -nv50_miptree_transfer_del(struct pipe_context *pcontext, - struct pipe_transfer *ptx); -void * -nv50_miptree_transfer_map(struct pipe_context *pcontext, - struct pipe_transfer *ptx); -void -nv50_miptree_transfer_unmap(struct pipe_context *pcontext, - struct pipe_transfer *ptx); - struct nv50_m2mf_rect { struct nouveau_bo *bo; uint32_t base; @@ -35,4 +19,9 @@ struct nv50_m2mf_rect { uint16_t cpp; }; +void +nv50_m2mf_rect_setup(struct nv50_m2mf_rect *rect, + struct pipe_resource *restrict res, unsigned l, + unsigned x, unsigned y, unsigned z); + #endif diff --git a/src/gallium/drivers/nv50/nv50_vbo.c b/src/gallium/drivers/nv50/nv50_vbo.c index abdb9ce2f93..1c8347a793a 100644 --- a/src/gallium/drivers/nv50/nv50_vbo.c +++ b/src/gallium/drivers/nv50/nv50_vbo.c @@ -389,11 +389,11 @@ nv50_prim_gl(unsigned prim) static void nv50_draw_vbo_flush_notify(struct nouveau_channel *chan) { - struct nv50_context *nv50 = chan->user_private; + struct nv50_screen *screen = chan->user_private; - nouveau_fence_update(&nv50->screen->base, TRUE); + nouveau_fence_update(&screen->base, TRUE); - nv50_bufctx_emit_relocs(nv50); + nv50_bufctx_emit_relocs(screen->cur_ctx); } static void @@ -404,9 +404,6 @@ nv50_draw_arrays(struct nv50_context *nv50, struct nouveau_channel *chan = nv50->screen->base.channel; unsigned prim; - chan->flush_notify = nv50_draw_vbo_flush_notify; - chan->user_private = nv50; - prim = nv50_prim_gl(mode); while (instance_count--) { @@ -420,8 +417,6 @@ nv50_draw_arrays(struct nv50_context *nv50, prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; } - - chan->flush_notify = nv50_default_flush_notify; } static void @@ -523,9 +518,6 @@ nv50_draw_elements(struct nv50_context *nv50, boolean shorten, unsigned prim; const unsigned index_size = nv50->idxbuf.index_size; - chan->flush_notify = nv50_draw_vbo_flush_notify; - chan->user_private = nv50; - prim = nv50_prim_gl(mode); if (index_bias != nv50->state.index_bias) { @@ -631,8 +623,6 @@ nv50_draw_elements(struct nv50_context *nv50, boolean shorten, prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; } } - - chan->flush_notify = nv50_default_flush_notify; } void @@ -657,10 +647,13 @@ nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) if (nv50->vbo_user && !(nv50->dirty & (NV50_NEW_VERTEX | NV50_NEW_ARRAYS))) nv50_update_user_vbufs(nv50); - nv50_state_validate(nv50); + nv50_state_validate(nv50, 8); /* 8 as minimum, we use flush_notify here */ + + chan->flush_notify = nv50_draw_vbo_flush_notify; if (nv50->vbo_fifo) { nv50_push_vbo(nv50, info); + chan->flush_notify = nv50_default_flush_notify; return; } @@ -712,6 +705,7 @@ nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) info->mode, info->start, info->count, info->instance_count, info->index_bias); } + chan->flush_notify = nv50_default_flush_notify; nv50_release_user_vbufs(nv50); } diff --git a/src/gallium/drivers/nvc0/nvc0_3d.xml.h b/src/gallium/drivers/nvc0/nvc0_3d.xml.h index 2ca0bc23836..63016372827 100644 --- a/src/gallium/drivers/nvc0/nvc0_3d.xml.h +++ b/src/gallium/drivers/nvc0/nvc0_3d.xml.h @@ -146,6 +146,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NVC0_3D_TFB_ENABLE 0x00000744 +#define NVC0_3D_SAMPLE_SHADING 0x00000754 +#define NVC0_3D_SAMPLE_SHADING_MIN_SAMPLES__MASK 0x0000000f +#define NVC0_3D_SAMPLE_SHADING_MIN_SAMPLES__SHIFT 0 +#define NVC0_3D_SAMPLE_SHADING_ENABLE 0x00000010 + #define NVC0_3D_LOCAL_BASE 0x0000077c #define NVC0_3D_LOCAL_ADDRESS_HIGH 0x00000790 @@ -419,7 +424,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NVC0_3D_VERTEX_ATTRIB_FORMAT(i0) (0x00001160 + 0x4*(i0)) #define NVC0_3D_VERTEX_ATTRIB_FORMAT__ESIZE 0x00000004 #define NVC0_3D_VERTEX_ATTRIB_FORMAT__LEN 0x00000020 -#define NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__MASK 0x0000003f +#define NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__MASK 0x0000001f #define NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT 0 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST 0x00000040 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_OFFSET__MASK 0x001fff80 @@ -438,8 +443,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_8_8 0x03000000 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_16 0x03600000 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_8 0x03a00000 -#define NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_2_10_10_10 0x06000000 -#define NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE__MASK 0x78000000 +#define NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_10_10_10_2 0x06000000 +#define NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE__MASK 0x38000000 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE__SHIFT 27 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_SNORM 0x08000000 #define NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_UNORM 0x10000000 @@ -819,13 +824,17 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NVC0_3D_LAYER_USE_GP 0x00010000 #define NVC0_3D_MULTISAMPLE_MODE 0x000015d0 -#define NVC0_3D_MULTISAMPLE_MODE_1X 0x00000000 -#define NVC0_3D_MULTISAMPLE_MODE_2XMS 0x00000001 -#define NVC0_3D_MULTISAMPLE_MODE_4XMS 0x00000002 -#define NVC0_3D_MULTISAMPLE_MODE_8XMS 0x00000003 -#define NVC0_3D_MULTISAMPLE_MODE_4XMS_4XCS 0x00000008 -#define NVC0_3D_MULTISAMPLE_MODE_4XMS_12XCS 0x00000009 -#define NVC0_3D_MULTISAMPLE_MODE_8XMS_8XCS 0x0000000a +#define NVC0_3D_MULTISAMPLE_MODE_MS1 0x00000000 +#define NVC0_3D_MULTISAMPLE_MODE_MS2 0x00000001 +#define NVC0_3D_MULTISAMPLE_MODE_MS4 0x00000002 +#define NVC0_3D_MULTISAMPLE_MODE_MS8 0x00000003 +#define NVC0_3D_MULTISAMPLE_MODE_MS8_ALT 0x00000004 +#define NVC0_3D_MULTISAMPLE_MODE_MS2_ALT 0x00000005 +#define NVC0_3D_MULTISAMPLE_MODE_UNK6 0x00000006 +#define NVC0_3D_MULTISAMPLE_MODE_MS4_CS4 0x00000008 +#define NVC0_3D_MULTISAMPLE_MODE_MS4_CS12 0x00000009 +#define NVC0_3D_MULTISAMPLE_MODE_MS8_CS8 0x0000000a +#define NVC0_3D_MULTISAMPLE_MODE_MS8_CS24 0x0000000b #define NVC0_3D_VERTEX_BEGIN_D3D 0x000015d4 #define NVC0_3D_VERTEX_BEGIN_D3D_PRIMITIVE__MASK 0x0fffffff diff --git a/src/gallium/drivers/nvc0/nvc0_context.c b/src/gallium/drivers/nvc0/nvc0_context.c index 2f2a3da7c44..360afbb943e 100644 --- a/src/gallium/drivers/nvc0/nvc0_context.c +++ b/src/gallium/drivers/nvc0/nvc0_context.c @@ -89,10 +89,8 @@ nvc0_destroy(struct pipe_context *pipe) draw_destroy(nvc0->draw); - if (nvc0->screen->cur_ctx == nvc0) { - nvc0->screen->base.channel->user_private = NULL; + if (nvc0->screen->cur_ctx == nvc0) nvc0->screen->cur_ctx = NULL; - } FREE(nvc0); } @@ -100,13 +98,13 @@ nvc0_destroy(struct pipe_context *pipe) void nvc0_default_flush_notify(struct nouveau_channel *chan) { - struct nvc0_context *nvc0 = chan->user_private; + struct nvc0_screen *screen = chan->user_private; - if (!nvc0) + if (!screen) return; - nouveau_fence_update(&nvc0->screen->base, TRUE); - nouveau_fence_next(&nvc0->screen->base); + nouveau_fence_update(&screen->base, TRUE); + nouveau_fence_next(&screen->base); } struct pipe_context * @@ -141,7 +139,6 @@ nvc0_create(struct pipe_screen *pscreen, void *priv) if (!screen->cur_ctx) screen->cur_ctx = nvc0; - screen->base.channel->user_private = nvc0; screen->base.channel->flush_notify = nvc0_default_flush_notify; nvc0_init_query_functions(nvc0); @@ -153,6 +150,8 @@ nvc0_create(struct pipe_screen *pscreen, void *priv) assert(nvc0->draw); draw_set_rasterize_stage(nvc0->draw, nvc0_draw_render_stage(nvc0)); + nouveau_context_init_vdec(&nvc0->base); + return pipe; } @@ -169,6 +168,7 @@ nvc0_bufctx_add_resident(struct nvc0_context *nvc0, int ctx, if (!resource->bo) return; + nvc0->residents_size += sizeof(struct resident); /* We don't need to reference the resource here, it will be referenced * in the context/state, and bufctx will be reset when state changes. @@ -190,6 +190,7 @@ nvc0_bufctx_del_resident(struct nvc0_context *nvc0, int ctx, top = util_dynarray_pop_ptr(&nvc0->residents[ctx], struct resident); if (rsd != top) *rsd = *top; + nvc0->residents_size -= sizeof(struct resident); break; } } @@ -202,11 +203,15 @@ nvc0_bufctx_emit_relocs(struct nvc0_context *nvc0) struct util_dynarray *array; unsigned ctx, i, n; + n = nvc0->residents_size / sizeof(struct resident); + n += NVC0_SCREEN_RESIDENT_BO_COUNT; + + MARK_RING(nvc0->screen->base.channel, n, n); + for (ctx = 0; ctx < NVC0_BUFCTX_COUNT; ++ctx) { array = &nvc0->residents[ctx]; n = array->size / sizeof(struct resident); - MARK_RING(nvc0->screen->base.channel, n, n); for (i = 0; i < n; ++i) { rsd = util_dynarray_element(array, struct resident, i); diff --git a/src/gallium/drivers/nvc0/nvc0_context.h b/src/gallium/drivers/nvc0/nvc0_context.h index f97141dd46e..bf891649a57 100644 --- a/src/gallium/drivers/nvc0/nvc0_context.h +++ b/src/gallium/drivers/nvc0/nvc0_context.h @@ -19,6 +19,8 @@ #include "nvc0_program.h" #include "nvc0_resource.h" +#include "nv50/nv50_transfer.h" + #include "nouveau/nouveau_context.h" #include "nvc0_3ddefs.xml.h" @@ -62,6 +64,7 @@ struct nvc0_context { struct nvc0_screen *screen; struct util_dynarray residents[NVC0_BUFCTX_COUNT]; + unsigned residents_size; uint32_t dirty; @@ -136,20 +139,6 @@ nvc0_context(struct pipe_context *pipe) return (struct nvc0_context *)pipe; } -struct nvc0_surface { - struct pipe_surface base; - uint32_t offset; - uint32_t width; - uint16_t height; - uint16_t depth; -}; - -static INLINE struct nvc0_surface * -nvc0_surface(struct pipe_surface *ps) -{ - return (struct nvc0_surface *)ps; -} - /* nvc0_context.c */ struct pipe_context *nvc0_create(struct pipe_screen *, void *); @@ -163,6 +152,7 @@ void nvc0_bufctx_del_resident(struct nvc0_context *, int ctx, static INLINE void nvc0_bufctx_reset(struct nvc0_context *nvc0, int ctx) { + nvc0->residents_size -= nvc0->residents[ctx].size; util_dynarray_resize(&nvc0->residents[ctx], 0); } @@ -207,6 +197,11 @@ nvc0_create_sampler_view(struct pipe_context *, /* nvc0_transfer.c */ void +nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen, + const struct nv50_m2mf_rect *dst, + const struct nv50_m2mf_rect *src, + uint32_t nblocksx, uint32_t nblocksy); +void nvc0_m2mf_push_linear(struct nouveau_context *nv, struct nouveau_bo *dst, unsigned offset, unsigned domain, unsigned size, void *data); diff --git a/src/gallium/drivers/nvc0/nvc0_formats.c b/src/gallium/drivers/nvc0/nvc0_formats.c index 81077a7fa80..8dd4419436d 100644 --- a/src/gallium/drivers/nvc0/nvc0_formats.c +++ b/src/gallium/drivers/nvc0/nvc0_formats.c @@ -66,33 +66,33 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = { /* COMMON FORMATS */ - [PIPE_FORMAT_B8G8R8A8_UNORM] = { NV50_SURFACE_FORMAT_A8R8G8B8_UNORM, + [PIPE_FORMAT_B8G8R8A8_UNORM] = { NV50_SURFACE_FORMAT_BGRA8_UNORM, A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B8G8R8X8_UNORM] = { NV50_SURFACE_FORMAT_X8R8G8B8_UNORM, + [PIPE_FORMAT_B8G8R8X8_UNORM] = { NV50_SURFACE_FORMAT_BGRX8_UNORM, A_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B8G8R8A8_SRGB] = { NV50_SURFACE_FORMAT_A8R8G8B8_SRGB, + [PIPE_FORMAT_B8G8R8A8_SRGB] = { NV50_SURFACE_FORMAT_BGRA8_SRGB, A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_B8G8R8X8_SRGB] = { NV50_SURFACE_FORMAT_X8R8G8B8_SRGB, + [PIPE_FORMAT_B8G8R8X8_SRGB] = { NV50_SURFACE_FORMAT_BGRX8_SRGB, A_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 1), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_B5G6R5_UNORM] = { NV50_SURFACE_FORMAT_R5G6B5_UNORM, + [PIPE_FORMAT_B5G6R5_UNORM] = { NV50_SURFACE_FORMAT_B5G6R5_UNORM, B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 5_6_5, 1), SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B5G5R5A1_UNORM] = { NV50_SURFACE_FORMAT_A1R5G5B5_UNORM, - B_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 1_5_5_5, 1), + [PIPE_FORMAT_B5G5R5A1_UNORM] = { NV50_SURFACE_FORMAT_BGR5_A1_UNORM, + B_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 5_5_5_1, 1), SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, - [PIPE_FORMAT_B5G5R5X1_UNORM] = { 0, - B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 1_5_5_5, 1), - SAMPLER_VIEW | SCANOUT }, + [PIPE_FORMAT_B5G5R5X1_UNORM] = { NV50_SURFACE_FORMAT_BGR5_X1_UNORM, + B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 5_5_5_1, 1), + SAMPLER_VIEW | RENDER_TARGET | SCANOUT }, [PIPE_FORMAT_B4G4R4A4_UNORM] = { 0, B_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 4_4_4_4, 1), @@ -102,12 +102,12 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = B_(C2, C1, C0, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 4_4_4_4, 1), SAMPLER_VIEW }, - [PIPE_FORMAT_R10G10B10A2_UNORM] = { NV50_SURFACE_FORMAT_A2B10G10R10_UNORM, - A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 2_10_10_10, 0), + [PIPE_FORMAT_R10G10B10A2_UNORM] = { NV50_SURFACE_FORMAT_RGB10_A2_UNORM, + A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 10_10_10_2, 0), SAMPLER_VIEW | RENDER_TARGET | VERTEX_BUFFER | SCANOUT }, - [PIPE_FORMAT_B10G10R10A2_UNORM] = { NV50_SURFACE_FORMAT_A2R10G10B10_UNORM, - A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 2_10_10_10, 1), + [PIPE_FORMAT_B10G10R10A2_UNORM] = { NV50_SURFACE_FORMAT_BGR10_A2_UNORM, + A_(C2, C1, C0, C3, UNORM, UNORM, UNORM, UNORM, 10_10_10_2, 1), SAMPLER_VIEW | RENDER_TARGET | VERTEX_BUFFER }, /* DEPTH/STENCIL FORMATS */ @@ -116,25 +116,24 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, Z16, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_Z24_UNORM_S8_USCALED] = { NV50_ZETA_FORMAT_S8Z24_UNORM, - B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, S8Z24, 0), + [PIPE_FORMAT_Z24_UNORM_S8_USCALED] = { NV50_ZETA_FORMAT_Z24_S8_UNORM, + B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, Z24_S8, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_Z24X8_UNORM] = { NV50_ZETA_FORMAT_X8Z24_UNORM, - B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, X8Z24, 0), + [PIPE_FORMAT_Z24X8_UNORM] = { NV50_ZETA_FORMAT_Z24_X8_UNORM, + B_(C0, C0, C0, ONE_FLOAT, UNORM, UINT, UINT, UINT, Z24_X8, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_S8_USCALED_Z24_UNORM] = { NV50_ZETA_FORMAT_Z24S8_UNORM, - B_(C1, C1, C1, ONE_FLOAT, UINT, UNORM, UINT, UINT, Z24S8, 0), + [PIPE_FORMAT_S8_USCALED_Z24_UNORM] = { NV50_ZETA_FORMAT_S8_Z24_UNORM, + B_(C1, C1, C1, ONE_FLOAT, UINT, UNORM, UINT, UINT, S8_Z24, 0), SAMPLER_VIEW | DEPTH_STENCIL }, [PIPE_FORMAT_Z32_FLOAT] = { NV50_ZETA_FORMAT_Z32_FLOAT, B_(C0, C0, C0, ONE_FLOAT, FLOAT, UINT, UINT, UINT, Z32, 0), SAMPLER_VIEW | DEPTH_STENCIL }, - [PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED] = { - NV50_ZETA_FORMAT_Z32_FLOAT_X24S8_UNORM, - B_(C0, C0, C0, ONE_FLOAT, FLOAT, UINT, UINT, UINT, X24S8Z32, 0), + [PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED] = { NV50_ZETA_FORMAT_Z32_S8_X24_FLOAT, + B_(C0, C0, C0, ONE_FLOAT, FLOAT, UINT, UINT, UINT, Z32_S8_X24, 0), SAMPLER_VIEW | DEPTH_STENCIL }, /* LUMINANCE, ALPHA, INTENSITY */ @@ -283,15 +282,15 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* FLOAT 16 */ - [PIPE_FORMAT_R16G16B16A16_FLOAT] = { NV50_SURFACE_FORMAT_R16G16B16A16_FLOAT, + [PIPE_FORMAT_R16G16B16A16_FLOAT] = { NV50_SURFACE_FORMAT_RGBA16_FLOAT, A_(C0, C1, C2, C3, FLOAT, FLOAT, FLOAT, FLOAT, 16_16_16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R16G16B16_FLOAT] = { NV50_SURFACE_FORMAT_R16G16B16X16_FLOAT, + [PIPE_FORMAT_R16G16B16_FLOAT] = { NV50_SURFACE_FORMAT_RGBX16_FLOAT, A_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 16_16_16, 0), - VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R16G16_FLOAT] = { NV50_SURFACE_FORMAT_R16G16_FLOAT, + [PIPE_FORMAT_R16G16_FLOAT] = { NV50_SURFACE_FORMAT_RG16_FLOAT, A_(C0, C1, ZERO, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -301,15 +300,15 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* FLOAT 32 */ - [PIPE_FORMAT_R32G32B32A32_FLOAT] = { NV50_SURFACE_FORMAT_R32G32B32A32_FLOAT, + [PIPE_FORMAT_R32G32B32A32_FLOAT] = { NV50_SURFACE_FORMAT_RGBA32_FLOAT, A_(C0, C1, C2, C3, FLOAT, FLOAT, FLOAT, FLOAT, 32_32_32_32, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R32G32B32_FLOAT] = { NV50_SURFACE_FORMAT_R32G32B32X32_FLOAT, + [PIPE_FORMAT_R32G32B32_FLOAT] = { NV50_SURFACE_FORMAT_RGBX32_FLOAT, A_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 32_32_32, 0), - VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R32G32_FLOAT] = { NV50_SURFACE_FORMAT_R32G32_FLOAT, + [PIPE_FORMAT_R32G32_FLOAT] = { NV50_SURFACE_FORMAT_RG32_FLOAT, A_(C0, C1, ZERO, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 32_32, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -319,12 +318,12 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* ODD FORMATS */ - [PIPE_FORMAT_R11G11B10_FLOAT] = { NV50_SURFACE_FORMAT_B10G11R11_FLOAT, - B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 10_11_11, 0), + [PIPE_FORMAT_R11G11B10_FLOAT] = { NV50_SURFACE_FORMAT_R11G11B10_FLOAT, + B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 11_11_10, 0), SAMPLER_VIEW | RENDER_TARGET | VERTEX_BUFFER }, [PIPE_FORMAT_R9G9B9E5_FLOAT] = { 0, - B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, E5_9_9_9, 0), + B_(C0, C1, C2, ONE_FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, 9_9_9_E5, 0), SAMPLER_VIEW }, /* SNORM 32 */ @@ -335,7 +334,7 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = [PIPE_FORMAT_R32G32B32_SNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 32_32_32, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, [PIPE_FORMAT_R32G32_SNORM] = { 0, A_(C0, C1, ZERO, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 32_32, 0), @@ -353,7 +352,7 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = [PIPE_FORMAT_R32G32B32_UNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 32_32_32, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, [PIPE_FORMAT_R32G32_UNORM] = { 0, A_(C0, C1, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 32_32, 0), @@ -365,15 +364,15 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* SNORM 16 */ - [PIPE_FORMAT_R16G16B16A16_SNORM] = { NV50_SURFACE_FORMAT_R16G16B16A16_SNORM, + [PIPE_FORMAT_R16G16B16A16_SNORM] = { NV50_SURFACE_FORMAT_RGBA16_SNORM, A_(C0, C1, C2, C3, SNORM, SNORM, SNORM, SNORM, 16_16_16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R16G16B16_SNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 16_16_16, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R16G16_SNORM] = { NV50_SURFACE_FORMAT_R16G16_SNORM, + [PIPE_FORMAT_R16G16_SNORM] = { NV50_SURFACE_FORMAT_RG16_SNORM, A_(C0, C1, ZERO, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -383,15 +382,15 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* UNORM 16 */ - [PIPE_FORMAT_R16G16B16A16_UNORM] = { NV50_SURFACE_FORMAT_R16G16B16A16_UNORM, + [PIPE_FORMAT_R16G16B16A16_UNORM] = { NV50_SURFACE_FORMAT_RGBA16_UNORM, A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 16_16_16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R16G16B16_UNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 16_16_16, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R16G16_UNORM] = { NV50_SURFACE_FORMAT_R16G16_UNORM, + [PIPE_FORMAT_R16G16_UNORM] = { NV50_SURFACE_FORMAT_RG16_UNORM, A_(C0, C1, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 16_16, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -401,15 +400,15 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* SNORM 8 */ - [PIPE_FORMAT_R8G8B8A8_SNORM] = { NV50_SURFACE_FORMAT_A8B8G8R8_SNORM, + [PIPE_FORMAT_R8G8B8A8_SNORM] = { NV50_SURFACE_FORMAT_RGBA8_SNORM, A_(C0, C1, C2, C3, SNORM, SNORM, SNORM, SNORM, 8_8_8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, [PIPE_FORMAT_R8G8B8_SNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 8_8_8, 0), - VERTEX_BUFFER | SAMPLER_VIEW }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R8G8_SNORM] = { NV50_SURFACE_FORMAT_R8G8_SNORM, + [PIPE_FORMAT_R8G8_SNORM] = { NV50_SURFACE_FORMAT_RG8_SNORM, A_(C0, C1, ZERO, ONE_FLOAT, SNORM, SNORM, SNORM, SNORM, 8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -419,23 +418,23 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* UNORM 8 */ - [PIPE_FORMAT_R8G8B8A8_UNORM] = { NV50_SURFACE_FORMAT_A8B8G8R8_UNORM, + [PIPE_FORMAT_R8G8B8A8_UNORM] = { NV50_SURFACE_FORMAT_RGBA8_UNORM, A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R8G8B8A8_SRGB] = { NV50_SURFACE_FORMAT_A8B8G8R8_SRGB, - A_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), + [PIPE_FORMAT_R8G8B8A8_SRGB] = { NV50_SURFACE_FORMAT_RGBA8_SRGB, + B_(C0, C1, C2, C3, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R8G8B8_UNORM] = { NV50_SURFACE_FORMAT_X8B8G8R8_UNORM, - A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8, 0), - VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, + [PIPE_FORMAT_R8G8B8X8_UNORM] = { NV50_SURFACE_FORMAT_RGBX8_UNORM, + B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8_8, 0), + SAMPLER_VIEW | RENDER_TARGET }, - [PIPE_FORMAT_R8G8B8_SRGB] = { NV50_SURFACE_FORMAT_X8B8G8R8_SRGB, + [PIPE_FORMAT_R8G8B8_UNORM] = { 0, A_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8_8, 0), - SAMPLER_VIEW | RENDER_TARGET }, + VERTEX_BUFFER }, - [PIPE_FORMAT_R8G8_UNORM] = { NV50_SURFACE_FORMAT_R8G8_UNORM, + [PIPE_FORMAT_R8G8_UNORM] = { NV50_SURFACE_FORMAT_RG8_UNORM, A_(C0, C1, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, 8_8, 0), VERTEX_BUFFER | SAMPLER_VIEW | RENDER_TARGET }, @@ -554,11 +553,11 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = /* OTHER FORMATS */ [PIPE_FORMAT_R8G8_B8G8_UNORM] = { 0, - B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, C1_C2_C1_C0, 0), + B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, U8_YA8_V8_YB8, 0), SAMPLER_VIEW }, [PIPE_FORMAT_G8R8_G8B8_UNORM] = { 0, - B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, C2_C1_C0_C1, 0), + B_(C0, C1, C2, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, YA8_U8_YB8_V8, 0), SAMPLER_VIEW }, [PIPE_FORMAT_R8SG8SB8UX8U_NORM] = { 0, @@ -566,11 +565,11 @@ const struct nvc0_format nvc0_format_table[PIPE_FORMAT_COUNT] = SAMPLER_VIEW }, [PIPE_FORMAT_R5SG5SB6U_NORM] = { 0, - B_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, UNORM, UNORM, 6_5_5, 0), + B_(C0, C1, C2, ONE_FLOAT, SNORM, SNORM, UNORM, UNORM, 5_5_6, 0), SAMPLER_VIEW }, [PIPE_FORMAT_R1_UNORM] = { 0, - B_(C0, ZERO, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, BITMAP_8X8, 0), + B_(C0, ZERO, ZERO, ONE_FLOAT, UNORM, UNORM, UNORM, UNORM, BITMAP, 0), SAMPLER_VIEW }, [PIPE_FORMAT_A8B8G8R8_UNORM] = { 0, diff --git a/src/gallium/drivers/nvc0/nvc0_miptree.c b/src/gallium/drivers/nvc0/nvc0_miptree.c index bced3245524..a72ddf306cd 100644 --- a/src/gallium/drivers/nvc0/nvc0_miptree.c +++ b/src/gallium/drivers/nvc0/nvc0_miptree.c @@ -27,10 +27,9 @@ #include "nvc0_context.h" #include "nvc0_resource.h" -#include "nvc0_transfer.h" -static INLINE uint32_t -get_tile_dims(unsigned nx, unsigned ny, unsigned nz) +uint32_t +nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz) { uint32_t tile_mode = 0x000; @@ -57,66 +56,188 @@ get_tile_dims(unsigned nx, unsigned ny, unsigned nz) return tile_mode | 0x100; } -uint32_t -nvc0_miptree_zslice_offset(struct nvc0_miptree *mt, unsigned l, unsigned z) +static uint32_t +nvc0_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed) { - unsigned nblocksy; /* height of texture level aligned to tile height */ + const unsigned ms = util_logbase2(mt->base.base.nr_samples); - unsigned stride_2d; /* to next slice within a 3D tile */ - unsigned stride_3d; /* to slice in the next (in z direction !) 3D tile */ + uint32_t tile_flags; - unsigned tile_d_shift = NVC0_TILE_DIM_SHIFT(mt->level[l].tile_mode, 2); - unsigned tile_d = 1 << tile_d_shift; + compressed = FALSE; /* not yet supported */ - nblocksy = util_format_get_nblocksy(mt->base.base.format, - u_minify(mt->base.base.height0, l)); + if (mt->base.base.bind & PIPE_BIND_CURSOR) + return NOUVEAU_BO_TILE_SCANOUT; - nblocksy = align(nblocksy, NVC0_TILE_HEIGHT(mt->level[l].tile_mode)); + switch (mt->base.base.format) { + case PIPE_FORMAT_Z16_UNORM: + if (compressed) + tile_flags = 0x0200 + (ms << 8); + else + tile_flags = 0x0100; + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + if (compressed) + tile_flags = 0x5100 + (ms << 8); + else + tile_flags = 0x4600; + break; + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + if (compressed) + tile_flags = 0x1700 + (ms << 8); + else + tile_flags = 0x1100; + break; + case PIPE_FORMAT_Z32_FLOAT: + if (compressed) + tile_flags = 0x8600 + (ms << 8); + else + tile_flags = 0x7b00; + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + if (compressed) + tile_flags = 0xce00 + (ms << 8); + else + tile_flags = 0xc300; + break; + default: + switch (util_format_get_blocksizebits(mt->base.base.format)) { + case 128: + if (compressed) + tile_flags = 0xf400 + (ms << 9); + else + tile_flags = 0xfe00; + break; + case 64: + if (compressed) { + switch (ms) { + case 0: tile_flags = 0xe600; break; + case 1: tile_flags = 0xeb00; break; + case 2: tile_flags = 0xed00; break; + case 3: tile_flags = 0xf200; break; + default: + return 0; + } + } else { + tile_flags = 0xfe00; + } + break; + case 32: + if (compressed) { + switch (ms) { + case 0: tile_flags = 0xdb00; break; + case 1: tile_flags = 0xdd00; break; + case 2: tile_flags = 0xdf00; break; + case 3: tile_flags = 0xe400; break; + default: + return 0; + } + } else { + tile_flags = 0xfe00; + } + break; + case 16: + case 8: + tile_flags = 0xfe00; + break; + default: + return 0; + } + break; + } - stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode); + if (mt->base.base.bind & PIPE_BIND_SCANOUT) + tile_flags |= NOUVEAU_BO_TILE_SCANOUT; - stride_3d = (nblocksy * mt->level[l].pitch) << tile_d_shift; + return tile_flags; +} - return (z & (tile_d - 1)) * stride_2d + (z >> tile_d_shift) * stride_3d; +static INLINE boolean +nvc0_miptree_init_ms_mode(struct nv50_miptree *mt) +{ + switch (mt->base.base.nr_samples) { + case 8: + mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS8; + mt->ms_x = 2; + mt->ms_y = 1; + break; + case 4: + mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS4; + mt->ms_x = 1; + mt->ms_y = 1; + break; + case 2: + mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS2; + mt->ms_x = 1; + break; + case 1: + case 0: + mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1; + break; + default: + NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples); + return FALSE; + } + return TRUE; } +boolean +nv50_miptree_init_layout_linear(struct nv50_miptree *); + static void -nvc0_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) +nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt) { - struct nvc0_miptree *mt = nvc0_miptree(pt); + struct pipe_resource *pt = &mt->base.base; + unsigned w, h, d, l; + const unsigned blocksize = util_format_get_blocksize(pt->format); - nouveau_screen_bo_release(pscreen, mt->base.bo); + mt->layout_3d = pt->target == PIPE_TEXTURE_3D; - FREE(mt); -} + w = pt->width0 << mt->ms_x; + h = pt->height0 << mt->ms_y; -static boolean -nvc0_miptree_get_handle(struct pipe_screen *pscreen, - struct pipe_resource *pt, - struct winsys_handle *whandle) -{ - struct nvc0_miptree *mt = nvc0_miptree(pt); - unsigned stride; + /* For 3D textures, a mipmap is spanned by all the layers, for array + * textures and cube maps, each layer contains its own mipmaps. + */ + d = mt->layout_3d ? pt->depth0 : 1; - if (!mt || !mt->base.bo) - return FALSE; + for (l = 0; l <= pt->last_level; ++l) { + struct nv50_miptree_level *lvl = &mt->level[l]; + unsigned tsx, tsy, tsz; + unsigned nbx = util_format_get_nblocksx(pt->format, w); + unsigned nby = util_format_get_nblocksy(pt->format, h); + + lvl->offset = mt->total_size; + + lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d); + + tsx = NVC0_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */ + tsy = NVC0_TILE_SIZE_Y(lvl->tile_mode); + tsz = NVC0_TILE_SIZE_Z(lvl->tile_mode); - stride = util_format_get_stride(mt->base.base.format, - mt->base.base.width0); + lvl->pitch = align(nbx * blocksize, tsx); - return nouveau_screen_bo_get_handle(pscreen, - mt->base.bo, - stride, - whandle); + mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz); + + w = u_minify(w, 1); + h = u_minify(h, 1); + d = u_minify(d, 1); + } + + if (pt->array_size > 1) { + mt->layer_stride = align(mt->total_size, + NVC0_TILE_SIZE(mt->level[0].tile_mode)); + mt->total_size = mt->layer_stride * pt->array_size; + } } const struct u_resource_vtbl nvc0_miptree_vtbl = { - nvc0_miptree_get_handle, /* get_handle */ - nvc0_miptree_destroy, /* resource_destroy */ + nv50_miptree_get_handle, /* get_handle */ + nv50_miptree_destroy, /* resource_destroy */ nvc0_miptree_transfer_new, /* get_transfer */ nvc0_miptree_transfer_del, /* transfer_destroy */ - nvc0_miptree_transfer_map, /* transfer_map */ + nvc0_miptree_transfer_map, /* transfer_map */ u_default_transfer_flush_region, /* transfer_flush_region */ nvc0_miptree_transfer_unmap, /* transfer_unmap */ u_default_transfer_inline_write /* transfer_inline_write */ @@ -127,10 +248,9 @@ nvc0_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *templ) { struct nouveau_device *dev = nouveau_screen(pscreen)->device; - struct nvc0_miptree *mt = CALLOC_STRUCT(nvc0_miptree); + struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree); struct pipe_resource *pt = &mt->base.base; int ret; - unsigned w, h, d, l, alloc_size; uint32_t tile_flags; if (!mt) @@ -141,84 +261,23 @@ nvc0_miptree_create(struct pipe_screen *pscreen, pipe_reference_init(&pt->reference, 1); pt->screen = pscreen; - mt->layout_3d = pt->target == PIPE_TEXTURE_3D; - - w = pt->width0; - h = pt->height0; - d = mt->layout_3d ? pt->depth0 : 1; - - switch (pt->format) { - case PIPE_FORMAT_Z16_UNORM: - tile_flags = 0x0700; /* COMPRESSED */ - tile_flags = 0x0100; /* NORMAL */ - break; - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - tile_flags = 0x5300; /* MSAA 4, COMPRESSED */ - tile_flags = 0x4600; /* NORMAL */ - break; - case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - tile_flags = 0x1100; /* NORMAL */ - if (w * h >= 128 * 128 && 0) - tile_flags = 0x1700; /* COMPRESSED, requires magic */ - break; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - tile_flags = 0xf500; /* COMPRESSED */ - tile_flags = 0xf700; /* MSAA 2 */ - tile_flags = 0xf900; /* MSAA 4 */ - tile_flags = 0xfe00; /* NORMAL */ - break; - case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: - tile_flags = 0xce00; /* COMPRESSED */ - tile_flags = 0xcf00; /* MSAA 2, COMPRESSED */ - tile_flags = 0xd000; /* MSAA 4, COMPRESSED */ - tile_flags = 0xc300; /* NORMAL */ - break; - case PIPE_FORMAT_R16G16B16A16_UNORM: - tile_flags = 0xe900; /* COMPRESSED */ - tile_flags = 0xfe00; /* NORMAL */ - break; - default: - tile_flags = 0xe000; /* MSAA 4, COMPRESSED 32 BIT */ - tile_flags = 0xfe00; /* NORMAL 32 BIT */ - if (w * h >= 128 * 128 && 0) - tile_flags = 0xdb00; /* COMPRESSED 32 BIT, requires magic */ - break; - } - - /* For 3D textures, a mipmap is spanned by all the layers, for array - * textures and cube maps, each layer contains its own mipmaps. - */ - for (l = 0; l <= pt->last_level; ++l) { - struct nvc0_miptree_level *lvl = &mt->level[l]; - unsigned nbx = util_format_get_nblocksx(pt->format, w); - unsigned nby = util_format_get_nblocksy(pt->format, h); - unsigned blocksize = util_format_get_blocksize(pt->format); - - lvl->offset = mt->total_size; - lvl->tile_mode = get_tile_dims(nbx, nby, d); - lvl->pitch = align(nbx * blocksize, NVC0_TILE_PITCH(lvl->tile_mode)); + tile_flags = nvc0_mt_choose_storage_type(mt, TRUE); - mt->total_size += lvl->pitch * - align(nby, NVC0_TILE_HEIGHT(lvl->tile_mode)) * - align(d, NVC0_TILE_DEPTH(lvl->tile_mode)); - - w = u_minify(w, 1); - h = u_minify(h, 1); - d = u_minify(d, 1); + if (!nvc0_miptree_init_ms_mode(mt)) { + FREE(mt); + return NULL; } - if (pt->array_size > 1) { - mt->layer_stride = align(mt->total_size, - NVC0_TILE_SIZE(mt->level[0].tile_mode)); - mt->total_size = mt->layer_stride * pt->array_size; + if (tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK) { + nvc0_miptree_init_layout_tiled(mt); + } else + if (!nv50_miptree_init_layout_linear(mt)) { + FREE(mt); + return NULL; } - alloc_size = mt->total_size; - if (tile_flags == 0x1700) - alloc_size *= 3; /* HiZ, XXX: correct size */ - - ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 256, alloc_size, + ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 4096, + mt->total_size, mt->level[0].tile_mode, tile_flags, &mt->base.bo); if (ret) { @@ -230,44 +289,26 @@ nvc0_miptree_create(struct pipe_screen *pscreen, return pt; } -struct pipe_resource * -nvc0_miptree_from_handle(struct pipe_screen *pscreen, - const struct pipe_resource *templ, - struct winsys_handle *whandle) +/* Offset of zslice @z from start of level @l. */ +INLINE unsigned +nvc0_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z) { - struct nvc0_miptree *mt; - unsigned stride; - - /* only supports 2D, non-mipmapped textures for the moment */ - if ((templ->target != PIPE_TEXTURE_2D && - templ->target != PIPE_TEXTURE_RECT) || - templ->last_level != 0 || - templ->depth0 != 1 || - templ->array_size > 1) - return NULL; + const struct pipe_resource *pt = &mt->base.base; - mt = CALLOC_STRUCT(nvc0_miptree); - if (!mt) - return NULL; + unsigned tds = NVC0_TILE_SHIFT_Z(mt->level[l].tile_mode); + unsigned ths = NVC0_TILE_SHIFT_Y(mt->level[l].tile_mode); - mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride); - if (mt->base.bo == NULL) { - FREE(mt); - return NULL; - } + unsigned nby = util_format_get_nblocksy(pt->format, + u_minify(pt->height0, l)); - mt->base.base = *templ; - mt->base.vtbl = &nvc0_miptree_vtbl; - pipe_reference_init(&mt->base.base.reference, 1); - mt->base.base.screen = pscreen; - mt->level[0].pitch = stride; - mt->level[0].offset = 0; - mt->level[0].tile_mode = mt->base.bo->tile_mode; - - /* no need to adjust bo reference count */ - return &mt->base.base; -} + /* to next 2D tile slice within a 3D tile */ + unsigned stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode); + + /* to slice in the next (in z direction) 3D tile */ + unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds; + return (z & (1 << (tds - 1))) * stride_2d + (z >> tds) * stride_3d; +} /* Surface functions. */ @@ -277,43 +318,9 @@ nvc0_miptree_surface_new(struct pipe_context *pipe, struct pipe_resource *pt, const struct pipe_surface *templ) { - struct nvc0_miptree *mt = nvc0_miptree(pt); /* guaranteed */ - struct nvc0_surface *ns; - struct pipe_surface *ps; - struct nvc0_miptree_level *lvl = &mt->level[templ->u.tex.level]; - - ns = CALLOC_STRUCT(nvc0_surface); + struct nv50_surface *ns = nv50_surface_from_miptree(nv50_miptree(pt), templ); if (!ns) return NULL; - ps = &ns->base; - - pipe_reference_init(&ps->reference, 1); - pipe_resource_reference(&ps->texture, pt); - ps->context = pipe; - ps->format = templ->format; - ps->usage = templ->usage; - ps->u.tex.level = templ->u.tex.level; - ps->u.tex.first_layer = templ->u.tex.first_layer; - ps->u.tex.last_layer = templ->u.tex.last_layer; - - ns->width = u_minify(pt->width0, ps->u.tex.level); - ns->height = u_minify(pt->height0, ps->u.tex.level); - ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1; - ns->offset = lvl->offset; - - /* comment says there are going to be removed, but they're used by the st */ - ps->width = ns->width; - ps->height = ns->height; - - return ps; -} - -void -nvc0_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps) -{ - struct nvc0_surface *s = nvc0_surface(ps); - - pipe_resource_reference(&ps->texture, NULL); - - FREE(s); + ns->base.context = pipe; + return &ns->base; } diff --git a/src/gallium/drivers/nvc0/nvc0_resource.c b/src/gallium/drivers/nvc0/nvc0_resource.c index 44e66314e7e..a0289728ee9 100644 --- a/src/gallium/drivers/nvc0/nvc0_resource.c +++ b/src/gallium/drivers/nvc0/nvc0_resource.c @@ -21,10 +21,14 @@ nvc0_resource_from_handle(struct pipe_screen * screen, const struct pipe_resource *templ, struct winsys_handle *whandle) { - if (templ->target == PIPE_BUFFER) + if (templ->target == PIPE_BUFFER) { return NULL; - else - return nvc0_miptree_from_handle(screen, templ, whandle); + } else { + struct pipe_resource *res = nv50_miptree_from_handle(screen, + templ, whandle); + nv04_resource(res)->vtbl = &nvc0_miptree_vtbl; + return res; + } } void @@ -37,7 +41,7 @@ nvc0_init_resource_functions(struct pipe_context *pcontext) pcontext->transfer_destroy = u_transfer_destroy_vtbl; pcontext->transfer_inline_write = u_transfer_inline_write_vtbl; pcontext->create_surface = nvc0_miptree_surface_new; - pcontext->surface_destroy = nvc0_miptree_surface_del; + pcontext->surface_destroy = nv50_miptree_surface_del; } void diff --git a/src/gallium/drivers/nvc0/nvc0_resource.h b/src/gallium/drivers/nvc0/nvc0_resource.h index f1c445b5152..6d946c83834 100644 --- a/src/gallium/drivers/nvc0/nvc0_resource.h +++ b/src/gallium/drivers/nvc0/nvc0_resource.h @@ -2,53 +2,29 @@ #ifndef __NVC0_RESOURCE_H__ #define __NVC0_RESOURCE_H__ -#include "util/u_transfer.h" -#include "util/u_double_list.h" -#define NOUVEAU_NVC0 -#include "nouveau/nouveau_winsys.h" -#include "nouveau/nouveau_fence.h" -#include "nouveau/nouveau_buffer.h" -#undef NOUVEAU_NVC0 +#include "nv50/nv50_resource.h" -void -nvc0_init_resource_functions(struct pipe_context *pcontext); -void -nvc0_screen_init_resource_functions(struct pipe_screen *pscreen); +#define NVC0_TILE_SHIFT_X(m) ((((m) >> 0) & 0xf) + 6) +#define NVC0_TILE_SHIFT_Y(m) ((((m) >> 4) & 0xf) + 3) +#define NVC0_TILE_SHIFT_Z(m) ((((m) >> 8) & 0xf) + 0) -#define NVC0_TILE_DIM_SHIFT(m, d) (((m) >> (d * 4)) & 0xf) +#define NVC0_TILE_SIZE_X(m) (64 << (((m) >> 0) & 0xf)) +#define NVC0_TILE_SIZE_Y(m) ( 8 << (((m) >> 4) & 0xf)) +#define NVC0_TILE_SIZE_Z(m) ( 1 << (((m) >> 8) & 0xf)) -#define NVC0_TILE_PITCH(m) (64 << NVC0_TILE_DIM_SHIFT(m, 0)) -#define NVC0_TILE_HEIGHT(m) ( 8 << NVC0_TILE_DIM_SHIFT(m, 1)) -#define NVC0_TILE_DEPTH(m) ( 1 << NVC0_TILE_DIM_SHIFT(m, 2)) +/* it's ok to mask only in the end because max value is 3 * 5 */ -#define NVC0_TILE_SIZE_2D(m) (((64 * 8) << \ - NVC0_TILE_DIM_SHIFT(m, 0)) << \ - NVC0_TILE_DIM_SHIFT(m, 1)) +#define NVC0_TILE_SIZE_2D(m) ((64 * 8) << (((m) + ((m) >> 4)) & 0xf)) -#define NVC0_TILE_SIZE(m) (NVC0_TILE_SIZE_2D(m) << NVC0_TILE_DIM_SHIFT(m, 2)) +#define NVC0_TILE_SIZE(m) ((64 * 8) << (((m) + ((m) >> 4) + ((m) >> 8)) & 0xf)) -struct nvc0_miptree_level { - uint32_t offset; - uint32_t pitch; - uint32_t tile_mode; -}; -#define NVC0_MAX_TEXTURE_LEVELS 16 - -struct nvc0_miptree { - struct nv04_resource base; - struct nvc0_miptree_level level[NVC0_MAX_TEXTURE_LEVELS]; - uint32_t total_size; - uint32_t layer_stride; - boolean layout_3d; /* TRUE if layer count varies with mip level */ -}; +void +nvc0_init_resource_functions(struct pipe_context *pcontext); -static INLINE struct nvc0_miptree * -nvc0_miptree(struct pipe_resource *pt) -{ - return (struct nvc0_miptree *)pt; -} +void +nvc0_screen_init_resource_functions(struct pipe_screen *pscreen); /* Internal functions: */ @@ -56,20 +32,30 @@ struct pipe_resource * nvc0_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *tmp); -struct pipe_resource * -nvc0_miptree_from_handle(struct pipe_screen *pscreen, - const struct pipe_resource *template, - struct winsys_handle *whandle); +const struct u_resource_vtbl nvc0_miptree_vtbl; struct pipe_surface * nvc0_miptree_surface_new(struct pipe_context *, struct pipe_resource *, const struct pipe_surface *templ); -void -nvc0_miptree_surface_del(struct pipe_context *, struct pipe_surface *); +unsigned +nvc0_mt_zslice_offset(const struct nv50_miptree *, unsigned l, unsigned z); -uint32_t -nvc0_miptree_zslice_offset(struct nvc0_miptree *, unsigned l, unsigned z); +struct pipe_transfer * +nvc0_miptree_transfer_new(struct pipe_context *pcontext, + struct pipe_resource *pt, + unsigned level, + unsigned usage, + const struct pipe_box *box); +void +nvc0_miptree_transfer_del(struct pipe_context *pcontext, + struct pipe_transfer *ptx); +void * +nvc0_miptree_transfer_map(struct pipe_context *pcontext, + struct pipe_transfer *ptx); +void +nvc0_miptree_transfer_unmap(struct pipe_context *pcontext, + struct pipe_transfer *ptx); #endif diff --git a/src/gallium/drivers/nvc0/nvc0_screen.c b/src/gallium/drivers/nvc0/nvc0_screen.c index 52143981500..c79256a6ba2 100644 --- a/src/gallium/drivers/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nvc0/nvc0_screen.c @@ -24,6 +24,9 @@ #include "util/u_format_s3tc.h" #include "pipe/p_screen.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" + #include "nvc0_context.h" #include "nvc0_screen.h" @@ -37,7 +40,7 @@ nvc0_screen_is_format_supported(struct pipe_screen *pscreen, unsigned sample_count, unsigned bindings) { - if (sample_count > 1) + if (sample_count > 2 && sample_count != 4 && sample_count != 8) return FALSE; if (!util_format_is_supported(format, bindings)) @@ -200,8 +203,11 @@ nvc0_screen_destroy(struct pipe_screen *pscreen) { struct nvc0_screen *screen = nvc0_screen(pscreen); - nouveau_fence_wait(screen->base.fence.current); - nouveau_fence_ref(NULL, &screen->base.fence.current); + if (screen->base.fence.current) { + nouveau_fence_wait(screen->base.fence.current); + nouveau_fence_ref(NULL, &screen->base.fence.current); + } + screen->base.channel->user_private = NULL; nouveau_bo_ref(NULL, &screen->text); nouveau_bo_ref(NULL, &screen->tls); @@ -360,6 +366,7 @@ nvc0_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) return NULL; } chan = screen->base.channel; + chan->user_private = screen; pscreen->winsys = ws; pscreen->destroy = nvc0_screen_destroy; @@ -371,6 +378,8 @@ nvc0_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) nvc0_screen_init_resource_functions(pscreen); + nouveau_screen_init_vdec(&screen->base); + ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096, &screen->fence.bo); if (ret) @@ -435,7 +444,7 @@ nvc0_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) BEGIN_RING(chan, RING_3D(MULTISAMPLE_ENABLE), 1); OUT_RING (chan, 0); BEGIN_RING(chan, RING_3D(MULTISAMPLE_MODE), 1); - OUT_RING (chan, NVC0_3D_MULTISAMPLE_MODE_1X); + OUT_RING (chan, NVC0_3D_MULTISAMPLE_MODE_MS1); BEGIN_RING(chan, RING_3D(MULTISAMPLE_CTRL), 1); OUT_RING (chan, 0); BEGIN_RING(chan, RING_3D(LINE_WIDTH_SEPARATE), 1); diff --git a/src/gallium/drivers/nvc0/nvc0_screen.h b/src/gallium/drivers/nvc0/nvc0_screen.h index 94bf0cf3481..a3133b28876 100644 --- a/src/gallium/drivers/nvc0/nvc0_screen.h +++ b/src/gallium/drivers/nvc0/nvc0_screen.h @@ -4,6 +4,7 @@ #define NOUVEAU_NVC0 #include "nouveau/nouveau_screen.h" #include "nouveau/nouveau_mm.h" +#include "nouveau/nouveau_fence.h" #undef NOUVEAU_NVC0 #include "nvc0_winsys.h" #include "nvc0_stateobj.h" @@ -16,6 +17,8 @@ struct nvc0_context; #define NVC0_SCRATCH_SIZE (2 << 20) #define NVC0_SCRATCH_NR_BUFFERS 2 +#define NVC0_SCREEN_RESIDENT_BO_COUNT 5 + struct nvc0_screen { struct nouveau_screen base; struct nouveau_winsys *nvws; diff --git a/src/gallium/drivers/nvc0/nvc0_state.c b/src/gallium/drivers/nvc0/nvc0_state.c index b0b2065167e..9f9921cc09e 100644 --- a/src/gallium/drivers/nvc0/nvc0_state.c +++ b/src/gallium/drivers/nvc0/nvc0_state.c @@ -88,6 +88,7 @@ nvc0_blend_state_create(struct pipe_context *pipe, { struct nvc0_blend_stateobj *so = CALLOC_STRUCT(nvc0_blend_stateobj); int i; + uint32_t ms; so->pipe = *cso; @@ -144,6 +145,15 @@ nvc0_blend_state_create(struct pipe_context *pipe, SB_DATA(so, nvc0_colormask(cso->rt[i].colormask)); } + ms = 0; + if (cso->alpha_to_coverage) + ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; + if (cso->alpha_to_one) + ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; + + SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1); + SB_DATA (so, ms); + assert(so->size <= (sizeof(so->state) / sizeof(so->state[0]))); return so; } @@ -190,6 +200,8 @@ nvc0_rasterizer_state_create(struct pipe_context *pipe, SB_BEGIN_3D(so, FRAG_COLOR_CLAMP_EN, 1); SB_DATA (so, cso->clamp_fragment_color ? 0x11111111 : 0x00000000); + SB_IMMED_3D(so, MULTISAMPLE_ENABLE, cso->multisample); + SB_IMMED_3D(so, LINE_SMOOTH_ENABLE, cso->line_smooth); if (cso->line_smooth) SB_BEGIN_3D(so, LINE_WIDTH_SMOOTH, 1); diff --git a/src/gallium/drivers/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nvc0/nvc0_state_validate.c index 9b2a28150b1..968d7a7bd49 100644 --- a/src/gallium/drivers/nvc0/nvc0_state_validate.c +++ b/src/gallium/drivers/nvc0/nvc0_state_validate.c @@ -8,8 +8,8 @@ nvc0_validate_zcull(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; struct pipe_framebuffer_state *fb = &nvc0->framebuffer; - struct nvc0_surface *sf = nvc0_surface(fb->zsbuf); - struct nvc0_miptree *mt = nvc0_miptree(sf->base.texture); + struct nv50_surface *sf = nv50_surface(fb->zsbuf); + struct nv50_miptree *mt = nv50_miptree(sf->base.texture); struct nouveau_bo *bo = mt->base.bo; uint32_t size; uint32_t offset = align(mt->total_size, 1 << 17); @@ -59,6 +59,7 @@ nvc0_validate_fb(struct nvc0_context *nvc0) struct nouveau_channel *chan = nvc0->screen->base.channel; struct pipe_framebuffer_state *fb = &nvc0->framebuffer; unsigned i; + unsigned ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1; boolean serialize = FALSE; nvc0_bufctx_reset(nvc0, NVC0_BUFCTX_FRAME); @@ -72,8 +73,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0) MARK_RING(chan, 9 * fb->nr_cbufs, 2 * fb->nr_cbufs); for (i = 0; i < fb->nr_cbufs; ++i) { - struct nvc0_miptree *mt = nvc0_miptree(fb->cbufs[i]->texture); - struct nvc0_surface *sf = nvc0_surface(fb->cbufs[i]); + struct nv50_miptree *mt = nv50_miptree(fb->cbufs[i]->texture); + struct nv50_surface *sf = nv50_surface(fb->cbufs[i]); struct nouveau_bo *bo = mt->base.bo; uint32_t offset = sf->offset; @@ -89,6 +90,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0) OUT_RING (chan, mt->layer_stride >> 2); OUT_RING (chan, sf->base.u.tex.first_layer); + ms_mode = mt->ms_mode; + if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) serialize = TRUE; mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; @@ -100,8 +103,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0) } if (fb->zsbuf) { - struct nvc0_miptree *mt = nvc0_miptree(fb->zsbuf->texture); - struct nvc0_surface *sf = nvc0_surface(fb->zsbuf); + struct nv50_miptree *mt = nv50_miptree(fb->zsbuf->texture); + struct nv50_surface *sf = nv50_surface(fb->zsbuf); struct nouveau_bo *bo = mt->base.bo; int unk = mt->base.base.target == PIPE_TEXTURE_2D; uint32_t offset = sf->offset; @@ -123,6 +126,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0) BEGIN_RING(chan, RING_3D(ZETA_BASE_LAYER), 1); OUT_RING (chan, sf->base.u.tex.first_layer); + ms_mode = mt->ms_mode; + if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) serialize = TRUE; mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; @@ -135,6 +140,8 @@ nvc0_validate_fb(struct nvc0_context *nvc0) OUT_RING (chan, 0); } + IMMED_RING(chan, RING_3D(MULTISAMPLE_MODE), ms_mode); + if (serialize) { BEGIN_RING(chan, RING_3D(SERIALIZE), 1); OUT_RING (chan, 0); @@ -390,6 +397,28 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0) } static void +nvc0_validate_sample_mask(struct nvc0_context *nvc0) +{ + struct nouveau_channel *chan = nvc0->screen->base.channel; + + unsigned mask[4] = + { + nvc0->sample_mask & 0xffff, + nvc0->sample_mask & 0xffff, + nvc0->sample_mask & 0xffff, + nvc0->sample_mask & 0xffff + }; + + BEGIN_RING(chan, RING_3D(MSAA_MASK(0)), 4); + OUT_RING (chan, mask[0]); + OUT_RING (chan, mask[1]); + OUT_RING (chan, mask[2]); + OUT_RING (chan, mask[3]); + BEGIN_RING(chan, RING_3D(SAMPLE_SHADING), 1); + OUT_RING (chan, 0x01); +} + +static void nvc0_validate_derived_1(struct nvc0_context *nvc0) { struct nouveau_channel *chan = nvc0->screen->base.channel; @@ -428,8 +457,7 @@ nvc0_switch_pipe_context(struct nvc0_context *ctx_to) if (!ctx_to->zsa) ctx_to->dirty &= ~NVC0_NEW_ZSA; - ctx_to->screen->base.channel->user_private = ctx_to->screen->cur_ctx = - ctx_to; + ctx_to->screen->cur_ctx = ctx_to; } static struct state_validate { @@ -439,6 +467,7 @@ static struct state_validate { { nvc0_validate_fb, NVC0_NEW_FRAMEBUFFER }, { nvc0_validate_blend, NVC0_NEW_BLEND }, { nvc0_validate_zsa, NVC0_NEW_ZSA }, + { nvc0_validate_sample_mask, NVC0_NEW_SAMPLE_MASK }, { nvc0_validate_rasterizer, NVC0_NEW_RASTERIZER }, { nvc0_validate_blend_colour, NVC0_NEW_BLEND_COLOUR }, { nvc0_validate_stencil_ref, NVC0_NEW_STENCIL_REF }, diff --git a/src/gallium/drivers/nvc0/nvc0_stateobj.h b/src/gallium/drivers/nvc0/nvc0_stateobj.h index e0fe9df25d7..0686c52fd0c 100644 --- a/src/gallium/drivers/nvc0/nvc0_stateobj.h +++ b/src/gallium/drivers/nvc0/nvc0_stateobj.h @@ -19,13 +19,13 @@ struct nvc0_blend_stateobj { struct pipe_blend_state pipe; int size; - uint32_t state[70]; + uint32_t state[72]; }; struct nvc0_rasterizer_stateobj { struct pipe_rasterizer_state pipe; int size; - uint32_t state[38]; + uint32_t state[39]; }; struct nvc0_zsa_stateobj { diff --git a/src/gallium/drivers/nvc0/nvc0_surface.c b/src/gallium/drivers/nvc0/nvc0_surface.c index 6be3702bddc..67bba3c6cc3 100644 --- a/src/gallium/drivers/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nvc0/nvc0_surface.c @@ -31,7 +31,6 @@ #include "nvc0_context.h" #include "nvc0_resource.h" -#include "nvc0_transfer.h" #include "nv50/nv50_defs.xml.h" @@ -63,11 +62,11 @@ nvc0_2d_format(enum pipe_format format) case 2: return NV50_SURFACE_FORMAT_R16_UNORM; case 4: - return NV50_SURFACE_FORMAT_A8R8G8B8_UNORM; + return NV50_SURFACE_FORMAT_BGRA8_UNORM; case 8: - return NV50_SURFACE_FORMAT_R16G16B16A16_UNORM; + return NV50_SURFACE_FORMAT_RGBA16_UNORM; case 16: - return NV50_SURFACE_FORMAT_R32G32B32A32_FLOAT; + return NV50_SURFACE_FORMAT_RGBA32_FLOAT; default: return 0; } @@ -75,7 +74,7 @@ nvc0_2d_format(enum pipe_format format) static int nvc0_2d_texture_set(struct nouveau_channel *chan, int dst, - struct nvc0_miptree *mt, unsigned level, unsigned layer) + struct nv50_miptree *mt, unsigned level, unsigned layer) { struct nouveau_bo *bo = mt->base.bo; uint32_t width, height, depth; @@ -91,8 +90,8 @@ nvc0_2d_texture_set(struct nouveau_channel *chan, int dst, return 1; } - width = u_minify(mt->base.base.width0, level); - height = u_minify(mt->base.base.height0, level); + width = u_minify(mt->base.base.width0, level) << mt->ms_x; + height = u_minify(mt->base.base.height0, level) << mt->ms_y; depth = u_minify(mt->base.base.depth0, level); /* layer has to be < depth, and depth > tile depth / 2 */ @@ -103,7 +102,7 @@ nvc0_2d_texture_set(struct nouveau_channel *chan, int dst, depth = 1; } else if (!dst) { - offset += nvc0_miptree_zslice_offset(mt, level, layer); + offset += nvc0_mt_zslice_offset(mt, level, layer); layer = 0; } @@ -145,13 +144,19 @@ nvc0_2d_texture_set(struct nouveau_channel *chan, int dst, static int nvc0_2d_texture_do_copy(struct nouveau_channel *chan, - struct nvc0_miptree *dst, unsigned dst_level, + struct nv50_miptree *dst, unsigned dst_level, unsigned dx, unsigned dy, unsigned dz, - struct nvc0_miptree *src, unsigned src_level, + struct nv50_miptree *src, unsigned src_level, unsigned sx, unsigned sy, unsigned sz, unsigned w, unsigned h) { + static const uint32_t duvdxy[5] = + { + 0x40000000, 0x80000000, 0x00000001, 0x00000002, 0x00000004 + }; + int ret; + uint32_t ctrl = 0x00; ret = MARK_RING(chan, 2 * 16 + 32, 4); if (ret) @@ -165,66 +170,33 @@ nvc0_2d_texture_do_copy(struct nouveau_channel *chan, if (ret) return ret; - /* 0/1 = CENTER/CORNER, 10/00 = POINT/BILINEAR */ + /* NOTE: 2D engine doesn't work for MS8 */ + if (src->ms_x) + ctrl = 0x11; + + /* 0/1 = CENTER/CORNER, 00/10 = POINT/BILINEAR */ BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1); - OUT_RING (chan, 0); + OUT_RING (chan, ctrl); BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4); - OUT_RING (chan, dx); - OUT_RING (chan, dy); - OUT_RING (chan, w); - OUT_RING (chan, h); + OUT_RING (chan, dx << dst->ms_x); + OUT_RING (chan, dy << dst->ms_y); + OUT_RING (chan, w << dst->ms_x); + OUT_RING (chan, h << dst->ms_y); BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4); - OUT_RING (chan, 0); - OUT_RING (chan, 1); - OUT_RING (chan, 0); - OUT_RING (chan, 1); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0xf0000000); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0x0000000f); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0xf0000000); + OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0x0000000f); BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4); OUT_RING (chan, 0); - OUT_RING (chan, sx); + OUT_RING (chan, sx << src->ms_x); OUT_RING (chan, 0); - OUT_RING (chan, sy); + OUT_RING (chan, sy << src->ms_x); return 0; } static void -nvc0_setup_m2mf_rect(struct nvc0_m2mf_rect *rect, - struct pipe_resource *restrict res, unsigned l, - unsigned x, unsigned y, unsigned z) -{ - struct nvc0_miptree *mt = nvc0_miptree(res); - const unsigned w = u_minify(res->width0, l); - const unsigned h = u_minify(res->height0, l); - - rect->bo = mt->base.bo; - rect->domain = mt->base.domain; - rect->base = mt->level[l].offset; - rect->pitch = mt->level[l].pitch; - if (util_format_is_plain(res->format)) { - rect->width = w; - rect->height = h; - rect->x = x; - rect->y = y; - } else { - rect->width = util_format_get_nblocksx(res->format, w); - rect->height = util_format_get_nblocksy(res->format, h); - rect->x = util_format_get_nblocksx(res->format, x); - rect->y = util_format_get_nblocksy(res->format, y); - } - rect->tile_mode = mt->level[l].tile_mode; - rect->cpp = util_format_get_blocksize(res->format); - - if (mt->layout_3d) { - rect->z = z; - rect->depth = u_minify(res->depth0, l); - } else { - rect->base += z * mt->layer_stride; - rect->z = 0; - rect->depth = 1; - } -} - -static void nvc0_resource_copy_region(struct pipe_context *pipe, struct pipe_resource *dst, unsigned dst_level, unsigned dstx, unsigned dsty, unsigned dstz, @@ -244,28 +216,28 @@ nvc0_resource_copy_region(struct pipe_context *pipe, nv04_resource(dst)->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; - if (src->format == dst->format) { - struct nvc0_m2mf_rect drect, srect; + if (src->format == dst->format && src->nr_samples == dst->nr_samples) { + struct nv50_m2mf_rect drect, srect; unsigned i; unsigned nx = util_format_get_nblocksx(src->format, src_box->width); unsigned ny = util_format_get_nblocksy(src->format, src_box->height); - nvc0_setup_m2mf_rect(&drect, dst, dst_level, dstx, dsty, dstz); - nvc0_setup_m2mf_rect(&srect, src, src_level, + nv50_m2mf_rect_setup(&drect, dst, dst_level, dstx, dsty, dstz); + nv50_m2mf_rect_setup(&srect, src, src_level, src_box->x, src_box->y, src_box->z); for (i = 0; i < src_box->depth; ++i) { nvc0_m2mf_transfer_rect(&screen->base.base, &drect, &srect, nx, ny); - if (nvc0_miptree(dst)->layout_3d) + if (nv50_miptree(dst)->layout_3d) drect.z++; else - drect.base += nvc0_miptree(dst)->layer_stride; + drect.base += nv50_miptree(dst)->layer_stride; - if (nvc0_miptree(src)->layout_3d) + if (nv50_miptree(src)->layout_3d) srect.z++; else - srect.base += nvc0_miptree(src)->layer_stride; + srect.base += nv50_miptree(src)->layer_stride; } return; } @@ -275,9 +247,9 @@ nvc0_resource_copy_region(struct pipe_context *pipe, for (; dst_layer < dstz + src_box->depth; ++dst_layer, ++src_layer) { ret = nvc0_2d_texture_do_copy(screen->base.channel, - nvc0_miptree(dst), dst_level, + nv50_miptree(dst), dst_level, dstx, dsty, dst_layer, - nvc0_miptree(src), src_level, + nv50_miptree(src), src_level, src_box->x, src_box->y, src_layer, src_box->width, src_box->height); if (ret) @@ -295,8 +267,8 @@ nvc0_clear_render_target(struct pipe_context *pipe, struct nvc0_context *nv50 = nvc0_context(pipe); struct nvc0_screen *screen = nv50->screen; struct nouveau_channel *chan = screen->base.channel; - struct nvc0_miptree *mt = nvc0_miptree(dst->texture); - struct nvc0_surface *sf = nvc0_surface(dst); + struct nv50_miptree *mt = nv50_miptree(dst->texture); + struct nv50_surface *sf = nv50_surface(dst); struct nouveau_bo *bo = mt->base.bo; BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4); @@ -347,8 +319,8 @@ nvc0_clear_depth_stencil(struct pipe_context *pipe, struct nvc0_context *nv50 = nvc0_context(pipe); struct nvc0_screen *screen = nv50->screen; struct nouveau_channel *chan = screen->base.channel; - struct nvc0_miptree *mt = nvc0_miptree(dst->texture); - struct nvc0_surface *sf = nvc0_surface(dst); + struct nv50_miptree *mt = nv50_miptree(dst->texture); + struct nv50_surface *sf = nv50_surface(dst); struct nouveau_bo *bo = mt->base.bo; uint32_t mode = 0; int unk = mt->base.base.target == PIPE_TEXTURE_2D; diff --git a/src/gallium/drivers/nvc0/nvc0_tex.c b/src/gallium/drivers/nvc0/nvc0_tex.c index 24850b19986..0cbb4b33b59 100644 --- a/src/gallium/drivers/nvc0/nvc0_tex.c +++ b/src/gallium/drivers/nvc0/nvc0_tex.c @@ -60,7 +60,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe, uint32_t swz[4]; uint32_t depth; struct nv50_tic_entry *view; - struct nvc0_miptree *mt = nvc0_miptree(texture); + struct nv50_miptree *mt = nv50_miptree(texture); boolean tex_int; view = MALLOC_STRUCT(nv50_tic_entry); @@ -114,6 +114,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe, depth = MAX2(mt->base.base.array_size, mt->base.base.depth0); if (mt->base.base.target == PIPE_TEXTURE_1D_ARRAY || + /* mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS || */ mt->base.base.target == PIPE_TEXTURE_2D_ARRAY) { /* there doesn't seem to be a base layer field in TIC */ tic[1] = view->pipe.u.tex.first_layer * mt->layer_stride; @@ -124,6 +125,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe, case PIPE_TEXTURE_1D: tic[2] |= NV50_TIC_2_TARGET_1D; break; +/* case PIPE_TEXTURE_2D_MS: */ case PIPE_TEXTURE_2D: tic[2] |= NV50_TIC_2_TARGET_2D; break; @@ -143,6 +145,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe, case PIPE_TEXTURE_1D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_1D_ARRAY; break; +/* case PIPE_TEXTURE_2D_ARRAY_MS: */ case PIPE_TEXTURE_2D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY; break; @@ -159,16 +162,22 @@ nvc0_create_sampler_view(struct pipe_context *pipe, else tic[3] = 0x00300000; - tic[4] = (1 << 31) | mt->base.base.width0; + tic[4] = (1 << 31) | (mt->base.base.width0 << mt->ms_x); - tic[5] = mt->base.base.height0 & 0xffff; + tic[5] = (mt->base.base.height0 << mt->ms_y) & 0xffff; tic[5] |= depth << 16; tic[5] |= mt->base.base.last_level << 28; - tic[6] = 0x03000000; + tic[6] = (mt->ms_x > 1) ? 0x88000000 : 0x03000000; /* sampling points */ tic[7] = (view->pipe.u.tex.last_level << 4) | view->pipe.u.tex.first_level; + /* + if (mt->base.base.target == PIPE_TEXTURE_2D_MS || + mt->base.base.target == PIPE_TEXTURE_2D_ARRAY_MS) + tic[7] |= mt->ms_mode << 12; + */ + return &view->pipe; } @@ -189,7 +198,7 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s) OUT_RING (chan, (i << 1) | 0); continue; } - res = &nvc0_miptree(tic->pipe.texture)->base; + res = &nv50_miptree(tic->pipe.texture)->base; if (tic->id < 0) { uint32_t offset = tic->tic[1]; diff --git a/src/gallium/drivers/nvc0/nvc0_transfer.c b/src/gallium/drivers/nvc0/nvc0_transfer.c index 0509113e005..ecc9e213250 100644 --- a/src/gallium/drivers/nvc0/nvc0_transfer.c +++ b/src/gallium/drivers/nvc0/nvc0_transfer.c @@ -2,13 +2,12 @@ #include "util/u_format.h" #include "nvc0_context.h" -#include "nvc0_transfer.h" #include "nv50/nv50_defs.xml.h" struct nvc0_transfer { struct pipe_transfer base; - struct nvc0_m2mf_rect rect[2]; + struct nv50_m2mf_rect rect[2]; uint32_t nblocksx; uint16_t nblocksy; uint16_t nlayers; @@ -16,8 +15,8 @@ struct nvc0_transfer { void nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen, - const struct nvc0_m2mf_rect *dst, - const struct nvc0_m2mf_rect *src, + const struct nv50_m2mf_rect *dst, + const struct nv50_m2mf_rect *src, uint32_t nblocksx, uint32_t nblocksy) { struct nouveau_channel *chan = nouveau_screen(pscreen)->channel; @@ -174,9 +173,10 @@ nvc0_m2mf_copy_linear(struct nouveau_context *nv, } } +#if 0 static void nvc0_m2mf_push_rect(struct pipe_screen *pscreen, - const struct nvc0_m2mf_rect *dst, + const struct nv50_m2mf_rect *dst, const void *data, unsigned nblocksx, unsigned nblocksy) { @@ -228,6 +228,7 @@ nvc0_m2mf_push_rect(struct pipe_screen *pscreen, nblocksy -= line_count; } } +#endif struct pipe_transfer * nvc0_miptree_transfer_new(struct pipe_context *pctx, @@ -239,11 +240,9 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx, struct nvc0_context *nvc0 = nvc0_context(pctx); struct pipe_screen *pscreen = pctx->screen; struct nouveau_device *dev = nvc0->screen->base.device; - struct nvc0_miptree *mt = nvc0_miptree(res); - struct nvc0_miptree_level *lvl = &mt->level[level]; + struct nv50_miptree *mt = nv50_miptree(res); struct nvc0_transfer *tx; uint32_t size; - uint32_t w, h, d, z, layer; int ret; if (usage & PIPE_TRANSFER_MAP_DIRECTLY) @@ -253,45 +252,25 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx, if (!tx) return NULL; - if (mt->layout_3d) { - z = box->z; - d = u_minify(res->depth0, level); - layer = 0; - } else { - z = 0; - d = 1; - layer = box->z; - } - tx->nlayers = box->depth; - pipe_resource_reference(&tx->base.resource, res); tx->base.level = level; tx->base.usage = usage; tx->base.box = *box; - tx->nblocksx = util_format_get_nblocksx(res->format, box->width); - tx->nblocksy = util_format_get_nblocksy(res->format, box->height); + if (util_format_is_plain(res->format)) { + tx->nblocksx = box->width << mt->ms_x; + tx->nblocksy = box->height << mt->ms_y; + } else { + tx->nblocksx = util_format_get_nblocksx(res->format, box->width); + tx->nblocksy = util_format_get_nblocksy(res->format, box->height); + } + tx->nlayers = box->depth; tx->base.stride = tx->nblocksx * util_format_get_blocksize(res->format); tx->base.layer_stride = tx->nblocksy * tx->base.stride; - w = u_minify(res->width0, level); - h = u_minify(res->height0, level); - - tx->rect[0].cpp = tx->rect[1].cpp = util_format_get_blocksize(res->format); - - tx->rect[0].bo = mt->base.bo; - tx->rect[0].base = lvl->offset + layer * mt->layer_stride; - tx->rect[0].tile_mode = lvl->tile_mode; - tx->rect[0].x = util_format_get_nblocksx(res->format, box->x); - tx->rect[0].y = util_format_get_nblocksy(res->format, box->y); - tx->rect[0].z = z; - tx->rect[0].width = util_format_get_nblocksx(res->format, w); - tx->rect[0].height = util_format_get_nblocksy(res->format, h); - tx->rect[0].depth = d; - tx->rect[0].pitch = lvl->pitch; - tx->rect[0].domain = NOUVEAU_BO_VRAM; + nv50_m2mf_rect_setup(&tx->rect[0], res, level, box->x, box->y, box->z); size = tx->base.layer_stride; @@ -302,6 +281,7 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx, return NULL; } + tx->rect[1].cpp = tx->rect[0].cpp; tx->rect[1].width = tx->nblocksx; tx->rect[1].height = tx->nblocksy; tx->rect[1].depth = 1; @@ -310,6 +290,7 @@ nvc0_miptree_transfer_new(struct pipe_context *pctx, if (usage & PIPE_TRANSFER_READ) { unsigned base = tx->rect[0].base; + unsigned z = tx->rect[0].z; unsigned i; for (i = 0; i < tx->nlayers; ++i) { nvc0_m2mf_transfer_rect(pscreen, &tx->rect[1], &tx->rect[0], @@ -334,7 +315,7 @@ nvc0_miptree_transfer_del(struct pipe_context *pctx, { struct pipe_screen *pscreen = pctx->screen; struct nvc0_transfer *tx = (struct nvc0_transfer *)transfer; - struct nvc0_miptree *mt = nvc0_miptree(tx->base.resource); + struct nv50_miptree *mt = nv50_miptree(tx->base.resource); unsigned i; if (tx->base.usage & PIPE_TRANSFER_WRITE) { diff --git a/src/gallium/drivers/nvc0/nvc0_transfer.h b/src/gallium/drivers/nvc0/nvc0_transfer.h deleted file mode 100644 index 803ee3463ec..00000000000 --- a/src/gallium/drivers/nvc0/nvc0_transfer.h +++ /dev/null @@ -1,44 +0,0 @@ - -#ifndef __NVC0_TRANSFER_H__ -#define __NVC0_TRANSFER_H__ - -#include "pipe/p_state.h" - -struct pipe_transfer * -nvc0_miptree_transfer_new(struct pipe_context *pcontext, - struct pipe_resource *pt, - unsigned level, - unsigned usage, - const struct pipe_box *box); -void -nvc0_miptree_transfer_del(struct pipe_context *pcontext, - struct pipe_transfer *ptx); -void * -nvc0_miptree_transfer_map(struct pipe_context *pcontext, - struct pipe_transfer *ptx); -void -nvc0_miptree_transfer_unmap(struct pipe_context *pcontext, - struct pipe_transfer *ptx); - -struct nvc0_m2mf_rect { - struct nouveau_bo *bo; - uint32_t base; - unsigned domain; - uint32_t pitch; - uint32_t width; - uint32_t x; - uint32_t height; - uint32_t y; - uint16_t depth; - uint16_t z; - uint16_t tile_mode; - uint16_t cpp; -}; - -void -nvc0_m2mf_transfer_rect(struct pipe_screen *pscreen, - const struct nvc0_m2mf_rect *dst, - const struct nvc0_m2mf_rect *src, - uint32_t nblocksx, uint32_t nblocksy); - -#endif diff --git a/src/gallium/drivers/nvc0/nvc0_vbo.c b/src/gallium/drivers/nvc0/nvc0_vbo.c index 6bbcf2447ec..8a5bf8dc582 100644 --- a/src/gallium/drivers/nvc0/nvc0_vbo.c +++ b/src/gallium/drivers/nvc0/nvc0_vbo.c @@ -367,11 +367,11 @@ nvc0_prim_gl(unsigned prim) static void nvc0_draw_vbo_flush_notify(struct nouveau_channel *chan) { - struct nvc0_context *nvc0 = chan->user_private; + struct nvc0_screen *screen = chan->user_private; - nouveau_fence_update(&nvc0->screen->base, TRUE); + nouveau_fence_update(&screen->base, TRUE); - nvc0_bufctx_emit_relocs(nvc0); + nvc0_bufctx_emit_relocs(screen->cur_ctx); } static void @@ -382,9 +382,6 @@ nvc0_draw_arrays(struct nvc0_context *nvc0, struct nouveau_channel *chan = nvc0->screen->base.channel; unsigned prim; - chan->flush_notify = nvc0_draw_vbo_flush_notify; - chan->user_private = nvc0; - prim = nvc0_prim_gl(mode); while (instance_count--) { @@ -397,8 +394,6 @@ nvc0_draw_arrays(struct nvc0_context *nvc0, prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; } - - chan->flush_notify = nvc0_default_flush_notify; } static void @@ -500,9 +495,6 @@ nvc0_draw_elements(struct nvc0_context *nvc0, boolean shorten, unsigned prim; const unsigned index_size = nvc0->idxbuf.index_size; - chan->flush_notify = nvc0_draw_vbo_flush_notify; - chan->user_private = nvc0; - prim = nvc0_prim_gl(mode); if (index_bias != nvc0->state.index_bias) { @@ -568,8 +560,6 @@ nvc0_draw_elements(struct nvc0_context *nvc0, boolean shorten, prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT; } } - - chan->flush_notify = nvc0_default_flush_notify; } void @@ -596,8 +586,11 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) nvc0_state_validate(nvc0); + chan->flush_notify = nvc0_draw_vbo_flush_notify; + if (nvc0->vbo_fifo) { nvc0_push_vbo(nvc0, info); + chan->flush_notify = nvc0_default_flush_notify; return; } @@ -648,6 +641,7 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) info->mode, info->start, info->count, info->instance_count, info->index_bias); } + chan->flush_notify = nvc0_default_flush_notify; nvc0_release_user_vbufs(nvc0); } diff --git a/src/gallium/drivers/nvfx/nvfx_context.c b/src/gallium/drivers/nvfx/nvfx_context.c index 2b1510264a1..e2cdcf636f9 100644 --- a/src/gallium/drivers/nvfx/nvfx_context.c +++ b/src/gallium/drivers/nvfx/nvfx_context.c @@ -1,6 +1,8 @@ #include "draw/draw_context.h" #include "pipe/p_defines.h" #include "util/u_framebuffer.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "nvfx_context.h" #include "nvfx_screen.h" @@ -24,9 +26,21 @@ nvfx_flush(struct pipe_context *pipe, OUT_RING(chan, 1); }*/ - FIRE_RING(chan); - if (fence) + if (fence) { + /* horrific hack to make glFinish() work in the absence of + * having proper fences in nvfx. a pending rewrite will + * fix this properly, but may be a while off. + */ + MARK_RING(chan, 1, 1); + OUT_RELOC(chan, screen->fence, 0, NOUVEAU_BO_WR | + NOUVEAU_BO_DUMMY, 0, 0); + FIRE_RING(chan); + nouveau_bo_map(screen->fence, NOUVEAU_BO_RDWR); + nouveau_bo_unmap(screen->fence); *fence = NULL; + } else { + FIRE_RING(chan); + } } static void @@ -76,6 +90,9 @@ nvfx_create(struct pipe_screen *pscreen, void *priv) nvfx->pipe.clear = nvfx_clear; nvfx->pipe.flush = nvfx_flush; + nvfx->pipe.create_video_decoder = vl_create_decoder; + nvfx->pipe.create_video_buffer = vl_video_buffer_create; + nvfx->is_nv4x = screen->is_nv4x; nvfx->use_nv4x = screen->use_nv4x; /* TODO: it seems that nv30 might have fixed function clipping usable with vertex programs diff --git a/src/gallium/drivers/nvfx/nvfx_screen.c b/src/gallium/drivers/nvfx/nvfx_screen.c index d880b12fcaa..0e8f96772c6 100644 --- a/src/gallium/drivers/nvfx/nvfx_screen.c +++ b/src/gallium/drivers/nvfx/nvfx_screen.c @@ -3,6 +3,8 @@ #include "util/u_format.h" #include "util/u_format_s3tc.h" #include "util/u_simple_screen.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "nouveau/nouveau_screen.h" #include "nouveau/nv_object.xml.h" @@ -33,6 +35,9 @@ nvfx_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) return 1; case PIPE_CAP_GLSL: return 1; + case PIPE_CAP_SM3: + /* TODO: >= nv4x support Shader Model 3.0 */ + return 0; case PIPE_CAP_ANISOTROPIC_FILTER: return 1; case PIPE_CAP_POINT_SPRITE: @@ -208,6 +213,24 @@ nvfx_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_cap param) } } +static int +nvfx_screen_get_video_param(struct pipe_screen *screen, + enum pipe_video_profile profile, + enum pipe_video_cap param) +{ + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vl_profile_supported(screen, profile); + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 0; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vl_video_buffer_max_size(screen); + default: + return 0; + } +} + static boolean nvfx_screen_is_format_supported(struct pipe_screen *pscreen, enum pipe_format format, @@ -306,6 +329,7 @@ nvfx_screen_destroy(struct pipe_screen *pscreen) nouveau_notifier_free(&screen->sync); nouveau_grobj_free(&screen->eng3d); nvfx_screen_surface_takedown(pscreen); + nouveau_bo_ref(NULL, &screen->fence); nouveau_screen_fini(&screen->base); @@ -467,9 +491,17 @@ nvfx_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) pscreen->get_param = nvfx_screen_get_param; pscreen->get_shader_param = nvfx_screen_get_shader_param; pscreen->get_paramf = nvfx_screen_get_paramf; + pscreen->get_video_param = nvfx_screen_get_video_param; pscreen->is_format_supported = nvfx_screen_is_format_supported; + pscreen->is_video_format_supported = vl_video_buffer_is_format_supported; pscreen->context_create = nvfx_create; + ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 4096, &screen->fence); + if (ret) { + nvfx_screen_destroy(pscreen); + return NULL; + } + switch (dev->chipset & 0xf0) { case 0x30: if (NV30_3D_CHIPSET_3X_MASK & (1 << (dev->chipset & 0x0f))) diff --git a/src/gallium/drivers/nvfx/nvfx_screen.h b/src/gallium/drivers/nvfx/nvfx_screen.h index b1f07187c78..02e7c5d1cad 100644 --- a/src/gallium/drivers/nvfx/nvfx_screen.h +++ b/src/gallium/drivers/nvfx/nvfx_screen.h @@ -11,6 +11,7 @@ struct nvfx_screen { struct nouveau_screen base; struct nouveau_winsys *nvws; + struct nouveau_bo *fence; struct nvfx_context *cur_ctx; diff --git a/src/gallium/drivers/nvfx/nvfx_state.h b/src/gallium/drivers/nvfx/nvfx_state.h index 8fafca1950c..15e1cbb1986 100644 --- a/src/gallium/drivers/nvfx/nvfx_state.h +++ b/src/gallium/drivers/nvfx/nvfx_state.h @@ -2,6 +2,7 @@ #define __NVFX_STATE_H__ #include "pipe/p_state.h" +#include "pipe/p_video_state.h" #include "tgsi/tgsi_scan.h" #include "nouveau/nouveau_statebuf.h" #include "util/u_dynarray.h" diff --git a/src/gallium/drivers/r300/Makefile b/src/gallium/drivers/r300/Makefile index 4088216adcb..4f021276a8f 100644 --- a/src/gallium/drivers/r300/Makefile +++ b/src/gallium/drivers/r300/Makefile @@ -26,19 +26,51 @@ C_SOURCES = \ r300_texture.c \ r300_texture_desc.c \ r300_tgsi_to_rc.c \ - r300_transfer.c + r300_transfer.c \ + \ + compiler/radeon_code.c \ + compiler/radeon_compiler.c \ + compiler/radeon_compiler_util.c \ + compiler/radeon_emulate_branches.c \ + compiler/radeon_emulate_loops.c \ + compiler/radeon_program.c \ + compiler/radeon_program_print.c \ + compiler/radeon_opcodes.c \ + compiler/radeon_program_alu.c \ + compiler/radeon_program_pair.c \ + compiler/radeon_program_tex.c \ + compiler/radeon_pair_translate.c \ + compiler/radeon_pair_schedule.c \ + compiler/radeon_pair_regalloc.c \ + compiler/radeon_pair_dead_sources.c \ + compiler/radeon_dataflow.c \ + compiler/radeon_dataflow_deadcode.c \ + compiler/radeon_dataflow_swizzles.c \ + compiler/radeon_list.c \ + compiler/radeon_optimize.c \ + compiler/radeon_remove_constants.c \ + compiler/radeon_rename_regs.c \ + compiler/radeon_variable.c \ + compiler/r3xx_fragprog.c \ + compiler/r300_fragprog.c \ + compiler/r300_fragprog_swizzle.c \ + compiler/r300_fragprog_emit.c \ + compiler/r500_fragprog.c \ + compiler/r500_fragprog_emit.c \ + compiler/r3xx_vertprog.c \ + compiler/r3xx_vertprog_dump.c \ + compiler/memory_pool.c \ + \ + $(TOP)/src/glsl/ralloc.c \ + $(TOP)/src/mesa/program/register_allocate.c -LIBRARY_INCLUDES = \ - -I$(TOP)/src/mesa/drivers/dri/r300/compiler \ - -I$(TOP)/include - -COMPILER_ARCHIVE = $(TOP)/src/mesa/drivers/dri/r300/compiler/libr300compiler.a -EXTRA_OBJECTS = \ - $(COMPILER_ARCHIVE) +LIBRARY_INCLUDES = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/glsl include ../../Makefile.template -.PHONY: $(COMPILER_ARCHIVE) -$(COMPILER_ARCHIVE): - $(MAKE) -C $(TOP)/src/mesa/drivers/dri/r300/compiler +test: default + @$(MAKE) -s -C compiler/tests/ diff --git a/src/gallium/drivers/r300/SConscript b/src/gallium/drivers/r300/SConscript index 3af157a7956..7ffd1c27c96 100644 --- a/src/gallium/drivers/r300/SConscript +++ b/src/gallium/drivers/r300/SConscript @@ -1,13 +1,11 @@ Import('*') -r300compiler = SConscript('#/src/mesa/drivers/dri/r300/compiler/SConscript') - env = env.Clone() -# add the paths for r300compiler env.Append(CPPPATH = [ - '#/src/mesa/drivers/dri/r300/compiler', '#/include', '#/src/mesa', + '#/src/glsl', + '#/src/mapi', ]) r300 = env.ConvenienceLibrary( @@ -36,7 +34,41 @@ r300 = env.ConvenienceLibrary( 'r300_texture_desc.c', 'r300_tgsi_to_rc.c', 'r300_transfer.c', - ] + r300compiler) + r300compiler + 'compiler/radeon_code.c', + 'compiler/radeon_compiler.c', + 'compiler/radeon_compiler_util.c', + 'compiler/radeon_program.c', + 'compiler/radeon_program_print.c', + 'compiler/radeon_opcodes.c', + 'compiler/radeon_program_alu.c', + 'compiler/radeon_program_pair.c', + 'compiler/radeon_program_tex.c', + 'compiler/radeon_pair_translate.c', + 'compiler/radeon_pair_schedule.c', + 'compiler/radeon_pair_regalloc.c', + 'compiler/radeon_pair_dead_sources.c', + 'compiler/radeon_optimize.c', + 'compiler/radeon_remove_constants.c', + 'compiler/radeon_rename_regs.c', + 'compiler/radeon_emulate_branches.c', + 'compiler/radeon_emulate_loops.c', + 'compiler/radeon_dataflow.c', + 'compiler/radeon_dataflow_deadcode.c', + 'compiler/radeon_dataflow_swizzles.c', + 'compiler/radeon_variable.c', + 'compiler/radeon_list.c', + 'compiler/r3xx_fragprog.c', + 'compiler/r300_fragprog.c', + 'compiler/r300_fragprog_swizzle.c', + 'compiler/r300_fragprog_emit.c', + 'compiler/r500_fragprog.c', + 'compiler/r500_fragprog_emit.c', + 'compiler/r3xx_vertprog.c', + 'compiler/r3xx_vertprog_dump.c', + 'compiler/memory_pool.c', + '#/src/glsl/ralloc.c', + '#/src/mesa/program/register_allocate.c' + ]) env.Alias('r300', r300) diff --git a/src/gallium/drivers/r300/compiler/memory_pool.c b/src/gallium/drivers/r300/compiler/memory_pool.c new file mode 100644 index 00000000000..ddcdddf9e3c --- /dev/null +++ b/src/gallium/drivers/r300/compiler/memory_pool.c @@ -0,0 +1,97 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "memory_pool.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + + +#define POOL_LARGE_ALLOC 4096 +#define POOL_ALIGN 8 + + +struct memory_block { + struct memory_block * next; +}; + +void memory_pool_init(struct memory_pool * pool) +{ + memset(pool, 0, sizeof(struct memory_pool)); +} + + +void memory_pool_destroy(struct memory_pool * pool) +{ + while(pool->blocks) { + struct memory_block * block = pool->blocks; + pool->blocks = block->next; + free(block); + } +} + +static void refill_pool(struct memory_pool * pool) +{ + unsigned int blocksize = pool->total_allocated; + struct memory_block * newblock; + + if (!blocksize) + blocksize = 2*POOL_LARGE_ALLOC; + + newblock = (struct memory_block*)malloc(blocksize); + newblock->next = pool->blocks; + pool->blocks = newblock; + + pool->head = (unsigned char*)(newblock + 1); + pool->end = ((unsigned char*)newblock) + blocksize; + pool->total_allocated += blocksize; +} + + +void * memory_pool_malloc(struct memory_pool * pool, unsigned int bytes) +{ + if (bytes < POOL_LARGE_ALLOC) { + void * ptr; + + if (pool->head + bytes > pool->end) + refill_pool(pool); + + assert(pool->head + bytes <= pool->end); + + ptr = pool->head; + + pool->head += bytes; + pool->head = (unsigned char*)(((unsigned long)pool->head + POOL_ALIGN - 1) & ~(POOL_ALIGN - 1)); + + return ptr; + } else { + struct memory_block * block = (struct memory_block*)malloc(bytes + sizeof(struct memory_block)); + + block->next = pool->blocks; + pool->blocks = block; + + return (block + 1); + } +} + + diff --git a/src/gallium/drivers/r300/compiler/memory_pool.h b/src/gallium/drivers/r300/compiler/memory_pool.h new file mode 100644 index 00000000000..42344d0e3ba --- /dev/null +++ b/src/gallium/drivers/r300/compiler/memory_pool.h @@ -0,0 +1,80 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#ifndef MEMORY_POOL_H +#define MEMORY_POOL_H + +struct memory_block; + +/** + * Provides a pool of memory that can quickly be allocated from, at the + * cost of being unable to explicitly free one of the allocated blocks. + * Instead, the entire pool can be freed at once. + * + * The idea is to allow one to quickly allocate a flexible amount of + * memory during operations like shader compilation while avoiding + * reference counting headaches. + */ +struct memory_pool { + unsigned char * head; + unsigned char * end; + unsigned int total_allocated; + struct memory_block * blocks; +}; + + +void memory_pool_init(struct memory_pool * pool); +void memory_pool_destroy(struct memory_pool * pool); +void * memory_pool_malloc(struct memory_pool * pool, unsigned int bytes); + + +/** + * Generic helper for growing an array that has separate size/count + * and reserved counters to accomodate up to num new element. + * + * type * Array; + * unsigned int Size; + * unsigned int Reserved; + * + * memory_pool_array_reserve(pool, type, Array, Size, Reserved, k); + * assert(Size + k < Reserved); + * + * \note Size is not changed by this macro. + * + * \warning Array, Size, Reserved have to be lvalues and may be evaluated + * several times. + */ +#define memory_pool_array_reserve(pool, type, array, size, reserved, num) do { \ + unsigned int _num = (num); \ + if ((size) + _num > (reserved)) { \ + unsigned int newreserve = (reserved) * 2; \ + type * newarray; \ + if (newreserve < _num) \ + newreserve = 4 * _num; /* arbitrary heuristic */ \ + newarray = memory_pool_malloc((pool), newreserve * sizeof(type)); \ + memcpy(newarray, (array), (size) * sizeof(type)); \ + (array) = newarray; \ + (reserved) = newreserve; \ + } \ +} while(0) + +#endif /* MEMORY_POOL_H */ diff --git a/src/gallium/drivers/r300/compiler/r300_fragprog.c b/src/gallium/drivers/r300/compiler/r300_fragprog.c new file mode 100644 index 00000000000..deba9ca834d --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r300_fragprog.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2005 Ben Skeggs. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "r300_fragprog.h" + +#include <stdio.h> + +#include "../r300_reg.h" + +static void presub_string(char out[10], unsigned int inst) +{ + switch(inst & 0x600000){ + case R300_ALU_SRCP_1_MINUS_2_SRC0: + sprintf(out, "bias"); + break; + case R300_ALU_SRCP_SRC1_MINUS_SRC0: + sprintf(out, "sub"); + break; + case R300_ALU_SRCP_SRC1_PLUS_SRC0: + sprintf(out, "add"); + break; + case R300_ALU_SRCP_1_MINUS_SRC0: + sprintf(out, "inv "); + break; + } +} + +static int get_msb(unsigned int bit, unsigned int r400_ext_addr) +{ + return (r400_ext_addr & bit) ? 1 << 5 : 0; +} + +/* just some random things... */ +void r300FragmentProgramDump(struct radeon_compiler *c, void *user) +{ + struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c; + struct r300_fragment_program_code *code = &compiler->code->code.r300; + int n, i, j; + static int pc = 0; + + fprintf(stderr, "pc=%d*************************************\n", pc++); + + fprintf(stderr, "Hardware program\n"); + fprintf(stderr, "----------------\n"); + if (c->is_r400) { + fprintf(stderr, "code_offset_ext: %08x\n", code->r400_code_offset_ext); + } + + for (n = 0; n <= (code->config & 3); n++) { + uint32_t code_addr = code->code_addr[3 - (code->config & 3) + n]; + unsigned int alu_offset = ((code_addr & R300_ALU_START_MASK) >> R300_ALU_START_SHIFT) + + (((code->r400_code_offset_ext >> (24 - (n * 6))) & 0x7) << 6); + unsigned int alu_end = ((code_addr & R300_ALU_SIZE_MASK) >> R300_ALU_SIZE_SHIFT) + + (((code->r400_code_offset_ext >> (27 - (n * 6))) & 0x7) << 6); + int tex_offset = (code_addr & R300_TEX_START_MASK) >> R300_TEX_START_SHIFT; + int tex_end = (code_addr & R300_TEX_SIZE_MASK) >> R300_TEX_SIZE_SHIFT; + + fprintf(stderr, "NODE %d: alu_offset: %u, tex_offset: %d, " + "alu_end: %u, tex_end: %d (code_addr: %08x)\n", n, + alu_offset, tex_offset, alu_end, tex_end, code_addr); + + if (n > 0 || (code->config & R300_PFS_CNTL_FIRST_NODE_HAS_TEX)) { + fprintf(stderr, " TEX:\n"); + for (i = tex_offset; + i <= tex_offset + tex_end; + ++i) { + const char *instr; + + switch ((code->tex. + inst[i] >> R300_TEX_INST_SHIFT) & + 15) { + case R300_TEX_OP_LD: + instr = "TEX"; + break; + case R300_TEX_OP_KIL: + instr = "KIL"; + break; + case R300_TEX_OP_TXP: + instr = "TXP"; + break; + case R300_TEX_OP_TXB: + instr = "TXB"; + break; + default: + instr = "UNKNOWN"; + } + + fprintf(stderr, + " %s t%i, %c%i, texture[%i] (%08x)\n", + instr, + (code->tex. + inst[i] >> R300_DST_ADDR_SHIFT) & 31, + 't', + (code->tex. + inst[i] >> R300_SRC_ADDR_SHIFT) & 31, + (code->tex. + inst[i] & R300_TEX_ID_MASK) >> + R300_TEX_ID_SHIFT, + code->tex.inst[i]); + } + } + + for (i = alu_offset; + i <= alu_offset + alu_end; ++i) { + char srcc[4][10], dstc[20]; + char srca[4][10], dsta[20]; + char argc[3][20]; + char arga[3][20]; + char flags[5], tmp[10]; + + for (j = 0; j < 3; ++j) { + int regc = code->alu.inst[i].rgb_addr >> (j * 6); + int rega = code->alu.inst[i].alpha_addr >> (j * 6); + int msbc = get_msb(R400_ADDR_EXT_RGB_MSB_BIT(j), + code->alu.inst[i].r400_ext_addr); + int msba = get_msb(R400_ADDR_EXT_A_MSB_BIT(j), + code->alu.inst[i].r400_ext_addr); + + sprintf(srcc[j], "%c%i", + (regc & 32) ? 'c' : 't', (regc & 31) | msbc); + sprintf(srca[j], "%c%i", + (rega & 32) ? 'c' : 't', (rega & 31) | msba); + } + + dstc[0] = 0; + sprintf(flags, "%s%s%s", + (code->alu.inst[i]. + rgb_addr & R300_ALU_DSTC_REG_X) ? "x" : "", + (code->alu.inst[i]. + rgb_addr & R300_ALU_DSTC_REG_Y) ? "y" : "", + (code->alu.inst[i]. + rgb_addr & R300_ALU_DSTC_REG_Z) ? "z" : ""); + if (flags[0] != 0) { + unsigned int msb = get_msb( + R400_ADDRD_EXT_RGB_MSB_BIT, + code->alu.inst[i].r400_ext_addr); + + sprintf(dstc, "t%i.%s ", + ((code->alu.inst[i]. + rgb_addr >> R300_ALU_DSTC_SHIFT) + & 31) | msb, + flags); + } + sprintf(flags, "%s%s%s", + (code->alu.inst[i]. + rgb_addr & R300_ALU_DSTC_OUTPUT_X) ? "x" : "", + (code->alu.inst[i]. + rgb_addr & R300_ALU_DSTC_OUTPUT_Y) ? "y" : "", + (code->alu.inst[i]. + rgb_addr & R300_ALU_DSTC_OUTPUT_Z) ? "z" : ""); + if (flags[0] != 0) { + sprintf(tmp, "o%i.%s", + (code->alu.inst[i]. + rgb_addr >> 29) & 3, + flags); + strcat(dstc, tmp); + } + /* Presub */ + presub_string(srcc[3], code->alu.inst[i].rgb_inst); + presub_string(srca[3], code->alu.inst[i].alpha_inst); + + dsta[0] = 0; + if (code->alu.inst[i].alpha_addr & R300_ALU_DSTA_REG) { + unsigned int msb = get_msb( + R400_ADDRD_EXT_A_MSB_BIT, + code->alu.inst[i].r400_ext_addr); + sprintf(dsta, "t%i.w ", + ((code->alu.inst[i]. + alpha_addr >> R300_ALU_DSTA_SHIFT) & 31) + | msb); + } + if (code->alu.inst[i].alpha_addr & R300_ALU_DSTA_OUTPUT) { + sprintf(tmp, "o%i.w ", + (code->alu.inst[i]. + alpha_addr >> 25) & 3); + strcat(dsta, tmp); + } + if (code->alu.inst[i].alpha_addr & R300_ALU_DSTA_DEPTH) { + strcat(dsta, "Z"); + } + + fprintf(stderr, + "%3i: xyz: %3s %3s %3s %5s-> %-20s (%08x)\n" + " w: %3s %3s %3s %5s-> %-20s (%08x)\n", i, + srcc[0], srcc[1], srcc[2], srcc[3], dstc, + code->alu.inst[i].rgb_addr, srca[0], srca[1], + srca[2], srca[3], dsta, + code->alu.inst[i].alpha_addr); + + for (j = 0; j < 3; ++j) { + int regc = code->alu.inst[i].rgb_inst >> (j * 7); + int rega = code->alu.inst[i].alpha_inst >> (j * 7); + int d; + char buf[20]; + + d = regc & 31; + if (d < 12) { + switch (d % 4) { + case R300_ALU_ARGC_SRC0C_XYZ: + sprintf(buf, "%s.xyz", + srcc[d / 4]); + break; + case R300_ALU_ARGC_SRC0C_XXX: + sprintf(buf, "%s.xxx", + srcc[d / 4]); + break; + case R300_ALU_ARGC_SRC0C_YYY: + sprintf(buf, "%s.yyy", + srcc[d / 4]); + break; + case R300_ALU_ARGC_SRC0C_ZZZ: + sprintf(buf, "%s.zzz", + srcc[d / 4]); + break; + } + } else if (d < 15) { + sprintf(buf, "%s.www", srca[d - 12]); + } else if (d < 20 ) { + switch(d) { + case R300_ALU_ARGC_SRCP_XYZ: + sprintf(buf, "srcp.xyz"); + break; + case R300_ALU_ARGC_SRCP_XXX: + sprintf(buf, "srcp.xxx"); + break; + case R300_ALU_ARGC_SRCP_YYY: + sprintf(buf, "srcp.yyy"); + break; + case R300_ALU_ARGC_SRCP_ZZZ: + sprintf(buf, "srcp.zzz"); + break; + case R300_ALU_ARGC_SRCP_WWW: + sprintf(buf, "srcp.www"); + break; + } + } else if (d == 20) { + sprintf(buf, "0.0"); + } else if (d == 21) { + sprintf(buf, "1.0"); + } else if (d == 22) { + sprintf(buf, "0.5"); + } else if (d >= 23 && d < 32) { + d -= 23; + switch (d / 3) { + case 0: + sprintf(buf, "%s.yzx", + srcc[d % 3]); + break; + case 1: + sprintf(buf, "%s.zxy", + srcc[d % 3]); + break; + case 2: + sprintf(buf, "%s.Wzy", + srcc[d % 3]); + break; + } + } else { + sprintf(buf, "%i", d); + } + + sprintf(argc[j], "%s%s%s%s", + (regc & 32) ? "-" : "", + (regc & 64) ? "|" : "", + buf, (regc & 64) ? "|" : ""); + + d = rega & 31; + if (d < 9) { + sprintf(buf, "%s.%c", srcc[d / 3], + 'x' + (char)(d % 3)); + } else if (d < 12) { + sprintf(buf, "%s.w", srca[d - 9]); + } else if (d < 16) { + switch(d) { + case R300_ALU_ARGA_SRCP_X: + sprintf(buf, "srcp.x"); + break; + case R300_ALU_ARGA_SRCP_Y: + sprintf(buf, "srcp.y"); + break; + case R300_ALU_ARGA_SRCP_Z: + sprintf(buf, "srcp.z"); + break; + case R300_ALU_ARGA_SRCP_W: + sprintf(buf, "srcp.w"); + break; + } + } else if (d == 16) { + sprintf(buf, "0.0"); + } else if (d == 17) { + sprintf(buf, "1.0"); + } else if (d == 18) { + sprintf(buf, "0.5"); + } else { + sprintf(buf, "%i", d); + } + + sprintf(arga[j], "%s%s%s%s", + (rega & 32) ? "-" : "", + (rega & 64) ? "|" : "", + buf, (rega & 64) ? "|" : ""); + } + + fprintf(stderr, " xyz: %8s %8s %8s op: %08x %s\n" + " w: %8s %8s %8s op: %08x\n", + argc[0], argc[1], argc[2], + code->alu.inst[i].rgb_inst, + code->alu.inst[i].rgb_inst & R300_ALU_INSERT_NOP ? + "NOP" : "", + arga[0], arga[1],arga[2], + code->alu.inst[i].alpha_inst); + } + } +} diff --git a/src/gallium/drivers/r300/compiler/r300_fragprog.h b/src/gallium/drivers/r300/compiler/r300_fragprog.h new file mode 100644 index 00000000000..0c88bab2f33 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r300_fragprog.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2005 Ben Skeggs. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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: + * Ben Skeggs <[email protected]> + * Jerome Glisse <[email protected]> + */ +#ifndef __R300_FRAGPROG_H_ +#define __R300_FRAGPROG_H_ + +#include "radeon_compiler.h" +#include "radeon_program.h" + + +extern void r300BuildFragmentProgramHwCode(struct radeon_compiler *c, void *user); + +extern void r300FragmentProgramDump(struct radeon_compiler *c, void *user); + +#endif diff --git a/src/gallium/drivers/r300/compiler/r300_fragprog_emit.c b/src/gallium/drivers/r300/compiler/r300_fragprog_emit.c new file mode 100644 index 00000000000..e6fd1fde62d --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r300_fragprog_emit.c @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2005 Ben Skeggs. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * \file + * + * Emit the r300_fragment_program_code that can be understood by the hardware. + * Input is a pre-transformed radeon_program. + * + * \author Ben Skeggs <[email protected]> + * + * \author Jerome Glisse <[email protected]> + */ + +#include "r300_fragprog.h" + +#include "../r300_reg.h" + +#include "radeon_program_pair.h" +#include "r300_fragprog_swizzle.h" + + +struct r300_emit_state { + struct r300_fragment_program_compiler * compiler; + + unsigned current_node : 2; + unsigned node_first_tex : 8; + unsigned node_first_alu : 8; + uint32_t node_flags; +}; + +#define PROG_CODE \ + struct r300_fragment_program_compiler *c = emit->compiler; \ + struct r300_fragment_program_code *code = &c->code->code.r300 + +#define error(fmt, args...) do { \ + rc_error(&c->Base, "%s::%s(): " fmt "\n", \ + __FILE__, __FUNCTION__, ##args); \ + } while(0) + +static unsigned int get_msbs_alu(unsigned int bits) +{ + return (bits >> 6) & 0x7; +} + +/** + * @param lsbs The number of least significant bits + */ +static unsigned int get_msbs_tex(unsigned int bits, unsigned int lsbs) +{ + return (bits >> lsbs) & 0x15; +} + +#define R400_EXT_GET_MSBS(x, lsbs, mask) (((x) >> lsbs) & mask) + +/** + * Mark a temporary register as used. + */ +static void use_temporary(struct r300_fragment_program_code *code, unsigned int index) +{ + if (index > code->pixsize) + code->pixsize = index; +} + +static unsigned int use_source(struct r300_fragment_program_code* code, struct rc_pair_instruction_source src) +{ + if (!src.Used) + return 0; + + if (src.File == RC_FILE_CONSTANT) { + return src.Index | (1 << 5); + } else if (src.File == RC_FILE_TEMPORARY || src.File == RC_FILE_INPUT) { + use_temporary(code, src.Index); + return src.Index & 0x1f; + } + + return 0; +} + + +static unsigned int translate_rgb_opcode(struct r300_fragment_program_compiler * c, rc_opcode opcode) +{ + switch(opcode) { + case RC_OPCODE_CMP: return R300_ALU_OUTC_CMP; + case RC_OPCODE_CND: return R300_ALU_OUTC_CND; + case RC_OPCODE_DP3: return R300_ALU_OUTC_DP3; + case RC_OPCODE_DP4: return R300_ALU_OUTC_DP4; + case RC_OPCODE_FRC: return R300_ALU_OUTC_FRC; + default: + error("translate_rgb_opcode: Unknown opcode %s", rc_get_opcode_info(opcode)->Name); + /* fall through */ + case RC_OPCODE_NOP: + /* fall through */ + case RC_OPCODE_MAD: return R300_ALU_OUTC_MAD; + case RC_OPCODE_MAX: return R300_ALU_OUTC_MAX; + case RC_OPCODE_MIN: return R300_ALU_OUTC_MIN; + case RC_OPCODE_REPL_ALPHA: return R300_ALU_OUTC_REPL_ALPHA; + } +} + +static unsigned int translate_alpha_opcode(struct r300_fragment_program_compiler * c, rc_opcode opcode) +{ + switch(opcode) { + case RC_OPCODE_CMP: return R300_ALU_OUTA_CMP; + case RC_OPCODE_CND: return R300_ALU_OUTA_CND; + case RC_OPCODE_DP3: return R300_ALU_OUTA_DP4; + case RC_OPCODE_DP4: return R300_ALU_OUTA_DP4; + case RC_OPCODE_EX2: return R300_ALU_OUTA_EX2; + case RC_OPCODE_FRC: return R300_ALU_OUTA_FRC; + case RC_OPCODE_LG2: return R300_ALU_OUTA_LG2; + default: + error("translate_rgb_opcode: Unknown opcode %s", rc_get_opcode_info(opcode)->Name); + /* fall through */ + case RC_OPCODE_NOP: + /* fall through */ + case RC_OPCODE_MAD: return R300_ALU_OUTA_MAD; + case RC_OPCODE_MAX: return R300_ALU_OUTA_MAX; + case RC_OPCODE_MIN: return R300_ALU_OUTA_MIN; + case RC_OPCODE_RCP: return R300_ALU_OUTA_RCP; + case RC_OPCODE_RSQ: return R300_ALU_OUTA_RSQ; + } +} + +/** + * Emit one paired ALU instruction. + */ +static int emit_alu(struct r300_emit_state * emit, struct rc_pair_instruction* inst) +{ + int ip; + int j; + PROG_CODE; + + if (code->alu.length >= c->Base.max_alu_insts) { + error("Too many ALU instructions"); + return 0; + } + + ip = code->alu.length++; + + code->alu.inst[ip].rgb_inst = translate_rgb_opcode(c, inst->RGB.Opcode); + code->alu.inst[ip].alpha_inst = translate_alpha_opcode(c, inst->Alpha.Opcode); + + for(j = 0; j < 3; ++j) { + /* Set the RGB address */ + unsigned int src = use_source(code, inst->RGB.Src[j]); + unsigned int arg; + if (inst->RGB.Src[j].Index >= R300_PFS_NUM_TEMP_REGS) + code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_RGB_MSB_BIT(j); + + code->alu.inst[ip].rgb_addr |= src << (6*j); + + /* Set the Alpha address */ + src = use_source(code, inst->Alpha.Src[j]); + if (inst->Alpha.Src[j].Index >= R300_PFS_NUM_TEMP_REGS) + code->alu.inst[ip].r400_ext_addr |= R400_ADDR_EXT_A_MSB_BIT(j); + + code->alu.inst[ip].alpha_addr |= src << (6*j); + + arg = r300FPTranslateRGBSwizzle(inst->RGB.Arg[j].Source, inst->RGB.Arg[j].Swizzle); + arg |= inst->RGB.Arg[j].Abs << 6; + arg |= inst->RGB.Arg[j].Negate << 5; + code->alu.inst[ip].rgb_inst |= arg << (7*j); + + arg = r300FPTranslateAlphaSwizzle(inst->Alpha.Arg[j].Source, inst->Alpha.Arg[j].Swizzle); + arg |= inst->Alpha.Arg[j].Abs << 6; + arg |= inst->Alpha.Arg[j].Negate << 5; + code->alu.inst[ip].alpha_inst |= arg << (7*j); + } + + /* Presubtract */ + if (inst->RGB.Src[RC_PAIR_PRESUB_SRC].Used) { + switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { + case RC_PRESUB_BIAS: + code->alu.inst[ip].rgb_inst |= + R300_ALU_SRCP_1_MINUS_2_SRC0; + break; + case RC_PRESUB_ADD: + code->alu.inst[ip].rgb_inst |= + R300_ALU_SRCP_SRC1_PLUS_SRC0; + break; + case RC_PRESUB_SUB: + code->alu.inst[ip].rgb_inst |= + R300_ALU_SRCP_SRC1_MINUS_SRC0; + break; + case RC_PRESUB_INV: + code->alu.inst[ip].rgb_inst |= + R300_ALU_SRCP_1_MINUS_SRC0; + break; + default: + break; + } + } + + if (inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) { + switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { + case RC_PRESUB_BIAS: + code->alu.inst[ip].alpha_inst |= + R300_ALU_SRCP_1_MINUS_2_SRC0; + break; + case RC_PRESUB_ADD: + code->alu.inst[ip].alpha_inst |= + R300_ALU_SRCP_SRC1_PLUS_SRC0; + break; + case RC_PRESUB_SUB: + code->alu.inst[ip].alpha_inst |= + R300_ALU_SRCP_SRC1_MINUS_SRC0; + break; + case RC_PRESUB_INV: + code->alu.inst[ip].alpha_inst |= + R300_ALU_SRCP_1_MINUS_SRC0; + break; + default: + break; + } + } + + if (inst->RGB.Saturate) + code->alu.inst[ip].rgb_inst |= R300_ALU_OUTC_CLAMP; + if (inst->Alpha.Saturate) + code->alu.inst[ip].alpha_inst |= R300_ALU_OUTA_CLAMP; + + if (inst->RGB.WriteMask) { + use_temporary(code, inst->RGB.DestIndex); + if (inst->RGB.DestIndex >= R300_PFS_NUM_TEMP_REGS) + code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_RGB_MSB_BIT; + code->alu.inst[ip].rgb_addr |= + ((inst->RGB.DestIndex & 0x1f) << R300_ALU_DSTC_SHIFT) | + (inst->RGB.WriteMask << R300_ALU_DSTC_REG_MASK_SHIFT); + } + if (inst->RGB.OutputWriteMask) { + code->alu.inst[ip].rgb_addr |= + (inst->RGB.OutputWriteMask << R300_ALU_DSTC_OUTPUT_MASK_SHIFT) | + R300_RGB_TARGET(inst->RGB.Target); + emit->node_flags |= R300_RGBA_OUT; + } + + if (inst->Alpha.WriteMask) { + use_temporary(code, inst->Alpha.DestIndex); + if (inst->Alpha.DestIndex >= R300_PFS_NUM_TEMP_REGS) + code->alu.inst[ip].r400_ext_addr |= R400_ADDRD_EXT_A_MSB_BIT; + code->alu.inst[ip].alpha_addr |= + ((inst->Alpha.DestIndex & 0x1f) << R300_ALU_DSTA_SHIFT) | + R300_ALU_DSTA_REG; + } + if (inst->Alpha.OutputWriteMask) { + code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_OUTPUT | + R300_ALPHA_TARGET(inst->Alpha.Target); + emit->node_flags |= R300_RGBA_OUT; + } + if (inst->Alpha.DepthWriteMask) { + code->alu.inst[ip].alpha_addr |= R300_ALU_DSTA_DEPTH; + emit->node_flags |= R300_W_OUT; + c->code->writes_depth = 1; + } + if (inst->Nop) + code->alu.inst[ip].rgb_inst |= R300_ALU_INSERT_NOP; + + return 1; +} + + +/** + * Finish the current node without advancing to the next one. + */ +static int finish_node(struct r300_emit_state * emit) +{ + struct r300_fragment_program_compiler * c = emit->compiler; + struct r300_fragment_program_code *code = &emit->compiler->code->code.r300; + unsigned alu_offset; + unsigned alu_end; + unsigned tex_offset; + unsigned tex_end; + + unsigned int alu_offset_msbs, alu_end_msbs; + + if (code->alu.length == emit->node_first_alu) { + /* Generate a single NOP for this node */ + struct rc_pair_instruction inst; + memset(&inst, 0, sizeof(inst)); + if (!emit_alu(emit, &inst)) + return 0; + } + + alu_offset = emit->node_first_alu; + alu_end = code->alu.length - alu_offset - 1; + tex_offset = emit->node_first_tex; + tex_end = code->tex.length - tex_offset - 1; + + if (code->tex.length == emit->node_first_tex) { + if (emit->current_node > 0) { + error("Node %i has no TEX instructions", emit->current_node); + return 0; + } + + tex_end = 0; + } else { + if (emit->current_node == 0) + code->config |= R300_PFS_CNTL_FIRST_NODE_HAS_TEX; + } + + /* Write the config register. + * Note: The order in which the words for each node are written + * is not correct here and needs to be fixed up once we're entirely + * done + * + * Also note that the register specification from AMD is slightly + * incorrect in its description of this register. */ + code->code_addr[emit->current_node] = + ((alu_offset << R300_ALU_START_SHIFT) + & R300_ALU_START_MASK) + | ((alu_end << R300_ALU_SIZE_SHIFT) + & R300_ALU_SIZE_MASK) + | ((tex_offset << R300_TEX_START_SHIFT) + & R300_TEX_START_MASK) + | ((tex_end << R300_TEX_SIZE_SHIFT) + & R300_TEX_SIZE_MASK) + | emit->node_flags + | (get_msbs_tex(tex_offset, 5) + << R400_TEX_START_MSB_SHIFT) + | (get_msbs_tex(tex_end, 5) + << R400_TEX_SIZE_MSB_SHIFT) + ; + + /* Write r400 extended instruction fields. These will be ignored on + * r300 cards. */ + alu_offset_msbs = get_msbs_alu(alu_offset); + alu_end_msbs = get_msbs_alu(alu_end); + switch(emit->current_node) { + case 0: + code->r400_code_offset_ext |= + alu_offset_msbs << R400_ALU_START3_MSB_SHIFT + | alu_end_msbs << R400_ALU_SIZE3_MSB_SHIFT; + break; + case 1: + code->r400_code_offset_ext |= + alu_offset_msbs << R400_ALU_START2_MSB_SHIFT + | alu_end_msbs << R400_ALU_SIZE2_MSB_SHIFT; + break; + case 2: + code->r400_code_offset_ext |= + alu_offset_msbs << R400_ALU_START1_MSB_SHIFT + | alu_end_msbs << R400_ALU_SIZE1_MSB_SHIFT; + break; + case 3: + code->r400_code_offset_ext |= + alu_offset_msbs << R400_ALU_START0_MSB_SHIFT + | alu_end_msbs << R400_ALU_SIZE0_MSB_SHIFT; + break; + } + return 1; +} + + +/** + * Begin a block of texture instructions. + * Create the necessary indirection. + */ +static int begin_tex(struct r300_emit_state * emit) +{ + PROG_CODE; + + if (code->alu.length == emit->node_first_alu && + code->tex.length == emit->node_first_tex) { + return 1; + } + + if (emit->current_node == 3) { + error("Too many texture indirections"); + return 0; + } + + if (!finish_node(emit)) + return 0; + + emit->current_node++; + emit->node_first_tex = code->tex.length; + emit->node_first_alu = code->alu.length; + emit->node_flags = 0; + return 1; +} + + +static int emit_tex(struct r300_emit_state * emit, struct rc_instruction * inst) +{ + unsigned int unit; + unsigned int dest; + unsigned int opcode; + PROG_CODE; + + if (code->tex.length >= emit->compiler->Base.max_tex_insts) { + error("Too many TEX instructions"); + return 0; + } + + unit = inst->U.I.TexSrcUnit; + dest = inst->U.I.DstReg.Index; + + switch(inst->U.I.Opcode) { + case RC_OPCODE_KIL: opcode = R300_TEX_OP_KIL; break; + case RC_OPCODE_TEX: opcode = R300_TEX_OP_LD; break; + case RC_OPCODE_TXB: opcode = R300_TEX_OP_TXB; break; + case RC_OPCODE_TXP: opcode = R300_TEX_OP_TXP; break; + default: + error("Unknown texture opcode %s", rc_get_opcode_info(inst->U.I.Opcode)->Name); + return 0; + } + + if (inst->U.I.Opcode == RC_OPCODE_KIL) { + unit = 0; + dest = 0; + } else { + use_temporary(code, dest); + } + + use_temporary(code, inst->U.I.SrcReg[0].Index); + + code->tex.inst[code->tex.length++] = + ((inst->U.I.SrcReg[0].Index << R300_SRC_ADDR_SHIFT) + & R300_SRC_ADDR_MASK) + | ((dest << R300_DST_ADDR_SHIFT) + & R300_DST_ADDR_MASK) + | (unit << R300_TEX_ID_SHIFT) + | (opcode << R300_TEX_INST_SHIFT) + | (inst->U.I.SrcReg[0].Index >= R300_PFS_NUM_TEMP_REGS ? + R400_SRC_ADDR_EXT_BIT : 0) + | (dest >= R300_PFS_NUM_TEMP_REGS ? + R400_DST_ADDR_EXT_BIT : 0) + ; + return 1; +} + + +/** + * Final compilation step: Turn the intermediate radeon_program into + * machine-readable instructions. + */ +void r300BuildFragmentProgramHwCode(struct radeon_compiler *c, void *user) +{ + struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c; + struct r300_emit_state emit; + struct r300_fragment_program_code *code = &compiler->code->code.r300; + unsigned int tex_end; + + memset(&emit, 0, sizeof(emit)); + emit.compiler = compiler; + + memset(code, 0, sizeof(struct r300_fragment_program_code)); + + for(struct rc_instruction * inst = compiler->Base.Program.Instructions.Next; + inst != &compiler->Base.Program.Instructions && !compiler->Base.Error; + inst = inst->Next) { + if (inst->Type == RC_INSTRUCTION_NORMAL) { + if (inst->U.I.Opcode == RC_OPCODE_BEGIN_TEX) { + begin_tex(&emit); + continue; + } + + emit_tex(&emit, inst); + } else { + emit_alu(&emit, &inst->U.P); + } + } + + if (code->pixsize >= compiler->Base.max_temp_regs) + rc_error(&compiler->Base, "Too many hardware temporaries used.\n"); + + if (compiler->Base.Error) + return; + + /* Finish the program */ + finish_node(&emit); + + code->config |= emit.current_node; /* FIRST_NODE_HAS_TEX set by finish_node */ + + /* Set r400 extended instruction fields. These values will be ignored + * on r300 cards. */ + code->r400_code_offset_ext |= + (get_msbs_alu(0) + << R400_ALU_OFFSET_MSB_SHIFT) + | (get_msbs_alu(code->alu.length - 1) + << R400_ALU_SIZE_MSB_SHIFT); + + tex_end = code->tex.length ? code->tex.length - 1 : 0; + code->code_offset = + ((0 << R300_PFS_CNTL_ALU_OFFSET_SHIFT) + & R300_PFS_CNTL_ALU_OFFSET_MASK) + | (((code->alu.length - 1) << R300_PFS_CNTL_ALU_END_SHIFT) + & R300_PFS_CNTL_ALU_END_MASK) + | ((0 << R300_PFS_CNTL_TEX_OFFSET_SHIFT) + & R300_PFS_CNTL_TEX_OFFSET_MASK) + | ((tex_end << R300_PFS_CNTL_TEX_END_SHIFT) + & R300_PFS_CNTL_TEX_END_MASK) + | (get_msbs_tex(0, 5) << R400_TEX_START_MSB_SHIFT) + | (get_msbs_tex(tex_end, 6) << R400_TEX_SIZE_MSB_SHIFT) + ; + + if (emit.current_node < 3) { + int shift = 3 - emit.current_node; + int i; + for(i = emit.current_node; i >= 0; --i) + code->code_addr[shift + i] = code->code_addr[i]; + for(i = 0; i < shift; ++i) + code->code_addr[i] = 0; + } + + if (code->pixsize >= R300_PFS_NUM_TEMP_REGS + || code->alu.length > R300_PFS_MAX_ALU_INST + || code->tex.length > R300_PFS_MAX_TEX_INST) { + + code->r390_mode = 1; + } +} diff --git a/src/gallium/drivers/r300/compiler/r300_fragprog_swizzle.c b/src/gallium/drivers/r300/compiler/r300_fragprog_swizzle.c new file mode 100644 index 00000000000..b7bca8c0cfa --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r300_fragprog_swizzle.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * @file + * Utilities to deal with the somewhat odd restriction on R300 fragment + * program swizzles. + */ + +#include "r300_fragprog_swizzle.h" + +#include <stdio.h> + +#include "../r300_reg.h" +#include "radeon_compiler.h" + +#define MAKE_SWZ3(x, y, z) (RC_MAKE_SWIZZLE(RC_SWIZZLE_##x, RC_SWIZZLE_##y, RC_SWIZZLE_##z, RC_SWIZZLE_ZERO)) + +struct swizzle_data { + unsigned int hash; /**< swizzle value this matches */ + unsigned int base; /**< base value for hw swizzle */ + unsigned int stride; /**< difference in base between arg0/1/2 */ + unsigned int srcp_stride; /**< difference in base between arg0/scrp */ +}; + +static const struct swizzle_data native_swizzles[] = { + {MAKE_SWZ3(X, Y, Z), R300_ALU_ARGC_SRC0C_XYZ, 4, 15}, + {MAKE_SWZ3(X, X, X), R300_ALU_ARGC_SRC0C_XXX, 4, 15}, + {MAKE_SWZ3(Y, Y, Y), R300_ALU_ARGC_SRC0C_YYY, 4, 15}, + {MAKE_SWZ3(Z, Z, Z), R300_ALU_ARGC_SRC0C_ZZZ, 4, 15}, + {MAKE_SWZ3(W, W, W), R300_ALU_ARGC_SRC0A, 1, 7}, + {MAKE_SWZ3(Y, Z, X), R300_ALU_ARGC_SRC0C_YZX, 1, 0}, + {MAKE_SWZ3(Z, X, Y), R300_ALU_ARGC_SRC0C_ZXY, 1, 0}, + {MAKE_SWZ3(W, Z, Y), R300_ALU_ARGC_SRC0CA_WZY, 1, 0}, + {MAKE_SWZ3(ONE, ONE, ONE), R300_ALU_ARGC_ONE, 0, 0}, + {MAKE_SWZ3(ZERO, ZERO, ZERO), R300_ALU_ARGC_ZERO, 0, 0}, + {MAKE_SWZ3(HALF, HALF, HALF), R300_ALU_ARGC_HALF, 0, 0} +}; + +static const int num_native_swizzles = sizeof(native_swizzles)/sizeof(native_swizzles[0]); + +/** + * Find a native RGB swizzle that matches the given swizzle. + * Returns 0 if none found. + */ +static const struct swizzle_data* lookup_native_swizzle(unsigned int swizzle) +{ + int i, comp; + + for(i = 0; i < num_native_swizzles; ++i) { + const struct swizzle_data* sd = &native_swizzles[i]; + for(comp = 0; comp < 3; ++comp) { + unsigned int swz = GET_SWZ(swizzle, comp); + if (swz == RC_SWIZZLE_UNUSED) + continue; + if (swz != GET_SWZ(sd->hash, comp)) + break; + } + if (comp == 3) + return sd; + } + + return 0; +} + +/** + * Determines if the given swizzle is valid for r300/r400. In most situations + * it is better to use r300_swizzle_is_native() which can be accesed via + * struct radeon_compiler *c; c->SwizzleCaps->IsNative(). + */ +int r300_swizzle_is_native_basic(unsigned int swizzle) +{ + if(lookup_native_swizzle(swizzle)) + return 1; + else + return 0; +} + +/** + * Check whether the given instruction supports the swizzle and negate + * combinations in the given source register. + */ +static int r300_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) +{ + const struct swizzle_data* sd; + unsigned int relevant; + int j; + + if (opcode == RC_OPCODE_KIL || + opcode == RC_OPCODE_TEX || + opcode == RC_OPCODE_TXB || + opcode == RC_OPCODE_TXP) { + if (reg.Abs || reg.Negate) + return 0; + + for(j = 0; j < 4; ++j) { + unsigned int swz = GET_SWZ(reg.Swizzle, j); + if (swz == RC_SWIZZLE_UNUSED) + continue; + if (swz != j) + return 0; + } + + return 1; + } + + relevant = 0; + + for(j = 0; j < 3; ++j) + if (GET_SWZ(reg.Swizzle, j) != RC_SWIZZLE_UNUSED) + relevant |= 1 << j; + + if ((reg.Negate & relevant) && ((reg.Negate & relevant) != relevant)) + return 0; + + sd = lookup_native_swizzle(reg.Swizzle); + if (!sd || (reg.File == RC_FILE_PRESUB && sd->srcp_stride == 0)) + return 0; + + return 1; +} + + +static void r300_swizzle_split( + struct rc_src_register src, unsigned int mask, + struct rc_swizzle_split * split) +{ + split->NumPhases = 0; + + while(mask) { + unsigned int best_matchcount = 0; + unsigned int best_matchmask = 0; + int i, comp; + + for(i = 0; i < num_native_swizzles; ++i) { + const struct swizzle_data *sd = &native_swizzles[i]; + unsigned int matchcount = 0; + unsigned int matchmask = 0; + for(comp = 0; comp < 3; ++comp) { + unsigned int swz; + if (!GET_BIT(mask, comp)) + continue; + swz = GET_SWZ(src.Swizzle, comp); + if (swz == RC_SWIZZLE_UNUSED) + continue; + if (swz == GET_SWZ(sd->hash, comp)) { + /* check if the negate bit of current component + * is the same for already matched components */ + if (matchmask && (!!(src.Negate & matchmask) != !!(src.Negate & (1 << comp)))) + continue; + + matchcount++; + matchmask |= 1 << comp; + } + } + if (matchcount > best_matchcount) { + best_matchcount = matchcount; + best_matchmask = matchmask; + if (matchmask == (mask & RC_MASK_XYZ)) + break; + } + } + + if (mask & RC_MASK_W) + best_matchmask |= RC_MASK_W; + + split->Phase[split->NumPhases++] = best_matchmask; + mask &= ~best_matchmask; + } +} + +struct rc_swizzle_caps r300_swizzle_caps = { + .IsNative = r300_swizzle_is_native, + .Split = r300_swizzle_split +}; + + +/** + * Translate an RGB (XYZ) swizzle into the hardware code for the given + * instruction source. + */ +unsigned int r300FPTranslateRGBSwizzle(unsigned int src, unsigned int swizzle) +{ + const struct swizzle_data* sd = lookup_native_swizzle(swizzle); + + if (!sd || (src == RC_PAIR_PRESUB_SRC && sd->srcp_stride == 0)) { + fprintf(stderr, "Not a native swizzle: %08x\n", swizzle); + return 0; + } + + if (src == RC_PAIR_PRESUB_SRC) { + return sd->base + sd->srcp_stride; + } else { + return sd->base + src*sd->stride; + } +} + + +/** + * Translate an Alpha (W) swizzle into the hardware code for the given + * instruction source. + */ +unsigned int r300FPTranslateAlphaSwizzle(unsigned int src, unsigned int swizzle) +{ + unsigned int swz = GET_SWZ(swizzle, 0); + if (src == RC_PAIR_PRESUB_SRC) { + return R300_ALU_ARGA_SRCP_X + swz; + } + if (swz < 3) + return swz + 3*src; + + switch(swz) { + case RC_SWIZZLE_W: return R300_ALU_ARGA_SRC0A + src; + case RC_SWIZZLE_ONE: return R300_ALU_ARGA_ONE; + case RC_SWIZZLE_ZERO: return R300_ALU_ARGA_ZERO; + case RC_SWIZZLE_HALF: return R300_ALU_ARGA_HALF; + default: return R300_ALU_ARGA_ONE; + } +} diff --git a/src/gallium/drivers/r300/compiler/r300_fragprog_swizzle.h b/src/gallium/drivers/r300/compiler/r300_fragprog_swizzle.h new file mode 100644 index 00000000000..f2635be140d --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r300_fragprog_swizzle.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __R300_FRAGPROG_SWIZZLE_H_ +#define __R300_FRAGPROG_SWIZZLE_H_ + +#include "radeon_swizzle.h" + +extern struct rc_swizzle_caps r300_swizzle_caps; + +unsigned int r300FPTranslateRGBSwizzle(unsigned int src, unsigned int swizzle); +unsigned int r300FPTranslateAlphaSwizzle(unsigned int src, unsigned int swizzle); +int r300_swizzle_is_native_basic(unsigned int swizzle); + +#endif /* __R300_FRAGPROG_SWIZZLE_H_ */ diff --git a/src/gallium/drivers/r300/compiler/r3xx_fragprog.c b/src/gallium/drivers/r300/compiler/r3xx_fragprog.c new file mode 100644 index 00000000000..bb6c010e8e3 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r3xx_fragprog.c @@ -0,0 +1,172 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "radeon_compiler.h" + +#include <stdio.h> + +#include "radeon_compiler_util.h" +#include "radeon_dataflow.h" +#include "radeon_emulate_branches.h" +#include "radeon_emulate_loops.h" +#include "radeon_program_alu.h" +#include "radeon_program_tex.h" +#include "radeon_rename_regs.h" +#include "radeon_remove_constants.h" +#include "r300_fragprog.h" +#include "r300_fragprog_swizzle.h" +#include "r500_fragprog.h" + + +static void dataflow_outputs_mark_use(void * userdata, void * data, + void (*callback)(void *, unsigned int, unsigned int)) +{ + struct r300_fragment_program_compiler * c = userdata; + callback(data, c->OutputColor[0], RC_MASK_XYZW); + callback(data, c->OutputColor[1], RC_MASK_XYZW); + callback(data, c->OutputColor[2], RC_MASK_XYZW); + callback(data, c->OutputColor[3], RC_MASK_XYZW); + callback(data, c->OutputDepth, RC_MASK_W); +} + +static void rc_rewrite_depth_out(struct radeon_compiler *cc, void *user) +{ + struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)cc; + struct rc_instruction *rci; + + for (rci = c->Base.Program.Instructions.Next; rci != &c->Base.Program.Instructions; rci = rci->Next) { + struct rc_sub_instruction * inst = &rci->U.I; + unsigned i; + const struct rc_opcode_info *info = rc_get_opcode_info(inst->Opcode); + + if (inst->DstReg.File != RC_FILE_OUTPUT || inst->DstReg.Index != c->OutputDepth) + continue; + + if (inst->DstReg.WriteMask & RC_MASK_Z) { + inst->DstReg.WriteMask = RC_MASK_W; + } else { + inst->DstReg.WriteMask = 0; + continue; + } + + if (!info->IsComponentwise) { + continue; + } + + for (i = 0; i < info->NumSrcRegs; i++) { + inst->SrcReg[i] = lmul_swizzle(RC_SWIZZLE_ZZZZ, inst->SrcReg[i]); + } + } +} + +static int radeon_saturate_output( + struct radeon_compiler * c, + struct rc_instruction * inst, + void* data) +{ + const struct rc_opcode_info *info = rc_get_opcode_info(inst->U.I.Opcode); + + if (!info->HasDstReg || inst->U.I.DstReg.File != RC_FILE_OUTPUT) + return 0; + + inst->U.I.SaturateMode = RC_SATURATE_ZERO_ONE; + return 1; +} + +void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c) +{ + int is_r500 = c->Base.is_r500; + int opt = !c->Base.disable_optimizations; + int sat_out = c->state.frag_clamp; + + /* Lists of instruction transformations. */ + struct radeon_program_transformation saturate_output[] = { + { &radeon_saturate_output, c }, + { 0, 0 } + }; + + struct radeon_program_transformation rewrite_tex[] = { + { &radeonTransformTEX, c }, + { 0, 0 } + }; + + struct radeon_program_transformation rewrite_if[] = { + { &r500_transform_IF, 0 }, + {0, 0} + }; + + struct radeon_program_transformation native_rewrite_r500[] = { + { &radeonTransformALU, 0 }, + { &radeonTransformDeriv, 0 }, + { &radeonTransformTrigScale, 0 }, + { 0, 0 } + }; + + struct radeon_program_transformation native_rewrite_r300[] = { + { &radeonTransformALU, 0 }, + { &r300_transform_trig_simple, 0 }, + { 0, 0 } + }; + + /* List of compiler passes. */ + struct radeon_compiler_pass fs_list[] = { + /* NAME DUMP PREDICATE FUNCTION PARAM */ + {"rewrite depth out", 1, 1, rc_rewrite_depth_out, NULL}, + /* This transformation needs to be done before any of the IF + * instructions are modified. */ + {"transform KILP", 1, 1, rc_transform_KILP, NULL}, + {"unroll loops", 1, is_r500, rc_unroll_loops, NULL}, + {"transform loops", 1, !is_r500, rc_transform_loops, NULL}, + {"emulate branches", 1, !is_r500, rc_emulate_branches, NULL}, + {"saturate output writes", 1, sat_out, rc_local_transform, saturate_output}, + {"transform TEX", 1, 1, rc_local_transform, rewrite_tex}, + {"transform IF", 1, is_r500, rc_local_transform, rewrite_if}, + {"native rewrite", 1, is_r500, rc_local_transform, native_rewrite_r500}, + {"native rewrite", 1, !is_r500, rc_local_transform, native_rewrite_r300}, + {"deadcode", 1, opt, rc_dataflow_deadcode, dataflow_outputs_mark_use}, + {"emulate loops", 1, !is_r500, rc_emulate_loops, NULL}, + {"dataflow optimize", 1, opt, rc_optimize, NULL}, + {"dataflow swizzles", 1, 1, rc_dataflow_swizzles, NULL}, + {"dead constants", 1, 1, rc_remove_unused_constants, &c->code->constants_remap_table}, + /* This pass makes it easier for the scheduler to group TEX + * instructions and reduces the chances of creating too + * many texture indirections.*/ + {"register rename", 1, !is_r500, rc_rename_regs, NULL}, + {"pair translate", 1, 1, rc_pair_translate, NULL}, + {"pair scheduling", 1, 1, rc_pair_schedule, NULL}, + {"dead sources", 1, 1, rc_pair_remove_dead_sources, NULL}, + {"register allocation", 1, 1, rc_pair_regalloc, &opt}, + {"final code validation", 0, 1, rc_validate_final_shader, NULL}, + {"machine code generation", 0, is_r500, r500BuildFragmentProgramHwCode, NULL}, + {"machine code generation", 0, !is_r500, r300BuildFragmentProgramHwCode, NULL}, + {"dump machine code", 0, is_r500 && (c->Base.Debug & RC_DBG_LOG), r500FragmentProgramDump, NULL}, + {"dump machine code", 0, !is_r500 && (c->Base.Debug & RC_DBG_LOG), r300FragmentProgramDump, NULL}, + {NULL, 0, 0, NULL, NULL} + }; + + c->Base.type = RC_FRAGMENT_PROGRAM; + c->Base.SwizzleCaps = c->Base.is_r500 ? &r500_swizzle_caps : &r300_swizzle_caps; + + rc_run_compiler(&c->Base, fs_list); + + rc_constants_copy(&c->code->constants, &c->Base.Program.Constants); +} diff --git a/src/gallium/drivers/r300/compiler/r3xx_vertprog.c b/src/gallium/drivers/r300/compiler/r3xx_vertprog.c new file mode 100644 index 00000000000..654f9a070d5 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r3xx_vertprog.c @@ -0,0 +1,1045 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "radeon_compiler.h" + +#include <stdio.h> + +#include "../r300_reg.h" + +#include "radeon_compiler_util.h" +#include "radeon_dataflow.h" +#include "radeon_program_alu.h" +#include "radeon_swizzle.h" +#include "radeon_emulate_branches.h" +#include "radeon_emulate_loops.h" +#include "radeon_remove_constants.h" + +struct loop { + int BgnLoop; + +}; + +/* + * Take an already-setup and valid source then swizzle it appropriately to + * obtain a constant ZERO or ONE source. + */ +#define __CONST(x, y) \ + (PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[x]), \ + t_swizzle(y), \ + t_swizzle(y), \ + t_swizzle(y), \ + t_swizzle(y), \ + t_src_class(vpi->SrcReg[x].File), \ + RC_MASK_NONE) | (vpi->SrcReg[x].RelAddr << 4)) + + +static unsigned long t_dst_mask(unsigned int mask) +{ + /* RC_MASK_* is equivalent to VSF_FLAG_* */ + return mask & RC_MASK_XYZW; +} + +static unsigned long t_dst_class(rc_register_file file) +{ + switch (file) { + default: + fprintf(stderr, "%s: Bad register file %i\n", __FUNCTION__, file); + /* fall-through */ + case RC_FILE_TEMPORARY: + return PVS_DST_REG_TEMPORARY; + case RC_FILE_OUTPUT: + return PVS_DST_REG_OUT; + case RC_FILE_ADDRESS: + return PVS_DST_REG_A0; + } +} + +static unsigned long t_dst_index(struct r300_vertex_program_code *vp, + struct rc_dst_register *dst) +{ + if (dst->File == RC_FILE_OUTPUT) + return vp->outputs[dst->Index]; + + return dst->Index; +} + +static unsigned long t_src_class(rc_register_file file) +{ + switch (file) { + default: + fprintf(stderr, "%s: Bad register file %i\n", __FUNCTION__, file); + /* fall-through */ + case RC_FILE_NONE: + case RC_FILE_TEMPORARY: + return PVS_SRC_REG_TEMPORARY; + case RC_FILE_INPUT: + return PVS_SRC_REG_INPUT; + case RC_FILE_CONSTANT: + return PVS_SRC_REG_CONSTANT; + } +} + +static int t_src_conflict(struct rc_src_register a, struct rc_src_register b) +{ + unsigned long aclass = t_src_class(a.File); + unsigned long bclass = t_src_class(b.File); + + if (aclass != bclass) + return 0; + if (aclass == PVS_SRC_REG_TEMPORARY) + return 0; + + if (a.RelAddr || b.RelAddr) + return 1; + if (a.Index != b.Index) + return 1; + + return 0; +} + +static inline unsigned long t_swizzle(unsigned int swizzle) +{ + /* this is in fact a NOP as the Mesa RC_SWIZZLE_* are all identical to VSF_IN_COMPONENT_* */ + return swizzle; +} + +static unsigned long t_src_index(struct r300_vertex_program_code *vp, + struct rc_src_register *src) +{ + if (src->File == RC_FILE_INPUT) { + assert(vp->inputs[src->Index] != -1); + return vp->inputs[src->Index]; + } else { + if (src->Index < 0) { + fprintf(stderr, + "negative offsets for indirect addressing do not work.\n"); + return 0; + } + return src->Index; + } +} + +/* these two functions should probably be merged... */ + +static unsigned long t_src(struct r300_vertex_program_code *vp, + struct rc_src_register *src) +{ + /* src->Negate uses the RC_MASK_ flags from program_instruction.h, + * which equal our VSF_FLAGS_ values, so it's safe to just pass it here. + */ + return PVS_SRC_OPERAND(t_src_index(vp, src), + t_swizzle(GET_SWZ(src->Swizzle, 0)), + t_swizzle(GET_SWZ(src->Swizzle, 1)), + t_swizzle(GET_SWZ(src->Swizzle, 2)), + t_swizzle(GET_SWZ(src->Swizzle, 3)), + t_src_class(src->File), + src->Negate) | + (src->RelAddr << 4) | (src->Abs << 3); +} + +static unsigned long t_src_scalar(struct r300_vertex_program_code *vp, + struct rc_src_register *src) +{ + /* src->Negate uses the RC_MASK_ flags from program_instruction.h, + * which equal our VSF_FLAGS_ values, so it's safe to just pass it here. + */ + return PVS_SRC_OPERAND(t_src_index(vp, src), + t_swizzle(GET_SWZ(src->Swizzle, 0)), + t_swizzle(GET_SWZ(src->Swizzle, 0)), + t_swizzle(GET_SWZ(src->Swizzle, 0)), + t_swizzle(GET_SWZ(src->Swizzle, 0)), + t_src_class(src->File), + src->Negate ? RC_MASK_XYZW : RC_MASK_NONE) | + (src->RelAddr << 4) | (src->Abs << 3); +} + +static int valid_dst(struct r300_vertex_program_code *vp, + struct rc_dst_register *dst) +{ + if (dst->File == RC_FILE_OUTPUT && vp->outputs[dst->Index] == -1) { + return 0; + } else if (dst->File == RC_FILE_ADDRESS) { + assert(dst->Index == 0); + } + + return 1; +} + +static void ei_vector1(struct r300_vertex_program_code *vp, + unsigned int hw_opcode, + struct rc_sub_instruction *vpi, + unsigned int * inst) +{ + inst[0] = PVS_OP_DST_OPERAND(hw_opcode, + 0, + 0, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + inst[1] = t_src(vp, &vpi->SrcReg[0]); + inst[2] = __CONST(0, RC_SWIZZLE_ZERO); + inst[3] = __CONST(0, RC_SWIZZLE_ZERO); +} + +static void ei_vector2(struct r300_vertex_program_code *vp, + unsigned int hw_opcode, + struct rc_sub_instruction *vpi, + unsigned int * inst) +{ + inst[0] = PVS_OP_DST_OPERAND(hw_opcode, + 0, + 0, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + inst[1] = t_src(vp, &vpi->SrcReg[0]); + inst[2] = t_src(vp, &vpi->SrcReg[1]); + inst[3] = __CONST(1, RC_SWIZZLE_ZERO); +} + +static void ei_math1(struct r300_vertex_program_code *vp, + unsigned int hw_opcode, + struct rc_sub_instruction *vpi, + unsigned int * inst) +{ + inst[0] = PVS_OP_DST_OPERAND(hw_opcode, + 1, + 0, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]); + inst[2] = __CONST(0, RC_SWIZZLE_ZERO); + inst[3] = __CONST(0, RC_SWIZZLE_ZERO); +} + +static void ei_lit(struct r300_vertex_program_code *vp, + struct rc_sub_instruction *vpi, + unsigned int * inst) +{ + //LIT TMP 1.Y Z TMP 1{} {X W Z Y} TMP 1{} {Y W Z X} TMP 1{} {Y X Z W} + + inst[0] = PVS_OP_DST_OPERAND(ME_LIGHT_COEFF_DX, + 1, + 0, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + /* NOTE: Users swizzling might not work. */ + inst[1] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X + t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W + PVS_SRC_SELECT_FORCE_0, // Z + t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y + t_src_class(vpi->SrcReg[0].File), + vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) | + (vpi->SrcReg[0].RelAddr << 4); + inst[2] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y + t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W + PVS_SRC_SELECT_FORCE_0, // Z + t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X + t_src_class(vpi->SrcReg[0].File), + vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) | + (vpi->SrcReg[0].RelAddr << 4); + inst[3] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)), // Y + t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)), // X + PVS_SRC_SELECT_FORCE_0, // Z + t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)), // W + t_src_class(vpi->SrcReg[0].File), + vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) | + (vpi->SrcReg[0].RelAddr << 4); +} + +static void ei_mad(struct r300_vertex_program_code *vp, + struct rc_sub_instruction *vpi, + unsigned int * inst) +{ + unsigned int i; + /* Remarks about hardware limitations of MAD + * (please preserve this comment, as this information is _NOT_ + * in the documentation provided by AMD). + * + * As described in the documentation, MAD with three unique temporary + * source registers requires the use of the macro version. + * + * However (and this is not mentioned in the documentation), apparently + * the macro version is _NOT_ a full superset of the normal version. + * In particular, the macro version does not always work when relative + * addressing is used in the source operands. + * + * This limitation caused incorrect rendering in Sauerbraten's OpenGL + * assembly shader path when using medium quality animations + * (i.e. animations with matrix blending instead of quaternion blending). + * + * Unfortunately, I (nha) have been unable to extract a Piglit regression + * test for this issue - for some reason, it is possible to have vertex + * programs whose prefix is *exactly* the same as the prefix of the + * offending program in Sauerbraten up to the offending instruction + * without causing any trouble. + * + * Bottom line: Only use the macro version only when really necessary; + * according to AMD docs, this should improve performance by one clock + * as a nice side bonus. + */ + if (vpi->SrcReg[0].File == RC_FILE_TEMPORARY && + vpi->SrcReg[1].File == RC_FILE_TEMPORARY && + vpi->SrcReg[2].File == RC_FILE_TEMPORARY && + vpi->SrcReg[0].Index != vpi->SrcReg[1].Index && + vpi->SrcReg[0].Index != vpi->SrcReg[2].Index && + vpi->SrcReg[1].Index != vpi->SrcReg[2].Index) { + inst[0] = PVS_OP_DST_OPERAND(PVS_MACRO_OP_2CLK_MADD, + 0, + 1, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + } else { + inst[0] = PVS_OP_DST_OPERAND(VE_MULTIPLY_ADD, + 0, + 0, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + + /* Arguments with constant swizzles still count as a unique + * temporary, so we should make sure these arguments share a + * register index with one of the other arguments. */ + for (i = 0; i < 3; i++) { + unsigned int j; + if (vpi->SrcReg[i].File != RC_FILE_NONE) + continue; + + for (j = 0; j < 3; j++) { + if (i != j) { + vpi->SrcReg[i].Index = + vpi->SrcReg[j].Index; + break; + } + } + } + } + inst[1] = t_src(vp, &vpi->SrcReg[0]); + inst[2] = t_src(vp, &vpi->SrcReg[1]); + inst[3] = t_src(vp, &vpi->SrcReg[2]); +} + +static void ei_pow(struct r300_vertex_program_code *vp, + struct rc_sub_instruction *vpi, + unsigned int * inst) +{ + inst[0] = PVS_OP_DST_OPERAND(ME_POWER_FUNC_FF, + 1, + 0, + t_dst_index(vp, &vpi->DstReg), + t_dst_mask(vpi->DstReg.WriteMask), + t_dst_class(vpi->DstReg.File)); + inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]); + inst[2] = __CONST(0, RC_SWIZZLE_ZERO); + inst[3] = t_src_scalar(vp, &vpi->SrcReg[1]); +} + +static void mark_write(void * userdata, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask) +{ + unsigned int * writemasks = userdata; + + if (file != RC_FILE_TEMPORARY) + return; + + if (index >= R300_VS_MAX_TEMPS) + return; + + writemasks[index] |= mask; +} + +static unsigned long t_pred_src(struct r300_vertex_program_compiler * compiler) +{ + return PVS_SRC_OPERAND(compiler->PredicateIndex, + t_swizzle(RC_SWIZZLE_ZERO), + t_swizzle(RC_SWIZZLE_ZERO), + t_swizzle(RC_SWIZZLE_ZERO), + t_swizzle(RC_SWIZZLE_W), + t_src_class(RC_FILE_TEMPORARY), + 0); +} + +static unsigned long t_pred_dst(struct r300_vertex_program_compiler * compiler, + unsigned int hw_opcode, int is_math) +{ + return PVS_OP_DST_OPERAND(hw_opcode, + is_math, + 0, + compiler->PredicateIndex, + RC_MASK_W, + t_dst_class(RC_FILE_TEMPORARY)); + +} + +static void ei_if(struct r300_vertex_program_compiler * compiler, + struct rc_instruction *rci, + unsigned int * inst, + unsigned int branch_depth) +{ + unsigned int predicate_opcode; + int is_math = 0; + + if (!compiler->Base.is_r500) { + rc_error(&compiler->Base,"Opcode IF not supported\n"); + return; + } + + /* Reserve a temporary to use as our predicate stack counter, if we + * don't already have one. */ + if (!compiler->PredicateMask) { + unsigned int writemasks[RC_REGISTER_MAX_INDEX]; + struct rc_instruction * inst; + unsigned int i; + memset(writemasks, 0, sizeof(writemasks)); + for(inst = compiler->Base.Program.Instructions.Next; + inst != &compiler->Base.Program.Instructions; + inst = inst->Next) { + rc_for_all_writes_mask(inst, mark_write, writemasks); + } + for(i = 0; i < compiler->Base.max_temp_regs; i++) { + unsigned int mask = ~writemasks[i] & RC_MASK_XYZW; + /* Only the W component can be used fo the predicate + * stack counter. */ + if (mask & RC_MASK_W) { + compiler->PredicateMask = RC_MASK_W; + compiler->PredicateIndex = i; + break; + } + } + if (i == compiler->Base.max_temp_regs) { + rc_error(&compiler->Base, "No free temporary to use for" + " predicate stack counter.\n"); + return; + } + } + predicate_opcode = + branch_depth ? VE_PRED_SET_NEQ_PUSH : ME_PRED_SET_NEQ; + + rci->U.I.SrcReg[0].Swizzle = RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(rci->U.I.SrcReg[0].Swizzle,0)); + if (branch_depth == 0) { + is_math = 1; + predicate_opcode = ME_PRED_SET_NEQ; + inst[1] = t_src(compiler->code, &rci->U.I.SrcReg[0]); + inst[2] = 0; + } else { + predicate_opcode = VE_PRED_SET_NEQ_PUSH; + inst[1] = t_pred_src(compiler); + inst[2] = t_src(compiler->code, &rci->U.I.SrcReg[0]); + } + + inst[0] = t_pred_dst(compiler, predicate_opcode, is_math); + inst[3] = 0; + +} + +static void ei_else(struct r300_vertex_program_compiler * compiler, + unsigned int * inst) +{ + if (!compiler->Base.is_r500) { + rc_error(&compiler->Base,"Opcode ELSE not supported\n"); + return; + } + inst[0] = t_pred_dst(compiler, ME_PRED_SET_INV, 1); + inst[1] = t_pred_src(compiler); + inst[2] = 0; + inst[3] = 0; +} + +static void ei_endif(struct r300_vertex_program_compiler *compiler, + unsigned int * inst) +{ + if (!compiler->Base.is_r500) { + rc_error(&compiler->Base,"Opcode ENDIF not supported\n"); + return; + } + inst[0] = t_pred_dst(compiler, ME_PRED_SET_POP, 1); + inst[1] = t_pred_src(compiler); + inst[2] = 0; + inst[3] = 0; +} + +static void translate_vertex_program(struct radeon_compiler *c, void *user) +{ + struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c; + struct rc_instruction *rci; + + struct loop * loops = NULL; + int current_loop_depth = 0; + int loops_reserved = 0; + + unsigned int branch_depth = 0; + + compiler->code->pos_end = 0; /* Not supported yet */ + compiler->code->length = 0; + compiler->code->num_temporaries = 0; + + compiler->SetHwInputOutput(compiler); + + for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) { + struct rc_sub_instruction *vpi = &rci->U.I; + unsigned int *inst = compiler->code->body.d + compiler->code->length; + const struct rc_opcode_info *info = rc_get_opcode_info(vpi->Opcode); + + /* Skip instructions writing to non-existing destination */ + if (!valid_dst(compiler->code, &vpi->DstReg)) + continue; + + if (info->HasDstReg) { + /* Neither is Saturate. */ + if (vpi->SaturateMode != RC_SATURATE_NONE) { + rc_error(&compiler->Base, "Vertex program does not support the Saturate " + "modifier (yet).\n"); + } + } + + if (compiler->code->length >= c->max_alu_insts * 4) { + rc_error(&compiler->Base, "Vertex program has too many instructions\n"); + return; + } + + assert(compiler->Base.is_r500 || + (vpi->Opcode != RC_OPCODE_SEQ && + vpi->Opcode != RC_OPCODE_SNE)); + + switch (vpi->Opcode) { + case RC_OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break; + case RC_OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break; + case RC_OPCODE_COS: ei_math1(compiler->code, ME_COS, vpi, inst); break; + case RC_OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break; + case RC_OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break; + case RC_OPCODE_ELSE: ei_else(compiler, inst); break; + case RC_OPCODE_ENDIF: ei_endif(compiler, inst); branch_depth--; break; + case RC_OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break; + case RC_OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break; + case RC_OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break; + case RC_OPCODE_IF: ei_if(compiler, rci, inst, branch_depth); branch_depth++; break; + case RC_OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break; + case RC_OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break; + case RC_OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break; + case RC_OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break; + case RC_OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break; + case RC_OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break; + case RC_OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break; + case RC_OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break; + case RC_OPCODE_POW: ei_pow(compiler->code, vpi, inst); break; + case RC_OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break; + case RC_OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break; + case RC_OPCODE_SEQ: ei_vector2(compiler->code, VE_SET_EQUAL, vpi, inst); break; + case RC_OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break; + case RC_OPCODE_SIN: ei_math1(compiler->code, ME_SIN, vpi, inst); break; + case RC_OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break; + case RC_OPCODE_SNE: ei_vector2(compiler->code, VE_SET_NOT_EQUAL, vpi, inst); break; + case RC_OPCODE_BGNLOOP: + { + struct loop * l; + + if ((!compiler->Base.is_r500 + && loops_reserved >= R300_VS_MAX_LOOP_DEPTH) + || loops_reserved >= R500_VS_MAX_FC_DEPTH) { + rc_error(&compiler->Base, + "Loops are nested too deep."); + return; + } + memory_pool_array_reserve(&compiler->Base.Pool, + struct loop, loops, current_loop_depth, + loops_reserved, 1); + l = &loops[current_loop_depth++]; + memset(l , 0, sizeof(struct loop)); + l->BgnLoop = (compiler->code->length / 4); + continue; + } + case RC_OPCODE_ENDLOOP: + { + struct loop * l; + unsigned int act_addr; + unsigned int last_addr; + unsigned int ret_addr; + + assert(loops); + l = &loops[current_loop_depth - 1]; + act_addr = l->BgnLoop - 1; + last_addr = (compiler->code->length / 4) - 1; + ret_addr = l->BgnLoop; + + if (loops_reserved >= R300_VS_MAX_FC_OPS) { + rc_error(&compiler->Base, + "Too many flow control instructions."); + return; + } + if (compiler->Base.is_r500) { + compiler->code->fc_op_addrs.r500 + [compiler->code->num_fc_ops].lw = + R500_PVS_FC_ACT_ADRS(act_addr) + | R500_PVS_FC_LOOP_CNT_JMP_INST(0xffff) + ; + compiler->code->fc_op_addrs.r500 + [compiler->code->num_fc_ops].uw = + R500_PVS_FC_LAST_INST(last_addr) + | R500_PVS_FC_RTN_INST(ret_addr) + ; + } else { + compiler->code->fc_op_addrs.r300 + [compiler->code->num_fc_ops] = + R300_PVS_FC_ACT_ADRS(act_addr) + | R300_PVS_FC_LOOP_CNT_JMP_INST(0xff) + | R300_PVS_FC_LAST_INST(last_addr) + | R300_PVS_FC_RTN_INST(ret_addr) + ; + } + compiler->code->fc_loop_index[compiler->code->num_fc_ops] = + R300_PVS_FC_LOOP_INIT_VAL(0x0) + | R300_PVS_FC_LOOP_STEP_VAL(0x1) + ; + compiler->code->fc_ops |= R300_VAP_PVS_FC_OPC_LOOP( + compiler->code->num_fc_ops); + compiler->code->num_fc_ops++; + current_loop_depth--; + continue; + } + + default: + rc_error(&compiler->Base, "Unknown opcode %s\n", info->Name); + return; + } + + /* Non-flow control instructions that are inside an if statement + * need to pay attention to the predicate bit. */ + if (branch_depth + && vpi->Opcode != RC_OPCODE_IF + && vpi->Opcode != RC_OPCODE_ELSE + && vpi->Opcode != RC_OPCODE_ENDIF) { + + inst[0] |= (PVS_DST_PRED_ENABLE_MASK + << PVS_DST_PRED_ENABLE_SHIFT); + inst[0] |= (PVS_DST_PRED_SENSE_MASK + << PVS_DST_PRED_SENSE_SHIFT); + } + + /* Update the number of temporaries. */ + if (info->HasDstReg && vpi->DstReg.File == RC_FILE_TEMPORARY && + vpi->DstReg.Index >= compiler->code->num_temporaries) + compiler->code->num_temporaries = vpi->DstReg.Index + 1; + + for (unsigned i = 0; i < info->NumSrcRegs; i++) + if (vpi->SrcReg[i].File == RC_FILE_TEMPORARY && + vpi->SrcReg[i].Index >= compiler->code->num_temporaries) + compiler->code->num_temporaries = vpi->SrcReg[i].Index + 1; + + if (compiler->PredicateMask) + if (compiler->PredicateIndex >= compiler->code->num_temporaries) + compiler->code->num_temporaries = compiler->PredicateIndex + 1; + + if (compiler->code->num_temporaries > compiler->Base.max_temp_regs) { + rc_error(&compiler->Base, "Too many temporaries.\n"); + return; + } + + compiler->code->length += 4; + + if (compiler->Base.Error) + return; + } +} + +struct temporary_allocation { + unsigned int Allocated:1; + unsigned int HwTemp:15; + struct rc_instruction * LastRead; +}; + +static void allocate_temporary_registers(struct radeon_compiler *c, void *user) +{ + struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c; + struct rc_instruction *inst; + struct rc_instruction *end_loop = NULL; + unsigned int num_orig_temps = 0; + char hwtemps[RC_REGISTER_MAX_INDEX]; + struct temporary_allocation * ta; + unsigned int i, j; + + memset(hwtemps, 0, sizeof(hwtemps)); + + rc_recompute_ips(c); + + /* Pass 1: Count original temporaries. */ + for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + for (i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) { + if (inst->U.I.SrcReg[i].Index >= num_orig_temps) + num_orig_temps = inst->U.I.SrcReg[i].Index + 1; + } + } + + if (opcode->HasDstReg) { + if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) { + if (inst->U.I.DstReg.Index >= num_orig_temps) + num_orig_temps = inst->U.I.DstReg.Index + 1; + } + } + } + + ta = (struct temporary_allocation*)memory_pool_malloc(&compiler->Base.Pool, + sizeof(struct temporary_allocation) * num_orig_temps); + memset(ta, 0, sizeof(struct temporary_allocation) * num_orig_temps); + + /* Pass 2: Determine original temporary lifetimes */ + for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + /* Instructions inside of loops need to use the ENDLOOP + * instruction as their LastRead. */ + if (!end_loop && inst->U.I.Opcode == RC_OPCODE_BGNLOOP) { + int endloops = 1; + struct rc_instruction * ptr; + for(ptr = inst->Next; + ptr != &compiler->Base.Program.Instructions; + ptr = ptr->Next){ + if (ptr->U.I.Opcode == RC_OPCODE_BGNLOOP) { + endloops++; + } else if (ptr->U.I.Opcode == RC_OPCODE_ENDLOOP) { + endloops--; + if (endloops <= 0) { + end_loop = ptr; + break; + } + } + } + } + + if (inst == end_loop) { + end_loop = NULL; + continue; + } + + for (i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) { + ta[inst->U.I.SrcReg[i].Index].LastRead = end_loop ? end_loop : inst; + } + } + } + + /* Pass 3: Register allocation */ + for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + for (i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) { + unsigned int orig = inst->U.I.SrcReg[i].Index; + inst->U.I.SrcReg[i].Index = ta[orig].HwTemp; + + if (ta[orig].Allocated && inst == ta[orig].LastRead) + hwtemps[ta[orig].HwTemp] = 0; + } + } + + if (opcode->HasDstReg) { + if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) { + unsigned int orig = inst->U.I.DstReg.Index; + + if (!ta[orig].Allocated) { + for(j = 0; j < c->max_temp_regs; ++j) { + if (!hwtemps[j]) + break; + } + ta[orig].Allocated = 1; + ta[orig].HwTemp = j; + hwtemps[ta[orig].HwTemp] = 1; + } + + inst->U.I.DstReg.Index = ta[orig].HwTemp; + } + } + } +} + +/** + * R3xx-R4xx vertex engine does not support the Absolute source operand modifier + * and the Saturate opcode modifier. Only Absolute is currently transformed. + */ +static int transform_nonnative_modifiers( + struct radeon_compiler *c, + struct rc_instruction *inst, + void* unused) +{ + const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned i; + + /* Transform ABS(a) to MAX(a, -a). */ + for (i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].Abs) { + struct rc_instruction *new_inst; + unsigned temp; + + inst->U.I.SrcReg[i].Abs = 0; + + temp = rc_find_free_temporary(c); + + new_inst = rc_insert_new_instruction(c, inst->Prev); + new_inst->U.I.Opcode = RC_OPCODE_MAX; + new_inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + new_inst->U.I.DstReg.Index = temp; + new_inst->U.I.SrcReg[0] = inst->U.I.SrcReg[i]; + new_inst->U.I.SrcReg[1] = inst->U.I.SrcReg[i]; + new_inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; + + memset(&inst->U.I.SrcReg[i], 0, sizeof(inst->U.I.SrcReg[i])); + inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[i].Index = temp; + inst->U.I.SrcReg[i].Swizzle = RC_SWIZZLE_XYZW; + } + } + return 1; +} + +/** + * Vertex engine cannot read two inputs or two constants at the same time. + * Introduce intermediate MOVs to temporary registers to account for this. + */ +static int transform_source_conflicts( + struct radeon_compiler *c, + struct rc_instruction* inst, + void* unused) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (opcode->NumSrcRegs == 3) { + if (t_src_conflict(inst->U.I.SrcReg[1], inst->U.I.SrcReg[2]) + || t_src_conflict(inst->U.I.SrcReg[0], inst->U.I.SrcReg[2])) { + int tmpreg = rc_find_free_temporary(c); + struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = tmpreg; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[2]; + + reset_srcreg(&inst->U.I.SrcReg[2]); + inst->U.I.SrcReg[2].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[2].Index = tmpreg; + } + } + + if (opcode->NumSrcRegs >= 2) { + if (t_src_conflict(inst->U.I.SrcReg[1], inst->U.I.SrcReg[0])) { + int tmpreg = rc_find_free_temporary(c); + struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = tmpreg; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[1]; + + reset_srcreg(&inst->U.I.SrcReg[1]); + inst->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[1].Index = tmpreg; + } + } + + return 1; +} + +static void rc_vs_add_artificial_outputs(struct radeon_compiler *c, void *user) +{ + struct r300_vertex_program_compiler * compiler = (struct r300_vertex_program_compiler*)c; + int i; + + for(i = 0; i < 32; ++i) { + if ((compiler->RequiredOutputs & (1 << i)) && + !(compiler->Base.Program.OutputsWritten & (1 << i))) { + struct rc_instruction * inst = rc_insert_new_instruction(&compiler->Base, compiler->Base.Program.Instructions.Prev); + inst->U.I.Opcode = RC_OPCODE_MOV; + + inst->U.I.DstReg.File = RC_FILE_OUTPUT; + inst->U.I.DstReg.Index = i; + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + + inst->U.I.SrcReg[0].File = RC_FILE_CONSTANT; + inst->U.I.SrcReg[0].Index = 0; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + + compiler->Base.Program.OutputsWritten |= 1 << i; + } + } +} + +static void dataflow_outputs_mark_used(void * userdata, void * data, + void (*callback)(void *, unsigned int, unsigned int)) +{ + struct r300_vertex_program_compiler * c = userdata; + int i; + + for(i = 0; i < 32; ++i) { + if (c->RequiredOutputs & (1 << i)) + callback(data, i, RC_MASK_XYZW); + } +} + +static int swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) +{ + (void) opcode; + (void) reg; + + return 1; +} + +static void transform_negative_addressing(struct r300_vertex_program_compiler *c, + struct rc_instruction *arl, + struct rc_instruction *end, + int min_offset) +{ + struct rc_instruction *inst, *add; + unsigned const_swizzle; + + /* Transform ARL */ + add = rc_insert_new_instruction(&c->Base, arl->Prev); + add->U.I.Opcode = RC_OPCODE_ADD; + add->U.I.DstReg.File = RC_FILE_TEMPORARY; + add->U.I.DstReg.Index = rc_find_free_temporary(&c->Base); + add->U.I.DstReg.WriteMask = RC_MASK_X; + add->U.I.SrcReg[0] = arl->U.I.SrcReg[0]; + add->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + add->U.I.SrcReg[1].Index = rc_constants_add_immediate_scalar(&c->Base.Program.Constants, + min_offset, &const_swizzle); + add->U.I.SrcReg[1].Swizzle = const_swizzle; + + arl->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + arl->U.I.SrcReg[0].Index = add->U.I.DstReg.Index; + arl->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XXXX; + + /* Rewrite offsets up to and excluding inst. */ + for (inst = arl->Next; inst != end; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) + if (inst->U.I.SrcReg[i].RelAddr) + inst->U.I.SrcReg[i].Index -= min_offset; + } +} + +static void rc_emulate_negative_addressing(struct radeon_compiler *compiler, void *user) +{ + struct r300_vertex_program_compiler * c = (struct r300_vertex_program_compiler*)compiler; + struct rc_instruction *inst, *lastARL = NULL; + int min_offset = 0; + + for (inst = c->Base.Program.Instructions.Next; inst != &c->Base.Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (inst->U.I.Opcode == RC_OPCODE_ARL) { + if (lastARL != NULL && min_offset < 0) + transform_negative_addressing(c, lastARL, inst, min_offset); + + lastARL = inst; + min_offset = 0; + continue; + } + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].RelAddr && + inst->U.I.SrcReg[i].Index < 0) { + /* ARL must precede any indirect addressing. */ + if (lastARL == NULL) { + rc_error(&c->Base, "Vertex shader: Found relative addressing without ARL."); + return; + } + + if (inst->U.I.SrcReg[i].Index < min_offset) + min_offset = inst->U.I.SrcReg[i].Index; + } + } + } + + if (lastARL != NULL && min_offset < 0) + transform_negative_addressing(c, lastARL, inst, min_offset); +} + +static struct rc_swizzle_caps r300_vertprog_swizzle_caps = { + .IsNative = &swizzle_is_native, + .Split = 0 /* should never be called */ +}; + +void r3xx_compile_vertex_program(struct r300_vertex_program_compiler *c) +{ + int is_r500 = c->Base.is_r500; + int opt = !c->Base.disable_optimizations; + + /* Lists of instruction transformations. */ + struct radeon_program_transformation alu_rewrite_r500[] = { + { &r300_transform_vertex_alu, 0 }, + { &r300_transform_trig_scale_vertex, 0 }, + { 0, 0 } + }; + + struct radeon_program_transformation alu_rewrite_r300[] = { + { &r300_transform_vertex_alu, 0 }, + { &r300_transform_trig_simple, 0 }, + { 0, 0 } + }; + + /* Note: These passes have to be done seperately from ALU rewrite, + * otherwise non-native ALU instructions with source conflits + * or non-native modifiers will not be treated properly. + */ + struct radeon_program_transformation emulate_modifiers[] = { + { &transform_nonnative_modifiers, 0 }, + { 0, 0 } + }; + + struct radeon_program_transformation resolve_src_conflicts[] = { + { &transform_source_conflicts, 0 }, + { 0, 0 } + }; + + /* List of compiler passes. */ + struct radeon_compiler_pass vs_list[] = { + /* NAME DUMP PREDICATE FUNCTION PARAM */ + {"add artificial outputs", 0, 1, rc_vs_add_artificial_outputs, NULL}, + {"transform loops", 1, 1, rc_transform_loops, NULL}, + {"emulate branches", 1, !is_r500, rc_emulate_branches, NULL}, + {"emulate negative addressing", 1, 1, rc_emulate_negative_addressing, NULL}, + {"native rewrite", 1, is_r500, rc_local_transform, alu_rewrite_r500}, + {"native rewrite", 1, !is_r500, rc_local_transform, alu_rewrite_r300}, + {"emulate modifiers", 1, !is_r500, rc_local_transform, emulate_modifiers}, + {"deadcode", 1, opt, rc_dataflow_deadcode, dataflow_outputs_mark_used}, + {"dataflow optimize", 1, opt, rc_optimize, NULL}, + /* This pass must be done after optimizations. */ + {"source conflict resolve", 1, 1, rc_local_transform, resolve_src_conflicts}, + {"register allocation", 1, opt, allocate_temporary_registers, NULL}, + {"dead constants", 1, 1, rc_remove_unused_constants, &c->code->constants_remap_table}, + {"final code validation", 0, 1, rc_validate_final_shader, NULL}, + {"machine code generation", 0, 1, translate_vertex_program, NULL}, + {"dump machine code", 0, c->Base.Debug & RC_DBG_LOG, r300_vertex_program_dump, NULL}, + {NULL, 0, 0, NULL, NULL} + }; + + c->Base.type = RC_VERTEX_PROGRAM; + c->Base.SwizzleCaps = &r300_vertprog_swizzle_caps; + + rc_run_compiler(&c->Base, vs_list); + + c->code->InputsRead = c->Base.Program.InputsRead; + c->code->OutputsWritten = c->Base.Program.OutputsWritten; + rc_constants_copy(&c->code->constants, &c->Base.Program.Constants); +} diff --git a/src/gallium/drivers/r300/compiler/r3xx_vertprog_dump.c b/src/gallium/drivers/r300/compiler/r3xx_vertprog_dump.c new file mode 100644 index 00000000000..2bc0a87eed8 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r3xx_vertprog_dump.c @@ -0,0 +1,207 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "radeon_compiler.h" +#include "radeon_code.h" +#include "../r300_reg.h" + +#include <stdio.h> + +static char* r300_vs_ve_ops[] = { + /* R300 vector ops */ + " VE_NO_OP", + " VE_DOT_PRODUCT", + " VE_MULTIPLY", + " VE_ADD", + " VE_MULTIPLY_ADD", + " VE_DISTANCE_FACTOR", + " VE_FRACTION", + " VE_MAXIMUM", + " VE_MINIMUM", + "VE_SET_GREATER_THAN_EQUAL", + " VE_SET_LESS_THAN", + " VE_MULTIPLYX2_ADD", + " VE_MULTIPLY_CLAMP", + " VE_FLT2FIX_DX", + " VE_FLT2FIX_DX_RND", + /* R500 vector ops */ + " VE_PRED_SET_EQ_PUSH", + " VE_PRED_SET_GT_PUSH", + " VE_PRED_SET_GTE_PUSH", + " VE_PRED_SET_NEQ_PUSH", + " VE_COND_WRITE_EQ", + " VE_COND_WRITE_GT", + " VE_COND_WRITE_GTE", + " VE_COND_WRITE_NEQ", + " VE_COND_MUX_EQ", + " VE_COND_MUX_GT", + " VE_COND_MUX_GTE", + " VE_SET_GREATER_THAN", + " VE_SET_EQUAL", + " VE_SET_NOT_EQUAL", + " (reserved)", + " (reserved)", + " (reserved)", +}; + +static char* r300_vs_me_ops[] = { + /* R300 math ops */ + " ME_NO_OP", + " ME_EXP_BASE2_DX", + " ME_LOG_BASE2_DX", + " ME_EXP_BASEE_FF", + " ME_LIGHT_COEFF_DX", + " ME_POWER_FUNC_FF", + " ME_RECIP_DX", + " ME_RECIP_FF", + " ME_RECIP_SQRT_DX", + " ME_RECIP_SQRT_FF", + " ME_MULTIPLY", + " ME_EXP_BASE2_FULL_DX", + " ME_LOG_BASE2_FULL_DX", + " ME_POWER_FUNC_FF_CLAMP_B", + "ME_POWER_FUNC_FF_CLAMP_B1", + "ME_POWER_FUNC_FF_CLAMP_01", + " ME_SIN", + " ME_COS", + /* R500 math ops */ + " ME_LOG_BASE2_IEEE", + " ME_RECIP_IEEE", + " ME_RECIP_SQRT_IEEE", + " ME_PRED_SET_EQ", + " ME_PRED_SET_GT", + " ME_PRED_SET_GTE", + " ME_PRED_SET_NEQ", + " ME_PRED_SET_CLR", + " ME_PRED_SET_INV", + " ME_PRED_SET_POP", + " ME_PRED_SET_RESTORE", + " (reserved)", + " (reserved)", + " (reserved)", +}; + +/* XXX refactor to avoid clashing symbols */ +static char* r300_vs_src_debug[] = { + "t", + "i", + "c", + "a", +}; + +static char* r300_vs_dst_debug[] = { + "t", + "a0", + "o", + "ox", + "a", + "i", + "u", + "u", +}; + +static char* r300_vs_swiz_debug[] = { + "X", + "Y", + "Z", + "W", + "0", + "1", + "U", + "U", +}; + + +static void r300_vs_op_dump(uint32_t op) +{ + fprintf(stderr, " dst: %d%s op: ", + (op >> 13) & 0x7f, r300_vs_dst_debug[(op >> 8) & 0x7]); + if ((op >> PVS_DST_PRED_ENABLE_SHIFT) & 0x1) { + fprintf(stderr, "PRED %u", + (op >> PVS_DST_PRED_SENSE_SHIFT) & 0x1); + } + if (op & 0x80) { + if (op & 0x1) { + fprintf(stderr, "PVS_MACRO_OP_2CLK_M2X_ADD\n"); + } else { + fprintf(stderr, " PVS_MACRO_OP_2CLK_MADD\n"); + } + } else if (op & 0x40) { + fprintf(stderr, "%s\n", r300_vs_me_ops[op & 0x1f]); + } else { + fprintf(stderr, "%s\n", r300_vs_ve_ops[op & 0x1f]); + } +} + +static void r300_vs_src_dump(uint32_t src) +{ + fprintf(stderr, " reg: %d%s swiz: %s%s/%s%s/%s%s/%s%s\n", + (src >> 5) & 0xff, r300_vs_src_debug[src & 0x3], + src & (1 << 25) ? "-" : " ", + r300_vs_swiz_debug[(src >> 13) & 0x7], + src & (1 << 26) ? "-" : " ", + r300_vs_swiz_debug[(src >> 16) & 0x7], + src & (1 << 27) ? "-" : " ", + r300_vs_swiz_debug[(src >> 19) & 0x7], + src & (1 << 28) ? "-" : " ", + r300_vs_swiz_debug[(src >> 22) & 0x7]); +} + +void r300_vertex_program_dump(struct radeon_compiler *compiler, void *user) +{ + struct r300_vertex_program_compiler *c = (struct r300_vertex_program_compiler*)compiler; + struct r300_vertex_program_code * vs = c->code; + unsigned instrcount = vs->length / 4; + unsigned i; + + fprintf(stderr, "Final vertex program code:\n"); + + for(i = 0; i < instrcount; i++) { + unsigned offset = i*4; + unsigned src; + + fprintf(stderr, "%d: op: 0x%08x", i, vs->body.d[offset]); + r300_vs_op_dump(vs->body.d[offset]); + + for(src = 0; src < 3; ++src) { + fprintf(stderr, " src%i: 0x%08x", src, vs->body.d[offset+1+src]); + r300_vs_src_dump(vs->body.d[offset+1+src]); + } + } + + fprintf(stderr, "Flow Control Ops: 0x%08x\n",vs->fc_ops); + for(i = 0; i < vs->num_fc_ops; i++) { + switch((vs->fc_ops >> (i * 2)) & 0x3 ) { + case 0: fprintf(stderr, "NOP"); break; + case 1: fprintf(stderr, "JUMP"); break; + case 2: fprintf(stderr, "LOOP"); break; + case 3: fprintf(stderr, "JSR"); break; + } + if (c->Base.is_r500) { + fprintf(stderr,": uw-> 0x%08x lw-> 0x%08x\n", + vs->fc_op_addrs.r500[i].uw, + vs->fc_op_addrs.r500[i].lw); + } else { + fprintf(stderr,": 0x%08x\n", vs->fc_op_addrs.r300[i]); + } + } +} diff --git a/src/gallium/drivers/r300/compiler/r500_fragprog.c b/src/gallium/drivers/r300/compiler/r500_fragprog.c new file mode 100644 index 00000000000..cf99f5e4538 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r500_fragprog.c @@ -0,0 +1,539 @@ +/* + * Copyright 2008 Corbin Simpson <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "r500_fragprog.h" + +#include <stdio.h> + +#include "radeon_compiler_util.h" +#include "radeon_list.h" +#include "radeon_variable.h" +#include "../r300_reg.h" + +/** + * Rewrite IF instructions to use the ALU result special register. + */ +int r500_transform_IF( + struct radeon_compiler * c, + struct rc_instruction * inst_if, + void *data) +{ + struct rc_variable * writer; + struct rc_list * writer_list, * list_ptr; + struct rc_list * var_list = rc_get_variables(c); + unsigned int generic_if = 0; + unsigned int alu_chan; + + if (inst_if->U.I.Opcode != RC_OPCODE_IF) { + return 0; + } + + writer_list = rc_variable_list_get_writers( + var_list, inst_if->Type, &inst_if->U.I.SrcReg[0]); + if (!writer_list) { + generic_if = 1; + } else { + + /* Make sure it is safe for the writers to write to + * ALU Result */ + for (list_ptr = writer_list; list_ptr; + list_ptr = list_ptr->Next) { + struct rc_instruction * inst; + writer = list_ptr->Item; + /* We are going to modify the destination register + * of writer, so if it has a reader other than + * inst_if (aka ReaderCount > 1) we must fall back to + * our generic IF. + * If the writer has a lower IP than inst_if, this + * means that inst_if is above the writer in a loop. + * I'm not sure why this would ever happen, but + * if it does we want to make sure we fall back + * to our generic IF. */ + if (writer->ReaderCount > 1 || writer->Inst->IP < inst_if->IP) { + generic_if = 1; + break; + } + + /* The ALU Result is not preserved across IF + * instructions, so if there is another IF + * instruction between writer and inst_if, then + * we need to fall back to generic IF. */ + for (inst = writer->Inst; inst != inst_if; inst = inst->Next) { + const struct rc_opcode_info * info = + rc_get_opcode_info(inst->U.I.Opcode); + if (info->IsFlowControl) { + generic_if = 1; + break; + } + } + if (generic_if) { + break; + } + } + } + + if (GET_SWZ(inst_if->U.I.SrcReg[0].Swizzle, 0) == RC_SWIZZLE_X) { + alu_chan = RC_ALURESULT_X; + } else { + alu_chan = RC_ALURESULT_W; + } + if (generic_if) { + struct rc_instruction * inst_mov = + rc_insert_new_instruction(c, inst_if->Prev); + + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.WriteMask = 0; + inst_mov->U.I.DstReg.File = RC_FILE_NONE; + inst_mov->U.I.ALUResultCompare = RC_COMPARE_FUNC_NOTEQUAL; + inst_mov->U.I.WriteALUResult = alu_chan; + inst_mov->U.I.SrcReg[0] = inst_if->U.I.SrcReg[0]; + if (alu_chan == RC_ALURESULT_X) { + inst_mov->U.I.SrcReg[0].Swizzle = combine_swizzles4( + inst_mov->U.I.SrcReg[0].Swizzle, + RC_SWIZZLE_X, RC_SWIZZLE_UNUSED, + RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED); + } else { + inst_mov->U.I.SrcReg[0].Swizzle = combine_swizzles4( + inst_mov->U.I.SrcReg[0].Swizzle, + RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED, + RC_SWIZZLE_UNUSED, RC_SWIZZLE_Z); + } + } else { + rc_compare_func compare_func = RC_COMPARE_FUNC_NEVER; + unsigned int reverse_srcs = 0; + unsigned int preserve_opcode = 0; + for (list_ptr = writer_list; list_ptr; + list_ptr = list_ptr->Next) { + writer = list_ptr->Item; + switch(writer->Inst->U.I.Opcode) { + case RC_OPCODE_SEQ: + compare_func = RC_COMPARE_FUNC_EQUAL; + break; + case RC_OPCODE_SNE: + compare_func = RC_COMPARE_FUNC_NOTEQUAL; + break; + case RC_OPCODE_SLE: + reverse_srcs = 1; + /* Fall through */ + case RC_OPCODE_SGE: + compare_func = RC_COMPARE_FUNC_GEQUAL; + break; + case RC_OPCODE_SGT: + reverse_srcs = 1; + /* Fall through */ + case RC_OPCODE_SLT: + compare_func = RC_COMPARE_FUNC_LESS; + break; + default: + compare_func = RC_COMPARE_FUNC_NOTEQUAL; + preserve_opcode = 1; + break; + } + if (!preserve_opcode) { + writer->Inst->U.I.Opcode = RC_OPCODE_SUB; + } + writer->Inst->U.I.DstReg.WriteMask = 0; + writer->Inst->U.I.DstReg.File = RC_FILE_NONE; + writer->Inst->U.I.WriteALUResult = alu_chan; + writer->Inst->U.I.ALUResultCompare = compare_func; + if (reverse_srcs) { + struct rc_src_register temp_src; + temp_src = writer->Inst->U.I.SrcReg[0]; + writer->Inst->U.I.SrcReg[0] = + writer->Inst->U.I.SrcReg[1]; + writer->Inst->U.I.SrcReg[1] = temp_src; + } + } + } + + inst_if->U.I.SrcReg[0].File = RC_FILE_SPECIAL; + inst_if->U.I.SrcReg[0].Index = RC_SPECIAL_ALU_RESULT; + inst_if->U.I.SrcReg[0].Swizzle = RC_MAKE_SWIZZLE( + RC_SWIZZLE_X, RC_SWIZZLE_UNUSED, + RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED); + inst_if->U.I.SrcReg[0].Negate = 0; + + return 1; +} + +static int r500_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg) +{ + unsigned int relevant; + int i; + + if (opcode == RC_OPCODE_TEX || + opcode == RC_OPCODE_TXB || + opcode == RC_OPCODE_TXP || + opcode == RC_OPCODE_TXD || + opcode == RC_OPCODE_TXL || + opcode == RC_OPCODE_KIL) { + if (reg.Abs) + return 0; + + if (opcode == RC_OPCODE_KIL && (reg.Swizzle != RC_SWIZZLE_XYZW || reg.Negate != RC_MASK_NONE)) + return 0; + + for(i = 0; i < 4; ++i) { + unsigned int swz = GET_SWZ(reg.Swizzle, i); + if (swz == RC_SWIZZLE_UNUSED) { + reg.Negate &= ~(1 << i); + continue; + } + if (swz >= 4) + return 0; + } + + if (reg.Negate) + return 0; + + return 1; + } else if (opcode == RC_OPCODE_DDX || opcode == RC_OPCODE_DDY) { + /* DDX/MDH and DDY/MDV explicitly ignore incoming swizzles; + * if it doesn't fit perfectly into a .xyzw case... */ + if (reg.Swizzle == RC_SWIZZLE_XYZW && !reg.Abs && !reg.Negate) + return 1; + + return 0; + } else { + /* ALU instructions support almost everything */ + relevant = 0; + for(i = 0; i < 3; ++i) { + unsigned int swz = GET_SWZ(reg.Swizzle, i); + if (swz != RC_SWIZZLE_UNUSED && swz != RC_SWIZZLE_ZERO) + relevant |= 1 << i; + } + if ((reg.Negate & relevant) && ((reg.Negate & relevant) != relevant)) + return 0; + + return 1; + } +} + +/** + * Split source register access. + * + * The only thing we *cannot* do in an ALU instruction is per-component + * negation. + */ +static void r500_swizzle_split(struct rc_src_register src, unsigned int usemask, + struct rc_swizzle_split * split) +{ + unsigned int negatebase[2] = { 0, 0 }; + int i; + + for(i = 0; i < 4; ++i) { + unsigned int swz = GET_SWZ(src.Swizzle, i); + if (swz == RC_SWIZZLE_UNUSED || !GET_BIT(usemask, i)) + continue; + negatebase[GET_BIT(src.Negate, i)] |= 1 << i; + } + + split->NumPhases = 0; + + for(i = 0; i <= 1; ++i) { + if (!negatebase[i]) + continue; + + split->Phase[split->NumPhases++] = negatebase[i]; + } +} + +struct rc_swizzle_caps r500_swizzle_caps = { + .IsNative = r500_swizzle_is_native, + .Split = r500_swizzle_split +}; + +static char *toswiz(int swiz_val) { + switch(swiz_val) { + case 0: return "R"; + case 1: return "G"; + case 2: return "B"; + case 3: return "A"; + case 4: return "0"; + case 5: return "H"; + case 6: return "1"; + case 7: return "U"; + } + return NULL; +} + +static char *toop(int op_val) +{ + char *str = NULL; + switch (op_val) { + case 0: str = "MAD"; break; + case 1: str = "DP3"; break; + case 2: str = "DP4"; break; + case 3: str = "D2A"; break; + case 4: str = "MIN"; break; + case 5: str = "MAX"; break; + case 6: str = "Reserved"; break; + case 7: str = "CND"; break; + case 8: str = "CMP"; break; + case 9: str = "FRC"; break; + case 10: str = "SOP"; break; + case 11: str = "MDH"; break; + case 12: str = "MDV"; break; + } + return str; +} + +static char *to_alpha_op(int op_val) +{ + char *str = NULL; + switch (op_val) { + case 0: str = "MAD"; break; + case 1: str = "DP"; break; + case 2: str = "MIN"; break; + case 3: str = "MAX"; break; + case 4: str = "Reserved"; break; + case 5: str = "CND"; break; + case 6: str = "CMP"; break; + case 7: str = "FRC"; break; + case 8: str = "EX2"; break; + case 9: str = "LN2"; break; + case 10: str = "RCP"; break; + case 11: str = "RSQ"; break; + case 12: str = "SIN"; break; + case 13: str = "COS"; break; + case 14: str = "MDH"; break; + case 15: str = "MDV"; break; + } + return str; +} + +static char *to_mask(int val) +{ + char *str = NULL; + switch(val) { + case 0: str = "NONE"; break; + case 1: str = "R"; break; + case 2: str = "G"; break; + case 3: str = "RG"; break; + case 4: str = "B"; break; + case 5: str = "RB"; break; + case 6: str = "GB"; break; + case 7: str = "RGB"; break; + case 8: str = "A"; break; + case 9: str = "AR"; break; + case 10: str = "AG"; break; + case 11: str = "ARG"; break; + case 12: str = "AB"; break; + case 13: str = "ARB"; break; + case 14: str = "AGB"; break; + case 15: str = "ARGB"; break; + } + return str; +} + +static char *to_texop(int val) +{ + switch(val) { + case 0: return "NOP"; + case 1: return "LD"; + case 2: return "TEXKILL"; + case 3: return "PROJ"; + case 4: return "LODBIAS"; + case 5: return "LOD"; + case 6: return "DXDY"; + } + return NULL; +} + +void r500FragmentProgramDump(struct radeon_compiler *c, void *user) +{ + struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c; + struct r500_fragment_program_code *code = &compiler->code->code.r500; + int n, i; + uint32_t inst; + uint32_t inst0; + char *str = NULL; + fprintf(stderr, "R500 Fragment Program:\n--------\n"); + + for (n = 0; n < code->inst_end+1; n++) { + inst0 = inst = code->inst[n].inst0; + fprintf(stderr,"%d\t0:CMN_INST 0x%08x:", n, inst); + switch(inst & 0x3) { + case R500_INST_TYPE_ALU: str = "ALU"; break; + case R500_INST_TYPE_OUT: str = "OUT"; break; + case R500_INST_TYPE_FC: str = "FC"; break; + case R500_INST_TYPE_TEX: str = "TEX"; break; + }; + fprintf(stderr,"%s %s %s %s %s ", str, + inst & R500_INST_TEX_SEM_WAIT ? "TEX_WAIT" : "", + inst & R500_INST_LAST ? "LAST" : "", + inst & R500_INST_NOP ? "NOP" : "", + inst & R500_INST_ALU_WAIT ? "ALU WAIT" : ""); + fprintf(stderr,"wmask: %s omask: %s\n", to_mask((inst >> 11) & 0xf), + to_mask((inst >> 15) & 0xf)); + + switch(inst0 & 0x3) { + case R500_INST_TYPE_ALU: + case R500_INST_TYPE_OUT: + fprintf(stderr,"\t1:RGB_ADDR 0x%08x:", code->inst[n].inst1); + inst = code->inst[n].inst1; + + fprintf(stderr,"Addr0: %d%c, Addr1: %d%c, Addr2: %d%c, srcp:%d\n", + inst & 0xff, (inst & (1<<8)) ? 'c' : 't', + (inst >> 10) & 0xff, (inst & (1<<18)) ? 'c' : 't', + (inst >> 20) & 0xff, (inst & (1<<28)) ? 'c' : 't', + (inst >> 30)); + + fprintf(stderr,"\t2:ALPHA_ADDR 0x%08x:", code->inst[n].inst2); + inst = code->inst[n].inst2; + fprintf(stderr,"Addr0: %d%c, Addr1: %d%c, Addr2: %d%c, srcp:%d\n", + inst & 0xff, (inst & (1<<8)) ? 'c' : 't', + (inst >> 10) & 0xff, (inst & (1<<18)) ? 'c' : 't', + (inst >> 20) & 0xff, (inst & (1<<28)) ? 'c' : 't', + (inst >> 30)); + fprintf(stderr,"\t3 RGB_INST: 0x%08x:", code->inst[n].inst3); + inst = code->inst[n].inst3; + fprintf(stderr,"rgb_A_src:%d %s/%s/%s %d rgb_B_src:%d %s/%s/%s %d targ: %d\n", + (inst) & 0x3, toswiz((inst >> 2) & 0x7), toswiz((inst >> 5) & 0x7), toswiz((inst >> 8) & 0x7), + (inst >> 11) & 0x3, + (inst >> 13) & 0x3, toswiz((inst >> 15) & 0x7), toswiz((inst >> 18) & 0x7), toswiz((inst >> 21) & 0x7), + (inst >> 24) & 0x3, (inst >> 29) & 0x3); + + + fprintf(stderr,"\t4 ALPHA_INST:0x%08x:", code->inst[n].inst4); + inst = code->inst[n].inst4; + fprintf(stderr,"%s dest:%d%s alp_A_src:%d %s %d alp_B_src:%d %s %d targ %d w:%d\n", to_alpha_op(inst & 0xf), + (inst >> 4) & 0x7f, inst & (1<<11) ? "(rel)":"", + (inst >> 12) & 0x3, toswiz((inst >> 14) & 0x7), (inst >> 17) & 0x3, + (inst >> 19) & 0x3, toswiz((inst >> 21) & 0x7), (inst >> 24) & 0x3, + (inst >> 29) & 0x3, + (inst >> 31) & 0x1); + + fprintf(stderr,"\t5 RGBA_INST: 0x%08x:", code->inst[n].inst5); + inst = code->inst[n].inst5; + fprintf(stderr,"%s dest:%d%s rgb_C_src:%d %s/%s/%s %d alp_C_src:%d %s %d\n", toop(inst & 0xf), + (inst >> 4) & 0x7f, inst & (1<<11) ? "(rel)":"", + (inst >> 12) & 0x3, toswiz((inst >> 14) & 0x7), toswiz((inst >> 17) & 0x7), toswiz((inst >> 20) & 0x7), + (inst >> 23) & 0x3, + (inst >> 25) & 0x3, toswiz((inst >> 27) & 0x7), (inst >> 30) & 0x3); + break; + case R500_INST_TYPE_FC: + fprintf(stderr, "\t2:FC_INST 0x%08x:", code->inst[n].inst2); + inst = code->inst[n].inst2; + /* JUMP_FUNC JUMP_ANY*/ + fprintf(stderr, "0x%02x %1x ", inst >> 8 & 0xff, + (inst & R500_FC_JUMP_ANY) >> 5); + + /* OP */ + switch(inst & 0x7){ + case R500_FC_OP_JUMP: + fprintf(stderr, "JUMP"); + break; + case R500_FC_OP_LOOP: + fprintf(stderr, "LOOP"); + break; + case R500_FC_OP_ENDLOOP: + fprintf(stderr, "ENDLOOP"); + break; + case R500_FC_OP_REP: + fprintf(stderr, "REP"); + break; + case R500_FC_OP_ENDREP: + fprintf(stderr, "ENDREP"); + break; + case R500_FC_OP_BREAKLOOP: + fprintf(stderr, "BREAKLOOP"); + break; + case R500_FC_OP_BREAKREP: + fprintf(stderr, "BREAKREP"); + break; + case R500_FC_OP_CONTINUE: + fprintf(stderr, "CONTINUE"); + break; + } + fprintf(stderr," "); + /* A_OP */ + switch(inst & (0x3 << 6)){ + case R500_FC_A_OP_NONE: + fprintf(stderr, "NONE"); + break; + case R500_FC_A_OP_POP: + fprintf(stderr, "POP"); + break; + case R500_FC_A_OP_PUSH: + fprintf(stderr, "PUSH"); + break; + } + /* B_OP0 B_OP1 */ + for(i=0; i<2; i++){ + fprintf(stderr, " "); + switch(inst & (0x3 << (24 + (i * 2)))){ + /* R500_FC_B_OP0_NONE + * R500_FC_B_OP1_NONE */ + case 0: + fprintf(stderr, "NONE"); + break; + case R500_FC_B_OP0_DECR: + case R500_FC_B_OP1_DECR: + fprintf(stderr, "DECR"); + break; + case R500_FC_B_OP0_INCR: + case R500_FC_B_OP1_INCR: + fprintf(stderr, "INCR"); + break; + } + } + /*POP_CNT B_ELSE */ + fprintf(stderr, " %d %1x", (inst >> 16) & 0x1f, (inst & R500_FC_B_ELSE) >> 4); + inst = code->inst[n].inst3; + /* JUMP_ADDR */ + fprintf(stderr, " %d", inst >> 16); + + if(code->inst[n].inst2 & R500_FC_IGNORE_UNCOVERED){ + fprintf(stderr, " IGN_UNC"); + } + inst = code->inst[n].inst3; + fprintf(stderr, "\n\t3:FC_ADDR 0x%08x:", inst); + fprintf(stderr, "BOOL: 0x%02x, INT: 0x%02x, JUMP_ADDR: %d, JMP_GLBL: %1x\n", + inst & 0x1f, (inst >> 8) & 0x1f, (inst >> 16) & 0x1ff, inst >> 31); + break; + case R500_INST_TYPE_TEX: + inst = code->inst[n].inst1; + fprintf(stderr,"\t1:TEX_INST: 0x%08x: id: %d op:%s, %s, %s %s\n", inst, (inst >> 16) & 0xf, + to_texop((inst >> 22) & 0x7), (inst & (1<<25)) ? "ACQ" : "", + (inst & (1<<26)) ? "IGNUNC" : "", (inst & (1<<27)) ? "UNSCALED" : "SCALED"); + inst = code->inst[n].inst2; + fprintf(stderr,"\t2:TEX_ADDR: 0x%08x: src: %d%s %s/%s/%s/%s dst: %d%s %s/%s/%s/%s\n", inst, + inst & 127, inst & (1<<7) ? "(rel)" : "", + toswiz((inst >> 8) & 0x3), toswiz((inst >> 10) & 0x3), + toswiz((inst >> 12) & 0x3), toswiz((inst >> 14) & 0x3), + (inst >> 16) & 127, inst & (1<<23) ? "(rel)" : "", + toswiz((inst >> 24) & 0x3), toswiz((inst >> 26) & 0x3), + toswiz((inst >> 28) & 0x3), toswiz((inst >> 30) & 0x3)); + + fprintf(stderr,"\t3:TEX_DXDY: 0x%08x\n", code->inst[n].inst3); + break; + } + fprintf(stderr,"\n"); + } + +} diff --git a/src/gallium/drivers/r300/compiler/r500_fragprog.h b/src/gallium/drivers/r300/compiler/r500_fragprog.h new file mode 100644 index 00000000000..6aa448cc6f7 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r500_fragprog.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005 Ben Skeggs. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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: + * Ben Skeggs <[email protected]> + * Jerome Glisse <[email protected]> + */ +#ifndef __R500_FRAGPROG_H_ +#define __R500_FRAGPROG_H_ + +#include "radeon_compiler.h" +#include "radeon_swizzle.h" + +extern void r500BuildFragmentProgramHwCode(struct radeon_compiler *c, void *user); + +extern void r500FragmentProgramDump(struct radeon_compiler *c, void *user); + +extern struct rc_swizzle_caps r500_swizzle_caps; + +extern int r500_transform_IF( + struct radeon_compiler * c, + struct rc_instruction * inst_if, + void* data); + +#endif diff --git a/src/gallium/drivers/r300/compiler/r500_fragprog_emit.c b/src/gallium/drivers/r300/compiler/r500_fragprog_emit.c new file mode 100644 index 00000000000..c30cd753d15 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/r500_fragprog_emit.c @@ -0,0 +1,678 @@ +/* + * Copyright (C) 2005 Ben Skeggs. + * + * Copyright 2008 Corbin Simpson <[email protected]> + * Adaptation and modification for ATI/AMD Radeon R500 GPU chipsets. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * \file + * + * \author Ben Skeggs <[email protected]> + * + * \author Jerome Glisse <[email protected]> + * + * \author Corbin Simpson <[email protected]> + * + */ + +#include "r500_fragprog.h" + +#include "../r300_reg.h" + +#include "radeon_program_pair.h" + +#define PROG_CODE \ + struct r500_fragment_program_code *code = &c->code->code.r500 + +#define error(fmt, args...) do { \ + rc_error(&c->Base, "%s::%s(): " fmt "\n", \ + __FILE__, __FUNCTION__, ##args); \ + } while(0) + + +struct branch_info { + int If; + int Else; + int Endif; +}; + +struct r500_loop_info { + int BgnLoop; + + int BranchDepth; + int * Brks; + int BrkCount; + int BrkReserved; + + int * Conts; + int ContCount; + int ContReserved; +}; + +struct emit_state { + struct radeon_compiler * C; + struct r500_fragment_program_code * Code; + + struct branch_info * Branches; + unsigned int CurrentBranchDepth; + unsigned int BranchesReserved; + + struct r500_loop_info * Loops; + unsigned int CurrentLoopDepth; + unsigned int LoopsReserved; + + unsigned int MaxBranchDepth; + +}; + +static unsigned int translate_rgb_op(struct r300_fragment_program_compiler *c, rc_opcode opcode) +{ + switch(opcode) { + case RC_OPCODE_CMP: return R500_ALU_RGBA_OP_CMP; + case RC_OPCODE_CND: return R500_ALU_RGBA_OP_CND; + case RC_OPCODE_DDX: return R500_ALU_RGBA_OP_MDH; + case RC_OPCODE_DDY: return R500_ALU_RGBA_OP_MDV; + case RC_OPCODE_DP3: return R500_ALU_RGBA_OP_DP3; + case RC_OPCODE_DP4: return R500_ALU_RGBA_OP_DP4; + case RC_OPCODE_FRC: return R500_ALU_RGBA_OP_FRC; + default: + error("translate_rgb_op: unknown opcode %s\n", rc_get_opcode_info(opcode)->Name); + /* fall through */ + case RC_OPCODE_NOP: + /* fall through */ + case RC_OPCODE_MAD: return R500_ALU_RGBA_OP_MAD; + case RC_OPCODE_MAX: return R500_ALU_RGBA_OP_MAX; + case RC_OPCODE_MIN: return R500_ALU_RGBA_OP_MIN; + case RC_OPCODE_REPL_ALPHA: return R500_ALU_RGBA_OP_SOP; + } +} + +static unsigned int translate_alpha_op(struct r300_fragment_program_compiler *c, rc_opcode opcode) +{ + switch(opcode) { + case RC_OPCODE_CMP: return R500_ALPHA_OP_CMP; + case RC_OPCODE_CND: return R500_ALPHA_OP_CND; + case RC_OPCODE_COS: return R500_ALPHA_OP_COS; + case RC_OPCODE_DDX: return R500_ALPHA_OP_MDH; + case RC_OPCODE_DDY: return R500_ALPHA_OP_MDV; + case RC_OPCODE_DP3: return R500_ALPHA_OP_DP; + case RC_OPCODE_DP4: return R500_ALPHA_OP_DP; + case RC_OPCODE_EX2: return R500_ALPHA_OP_EX2; + case RC_OPCODE_FRC: return R500_ALPHA_OP_FRC; + case RC_OPCODE_LG2: return R500_ALPHA_OP_LN2; + default: + error("translate_alpha_op: unknown opcode %s\n", rc_get_opcode_info(opcode)->Name); + /* fall through */ + case RC_OPCODE_NOP: + /* fall through */ + case RC_OPCODE_MAD: return R500_ALPHA_OP_MAD; + case RC_OPCODE_MAX: return R500_ALPHA_OP_MAX; + case RC_OPCODE_MIN: return R500_ALPHA_OP_MIN; + case RC_OPCODE_RCP: return R500_ALPHA_OP_RCP; + case RC_OPCODE_RSQ: return R500_ALPHA_OP_RSQ; + case RC_OPCODE_SIN: return R500_ALPHA_OP_SIN; + } +} + +static unsigned int fix_hw_swizzle(unsigned int swz) +{ + switch (swz) { + case RC_SWIZZLE_ZERO: + case RC_SWIZZLE_UNUSED: + swz = 4; + break; + case RC_SWIZZLE_HALF: + swz = 5; + break; + case RC_SWIZZLE_ONE: + swz = 6; + break; + } + + return swz; +} + +static unsigned int translate_arg_rgb(struct rc_pair_instruction *inst, int arg) +{ + unsigned int t = inst->RGB.Arg[arg].Source; + int comp; + t |= inst->RGB.Arg[arg].Negate << 11; + t |= inst->RGB.Arg[arg].Abs << 12; + + for(comp = 0; comp < 3; ++comp) + t |= fix_hw_swizzle(GET_SWZ(inst->RGB.Arg[arg].Swizzle, comp)) << (3*comp + 2); + + return t; +} + +static unsigned int translate_arg_alpha(struct rc_pair_instruction *inst, int i) +{ + unsigned int t = inst->Alpha.Arg[i].Source; + t |= fix_hw_swizzle(GET_SWZ(inst->Alpha.Arg[i].Swizzle, 0)) << 2; + t |= inst->Alpha.Arg[i].Negate << 5; + t |= inst->Alpha.Arg[i].Abs << 6; + return t; +} + +static uint32_t translate_alu_result_op(struct r300_fragment_program_compiler * c, rc_compare_func func) +{ + switch(func) { + case RC_COMPARE_FUNC_EQUAL: return R500_INST_ALU_RESULT_OP_EQ; + case RC_COMPARE_FUNC_LESS: return R500_INST_ALU_RESULT_OP_LT; + case RC_COMPARE_FUNC_GEQUAL: return R500_INST_ALU_RESULT_OP_GE; + case RC_COMPARE_FUNC_NOTEQUAL: return R500_INST_ALU_RESULT_OP_NE; + default: + rc_error(&c->Base, "%s: unsupported compare func %i\n", __FUNCTION__, func); + return 0; + } +} + +static void use_temporary(struct r500_fragment_program_code* code, unsigned int index) +{ + if (index > code->max_temp_idx) + code->max_temp_idx = index; +} + +static unsigned int use_source(struct r500_fragment_program_code* code, struct rc_pair_instruction_source src) +{ + /* From docs: + * Note that inline constants set the MSB of ADDR0 and clear ADDR0_CONST. + * MSB = 1 << 7 */ + if (!src.Used) + return 1 << 7; + + if (src.File == RC_FILE_CONSTANT) { + return src.Index | R500_RGB_ADDR0_CONST; + } else if (src.File == RC_FILE_TEMPORARY || src.File == RC_FILE_INPUT) { + use_temporary(code, src.Index); + return src.Index; + } + + return 0; +} + +/** + * NOP the specified instruction if it is not a texture lookup. + */ +static void alu_nop(struct r300_fragment_program_compiler *c, int ip) +{ + PROG_CODE; + + if ((code->inst[ip].inst0 & 0x3) != R500_INST_TYPE_TEX) { + code->inst[ip].inst0 |= R500_INST_NOP; + } +} + +/** + * Emit a paired ALU instruction. + */ +static void emit_paired(struct r300_fragment_program_compiler *c, struct rc_pair_instruction *inst) +{ + int ip; + PROG_CODE; + + if (code->inst_end >= c->Base.max_alu_insts-1) { + error("emit_alu: Too many instructions"); + return; + } + + ip = ++code->inst_end; + + /* Quirk: MDH/MDV (DDX/DDY) need a NOP on previous non-TEX instructions. */ + if (inst->RGB.Opcode == RC_OPCODE_DDX || inst->Alpha.Opcode == RC_OPCODE_DDX || + inst->RGB.Opcode == RC_OPCODE_DDY || inst->Alpha.Opcode == RC_OPCODE_DDY) { + if (ip > 0) { + alu_nop(c, ip - 1); + } + } + + code->inst[ip].inst5 = translate_rgb_op(c, inst->RGB.Opcode); + code->inst[ip].inst4 = translate_alpha_op(c, inst->Alpha.Opcode); + + if (inst->RGB.OutputWriteMask || inst->Alpha.OutputWriteMask || inst->Alpha.DepthWriteMask) { + code->inst[ip].inst0 = R500_INST_TYPE_OUT; + if (inst->WriteALUResult) { + error("Cannot write output and ALU result at the same time"); + return; + } + } else { + code->inst[ip].inst0 = R500_INST_TYPE_ALU; + } + code->inst[ip].inst0 |= R500_INST_TEX_SEM_WAIT; + + code->inst[ip].inst0 |= (inst->RGB.WriteMask << 11); + code->inst[ip].inst0 |= inst->Alpha.WriteMask ? 1 << 14 : 0; + code->inst[ip].inst0 |= (inst->RGB.OutputWriteMask << 15) | (inst->Alpha.OutputWriteMask << 18); + if (inst->Nop) { + code->inst[ip].inst0 |= R500_INST_NOP; + } + if (inst->Alpha.DepthWriteMask) { + code->inst[ip].inst4 |= R500_ALPHA_W_OMASK; + c->code->writes_depth = 1; + } + + code->inst[ip].inst4 |= R500_ALPHA_ADDRD(inst->Alpha.DestIndex); + code->inst[ip].inst5 |= R500_ALU_RGBA_ADDRD(inst->RGB.DestIndex); + use_temporary(code, inst->Alpha.DestIndex); + use_temporary(code, inst->RGB.DestIndex); + + if (inst->RGB.Saturate) + code->inst[ip].inst0 |= R500_INST_RGB_CLAMP; + if (inst->Alpha.Saturate) + code->inst[ip].inst0 |= R500_INST_ALPHA_CLAMP; + + /* Set the presubtract operation. */ + switch(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { + case RC_PRESUB_BIAS: + code->inst[ip].inst1 |= R500_RGB_SRCP_OP_1_MINUS_2RGB0; + break; + case RC_PRESUB_SUB: + code->inst[ip].inst1 |= R500_RGB_SRCP_OP_RGB1_MINUS_RGB0; + break; + case RC_PRESUB_ADD: + code->inst[ip].inst1 |= R500_RGB_SRCP_OP_RGB1_PLUS_RGB0; + break; + case RC_PRESUB_INV: + code->inst[ip].inst1 |= R500_RGB_SRCP_OP_1_MINUS_RGB0; + break; + default: + break; + } + switch(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { + case RC_PRESUB_BIAS: + code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_1_MINUS_2A0; + break; + case RC_PRESUB_SUB: + code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_A1_MINUS_A0; + break; + case RC_PRESUB_ADD: + code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_A1_PLUS_A0; + break; + case RC_PRESUB_INV: + code->inst[ip].inst2 |= R500_ALPHA_SRCP_OP_1_MINUS_A0; + break; + default: + break; + } + + code->inst[ip].inst1 |= R500_RGB_ADDR0(use_source(code, inst->RGB.Src[0])); + code->inst[ip].inst1 |= R500_RGB_ADDR1(use_source(code, inst->RGB.Src[1])); + code->inst[ip].inst1 |= R500_RGB_ADDR2(use_source(code, inst->RGB.Src[2])); + + code->inst[ip].inst2 |= R500_ALPHA_ADDR0(use_source(code, inst->Alpha.Src[0])); + code->inst[ip].inst2 |= R500_ALPHA_ADDR1(use_source(code, inst->Alpha.Src[1])); + code->inst[ip].inst2 |= R500_ALPHA_ADDR2(use_source(code, inst->Alpha.Src[2])); + + code->inst[ip].inst3 |= translate_arg_rgb(inst, 0) << R500_ALU_RGB_SEL_A_SHIFT; + code->inst[ip].inst3 |= translate_arg_rgb(inst, 1) << R500_ALU_RGB_SEL_B_SHIFT; + code->inst[ip].inst5 |= translate_arg_rgb(inst, 2) << R500_ALU_RGBA_SEL_C_SHIFT; + + code->inst[ip].inst4 |= translate_arg_alpha(inst, 0) << R500_ALPHA_SEL_A_SHIFT; + code->inst[ip].inst4 |= translate_arg_alpha(inst, 1) << R500_ALPHA_SEL_B_SHIFT; + code->inst[ip].inst5 |= translate_arg_alpha(inst, 2) << R500_ALU_RGBA_ALPHA_SEL_C_SHIFT; + + code->inst[ip].inst3 |= R500_ALU_RGB_TARGET(inst->RGB.Target); + code->inst[ip].inst4 |= R500_ALPHA_TARGET(inst->Alpha.Target); + + if (inst->WriteALUResult) { + code->inst[ip].inst3 |= R500_ALU_RGB_WMASK; + + if (inst->WriteALUResult == RC_ALURESULT_X) + code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_RED; + else + code->inst[ip].inst0 |= R500_INST_ALU_RESULT_SEL_ALPHA; + + code->inst[ip].inst0 |= translate_alu_result_op(c, inst->ALUResultCompare); + } +} + +static unsigned int translate_strq_swizzle(unsigned int swizzle) +{ + unsigned int swiz = 0; + int i; + for (i = 0; i < 4; i++) + swiz |= (GET_SWZ(swizzle, i) & 0x3) << i*2; + return swiz; +} + +/** + * Emit a single TEX instruction + */ +static int emit_tex(struct r300_fragment_program_compiler *c, struct rc_sub_instruction *inst) +{ + int ip; + PROG_CODE; + + if (code->inst_end >= c->Base.max_alu_insts-1) { + error("emit_tex: Too many instructions"); + return 0; + } + + ip = ++code->inst_end; + + code->inst[ip].inst0 = R500_INST_TYPE_TEX + | (inst->DstReg.WriteMask << 11) + | R500_INST_TEX_SEM_WAIT; + code->inst[ip].inst1 = R500_TEX_ID(inst->TexSrcUnit) + | R500_TEX_SEM_ACQUIRE; + + if (inst->TexSrcTarget == RC_TEXTURE_RECT) + code->inst[ip].inst1 |= R500_TEX_UNSCALED; + + switch (inst->Opcode) { + case RC_OPCODE_KIL: + code->inst[ip].inst1 |= R500_TEX_INST_TEXKILL; + break; + case RC_OPCODE_TEX: + code->inst[ip].inst1 |= R500_TEX_INST_LD; + break; + case RC_OPCODE_TXB: + code->inst[ip].inst1 |= R500_TEX_INST_LODBIAS; + break; + case RC_OPCODE_TXP: + code->inst[ip].inst1 |= R500_TEX_INST_PROJ; + break; + case RC_OPCODE_TXD: + code->inst[ip].inst1 |= R500_TEX_INST_DXDY; + break; + case RC_OPCODE_TXL: + code->inst[ip].inst1 |= R500_TEX_INST_LOD; + break; + default: + error("emit_tex can't handle opcode %s\n", rc_get_opcode_info(inst->Opcode)->Name); + } + + use_temporary(code, inst->SrcReg[0].Index); + if (inst->Opcode != RC_OPCODE_KIL) + use_temporary(code, inst->DstReg.Index); + + code->inst[ip].inst2 = R500_TEX_SRC_ADDR(inst->SrcReg[0].Index) + | (translate_strq_swizzle(inst->SrcReg[0].Swizzle) << 8) + | R500_TEX_DST_ADDR(inst->DstReg.Index) + | (GET_SWZ(inst->TexSwizzle, 0) << 24) + | (GET_SWZ(inst->TexSwizzle, 1) << 26) + | (GET_SWZ(inst->TexSwizzle, 2) << 28) + | (GET_SWZ(inst->TexSwizzle, 3) << 30) + ; + + if (inst->Opcode == RC_OPCODE_TXD) { + use_temporary(code, inst->SrcReg[1].Index); + use_temporary(code, inst->SrcReg[2].Index); + + /* DX and DY parameters are specified in a separate register. */ + code->inst[ip].inst3 = + R500_DX_ADDR(inst->SrcReg[1].Index) | + (translate_strq_swizzle(inst->SrcReg[1].Swizzle) << 8) | + R500_DY_ADDR(inst->SrcReg[2].Index) | + (translate_strq_swizzle(inst->SrcReg[2].Swizzle) << 24); + } + + return 1; +} + +static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst) +{ + unsigned int newip; + + if (s->Code->inst_end >= s->C->max_alu_insts-1) { + rc_error(s->C, "emit_tex: Too many instructions"); + return; + } + + newip = ++s->Code->inst_end; + + /* Currently all loops use the same integer constant to intialize + * the loop variables. */ + if(!s->Code->int_constants[0]) { + s->Code->int_constants[0] = R500_FC_INT_CONST_KR(0xff); + s->Code->int_constant_count = 1; + } + s->Code->inst[newip].inst0 = R500_INST_TYPE_FC | R500_INST_ALU_WAIT; + + switch(inst->U.I.Opcode){ + struct branch_info * branch; + struct r500_loop_info * loop; + case RC_OPCODE_BGNLOOP: + memory_pool_array_reserve(&s->C->Pool, struct r500_loop_info, + s->Loops, s->CurrentLoopDepth, s->LoopsReserved, 1); + + loop = &s->Loops[s->CurrentLoopDepth++]; + memset(loop, 0, sizeof(struct r500_loop_info)); + loop->BranchDepth = s->CurrentBranchDepth; + loop->BgnLoop = newip; + + s->Code->inst[newip].inst2 = R500_FC_OP_LOOP + | R500_FC_JUMP_FUNC(0x00) + | R500_FC_IGNORE_UNCOVERED + ; + break; + case RC_OPCODE_BRK: + loop = &s->Loops[s->CurrentLoopDepth - 1]; + memory_pool_array_reserve(&s->C->Pool, int, loop->Brks, + loop->BrkCount, loop->BrkReserved, 1); + + loop->Brks[loop->BrkCount++] = newip; + s->Code->inst[newip].inst2 = R500_FC_OP_BREAKLOOP + | R500_FC_JUMP_FUNC(0xff) + | R500_FC_B_OP1_DECR + | R500_FC_B_POP_CNT( + s->CurrentBranchDepth - loop->BranchDepth) + | R500_FC_IGNORE_UNCOVERED + ; + break; + + case RC_OPCODE_CONT: + loop = &s->Loops[s->CurrentLoopDepth - 1]; + memory_pool_array_reserve(&s->C->Pool, int, loop->Conts, + loop->ContCount, loop->ContReserved, 1); + loop->Conts[loop->ContCount++] = newip; + s->Code->inst[newip].inst2 = R500_FC_OP_CONTINUE + | R500_FC_JUMP_FUNC(0xff) + | R500_FC_B_OP1_DECR + | R500_FC_B_POP_CNT( + s->CurrentBranchDepth - loop->BranchDepth) + | R500_FC_IGNORE_UNCOVERED + ; + break; + + case RC_OPCODE_ENDLOOP: + { + loop = &s->Loops[s->CurrentLoopDepth - 1]; + /* Emit ENDLOOP */ + s->Code->inst[newip].inst2 = R500_FC_OP_ENDLOOP + | R500_FC_JUMP_FUNC(0xff) + | R500_FC_JUMP_ANY + | R500_FC_IGNORE_UNCOVERED + ; + /* The constant integer at index 0 is used by all loops. */ + s->Code->inst[newip].inst3 = R500_FC_INT_ADDR(0) + | R500_FC_JUMP_ADDR(loop->BgnLoop + 1) + ; + + /* Set jump address and int constant for BGNLOOP */ + s->Code->inst[loop->BgnLoop].inst3 = R500_FC_INT_ADDR(0) + | R500_FC_JUMP_ADDR(newip) + ; + + /* Set jump address for the BRK instructions. */ + while(loop->BrkCount--) { + s->Code->inst[loop->Brks[loop->BrkCount]].inst3 = + R500_FC_JUMP_ADDR(newip + 1); + } + + /* Set jump address for CONT instructions. */ + while(loop->ContCount--) { + s->Code->inst[loop->Conts[loop->ContCount]].inst3 = + R500_FC_JUMP_ADDR(newip); + } + s->CurrentLoopDepth--; + break; + } + case RC_OPCODE_IF: + if ( s->CurrentBranchDepth >= R500_PFS_MAX_BRANCH_DEPTH_FULL) { + rc_error(s->C, "Branch depth exceeds hardware limit"); + return; + } + memory_pool_array_reserve(&s->C->Pool, struct branch_info, + s->Branches, s->CurrentBranchDepth, s->BranchesReserved, 1); + + branch = &s->Branches[s->CurrentBranchDepth++]; + branch->If = newip; + branch->Else = -1; + branch->Endif = -1; + + if (s->CurrentBranchDepth > s->MaxBranchDepth) + s->MaxBranchDepth = s->CurrentBranchDepth; + + /* actual instruction is filled in at ENDIF time */ + break; + + case RC_OPCODE_ELSE: + if (!s->CurrentBranchDepth) { + rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); + return; + } + + branch = &s->Branches[s->CurrentBranchDepth - 1]; + branch->Else = newip; + + /* actual instruction is filled in at ENDIF time */ + break; + + case RC_OPCODE_ENDIF: + if (!s->CurrentBranchDepth) { + rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__); + return; + } + + branch = &s->Branches[s->CurrentBranchDepth - 1]; + branch->Endif = newip; + + s->Code->inst[branch->Endif].inst2 = R500_FC_OP_JUMP + | R500_FC_A_OP_NONE /* no address stack */ + | R500_FC_JUMP_ANY /* docs says set this, but I don't understand why */ + | R500_FC_B_OP0_DECR /* decrement branch counter if stay */ + | R500_FC_B_OP1_NONE /* no branch counter if stay */ + | R500_FC_B_POP_CNT(1) + ; + s->Code->inst[branch->Endif].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); + s->Code->inst[branch->If].inst2 = R500_FC_OP_JUMP + | R500_FC_A_OP_NONE /* no address stack */ + | R500_FC_JUMP_FUNC(0x0f) /* jump if ALU result is false */ + | R500_FC_B_OP0_INCR /* increment branch counter if stay */ + | R500_FC_IGNORE_UNCOVERED + ; + + if (branch->Else >= 0) { + /* increment branch counter also if jump */ + s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_INCR; + s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Else + 1); + + s->Code->inst[branch->Else].inst2 = R500_FC_OP_JUMP + | R500_FC_A_OP_NONE /* no address stack */ + | R500_FC_B_ELSE /* all active pixels want to jump */ + | R500_FC_B_OP0_NONE /* no counter op if stay */ + | R500_FC_B_OP1_DECR /* decrement branch counter if jump */ + | R500_FC_B_POP_CNT(1) + ; + s->Code->inst[branch->Else].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); + } else { + /* don't touch branch counter on jump */ + s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_NONE; + s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1); + } + + + s->CurrentBranchDepth--; + break; + default: + rc_error(s->C, "%s: unknown opcode %s\n", __FUNCTION__, rc_get_opcode_info(inst->U.I.Opcode)->Name); + } +} + +void r500BuildFragmentProgramHwCode(struct radeon_compiler *c, void *user) +{ + struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c; + struct emit_state s; + struct r500_fragment_program_code *code = &compiler->code->code.r500; + + memset(&s, 0, sizeof(s)); + s.C = &compiler->Base; + s.Code = code; + + memset(code, 0, sizeof(*code)); + code->max_temp_idx = 1; + code->inst_end = -1; + + for(struct rc_instruction * inst = compiler->Base.Program.Instructions.Next; + inst != &compiler->Base.Program.Instructions && !compiler->Base.Error; + inst = inst->Next) { + if (inst->Type == RC_INSTRUCTION_NORMAL) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (opcode->IsFlowControl) { + emit_flowcontrol(&s, inst); + } else if (inst->U.I.Opcode == RC_OPCODE_BEGIN_TEX) { + continue; + } else { + emit_tex(compiler, &inst->U.I); + } + } else { + emit_paired(compiler, &inst->U.P); + } + } + + if (code->max_temp_idx >= compiler->Base.max_temp_regs) + rc_error(&compiler->Base, "Too many hardware temporaries used"); + + if (compiler->Base.Error) + return; + + if (code->inst_end == -1 || + (code->inst[code->inst_end].inst0 & R500_INST_TYPE_MASK) != R500_INST_TYPE_OUT) { + int ip; + + /* This may happen when dead-code elimination is disabled or + * when most of the fragment program logic is leading to a KIL */ + if (code->inst_end >= compiler->Base.max_alu_insts-1) { + rc_error(&compiler->Base, "Introducing fake OUT: Too many instructions"); + return; + } + + ip = ++code->inst_end; + code->inst[ip].inst0 = R500_INST_TYPE_OUT | R500_INST_TEX_SEM_WAIT; + } + + /* Enable full flow control mode if we are using loops or have if + * statements nested at least four deep. */ + if (s.MaxBranchDepth >= 4 || s.LoopsReserved > 0) { + if (code->max_temp_idx < 1) + code->max_temp_idx = 1; + + code->us_fc_ctrl |= R500_FC_FULL_FC_EN; + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_code.c b/src/gallium/drivers/r300/compiler/radeon_code.c new file mode 100644 index 00000000000..6842fb873bc --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_code.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_code.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "radeon_program.h" + +void rc_constants_init(struct rc_constant_list * c) +{ + memset(c, 0, sizeof(*c)); +} + +/** + * Copy a constants structure, assuming that the destination structure + * is not initialized. + */ +void rc_constants_copy(struct rc_constant_list * dst, struct rc_constant_list * src) +{ + dst->Constants = malloc(sizeof(struct rc_constant) * src->Count); + memcpy(dst->Constants, src->Constants, sizeof(struct rc_constant) * src->Count); + dst->Count = src->Count; + dst->_Reserved = src->Count; +} + +void rc_constants_destroy(struct rc_constant_list * c) +{ + free(c->Constants); + memset(c, 0, sizeof(*c)); +} + +unsigned rc_constants_add(struct rc_constant_list * c, struct rc_constant * constant) +{ + unsigned index = c->Count; + + if (c->Count >= c->_Reserved) { + struct rc_constant * newlist; + + c->_Reserved = c->_Reserved * 2; + if (!c->_Reserved) + c->_Reserved = 16; + + newlist = malloc(sizeof(struct rc_constant) * c->_Reserved); + memcpy(newlist, c->Constants, sizeof(struct rc_constant) * c->Count); + + free(c->Constants); + c->Constants = newlist; + } + + c->Constants[index] = *constant; + c->Count++; + + return index; +} + + +/** + * Add a state vector to the constant list, while trying to avoid duplicates. + */ +unsigned rc_constants_add_state(struct rc_constant_list * c, unsigned state0, unsigned state1) +{ + unsigned index; + struct rc_constant constant; + + for(index = 0; index < c->Count; ++index) { + if (c->Constants[index].Type == RC_CONSTANT_STATE) { + if (c->Constants[index].u.State[0] == state0 && + c->Constants[index].u.State[1] == state1) + return index; + } + } + + memset(&constant, 0, sizeof(constant)); + constant.Type = RC_CONSTANT_STATE; + constant.Size = 4; + constant.u.State[0] = state0; + constant.u.State[1] = state1; + + return rc_constants_add(c, &constant); +} + + +/** + * Add an immediate vector to the constant list, while trying to avoid + * duplicates. + */ +unsigned rc_constants_add_immediate_vec4(struct rc_constant_list * c, const float * data) +{ + unsigned index; + struct rc_constant constant; + + for(index = 0; index < c->Count; ++index) { + if (c->Constants[index].Type == RC_CONSTANT_IMMEDIATE) { + if (!memcmp(c->Constants[index].u.Immediate, data, sizeof(float)*4)) + return index; + } + } + + memset(&constant, 0, sizeof(constant)); + constant.Type = RC_CONSTANT_IMMEDIATE; + constant.Size = 4; + memcpy(constant.u.Immediate, data, sizeof(float) * 4); + + return rc_constants_add(c, &constant); +} + + +/** + * Add an immediate scalar to the constant list, while trying to avoid + * duplicates. + */ +unsigned rc_constants_add_immediate_scalar(struct rc_constant_list * c, float data, unsigned * swizzle) +{ + unsigned index; + int free_index = -1; + struct rc_constant constant; + + for(index = 0; index < c->Count; ++index) { + if (c->Constants[index].Type == RC_CONSTANT_IMMEDIATE) { + unsigned comp; + for(comp = 0; comp < c->Constants[index].Size; ++comp) { + if (c->Constants[index].u.Immediate[comp] == data) { + *swizzle = RC_MAKE_SWIZZLE_SMEAR(comp); + return index; + } + } + + if (c->Constants[index].Size < 4) + free_index = index; + } + } + + if (free_index >= 0) { + unsigned comp = c->Constants[free_index].Size++; + c->Constants[free_index].u.Immediate[comp] = data; + *swizzle = RC_MAKE_SWIZZLE_SMEAR(comp); + return free_index; + } + + memset(&constant, 0, sizeof(constant)); + constant.Type = RC_CONSTANT_IMMEDIATE; + constant.Size = 1; + constant.u.Immediate[0] = data; + *swizzle = RC_SWIZZLE_XXXX; + + return rc_constants_add(c, &constant); +} + +void rc_constants_print(struct rc_constant_list * c) +{ + unsigned int i; + for(i = 0; i < c->Count; i++) { + if (c->Constants[i].Type == RC_CONSTANT_IMMEDIATE) { + float * values = c->Constants[i].u.Immediate; + fprintf(stderr, "CONST[%u] = " + "{ %10.4f %10.4f %10.4f %10.4f }\n", + i, values[0],values[1], values[2], values[3]); + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_code.h b/src/gallium/drivers/r300/compiler/radeon_code.h new file mode 100644 index 00000000000..67e6acf8b10 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_code.h @@ -0,0 +1,306 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#ifndef RADEON_CODE_H +#define RADEON_CODE_H + +#include <stdint.h> + +#define R300_PFS_MAX_ALU_INST 64 +#define R300_PFS_MAX_TEX_INST 32 +#define R300_PFS_MAX_TEX_INDIRECT 4 +#define R300_PFS_NUM_TEMP_REGS 32 +#define R300_PFS_NUM_CONST_REGS 32 + +#define R400_PFS_MAX_ALU_INST 512 +#define R400_PFS_MAX_TEX_INST 512 + +#define R500_PFS_MAX_INST 512 +#define R500_PFS_NUM_TEMP_REGS 128 +#define R500_PFS_NUM_CONST_REGS 256 +#define R500_PFS_MAX_BRANCH_DEPTH_FULL 32 +#define R500_PFS_MAX_BRANCH_DEPTH_PARTIAL 4 + + +#define STATE_R300_WINDOW_DIMENSION (STATE_INTERNAL_DRIVER+0) + +enum { + /** + * External constants are constants whose meaning is unknown to this + * compiler. For example, a Mesa gl_program's constants are turned + * into external constants. + */ + RC_CONSTANT_EXTERNAL = 0, + + RC_CONSTANT_IMMEDIATE, + + /** + * Constant referring to state that is known by this compiler, + * see RC_STATE_xxx, i.e. *not* arbitrary Mesa (or other) state. + */ + RC_CONSTANT_STATE +}; + +enum { + RC_STATE_SHADOW_AMBIENT = 0, + + RC_STATE_R300_WINDOW_DIMENSION, + RC_STATE_R300_TEXRECT_FACTOR, + RC_STATE_R300_TEXSCALE_FACTOR, + RC_STATE_R300_VIEWPORT_SCALE, + RC_STATE_R300_VIEWPORT_OFFSET +}; + +struct rc_constant { + unsigned Type:2; /**< RC_CONSTANT_xxx */ + unsigned Size:3; + + union { + unsigned External; + float Immediate[4]; + unsigned State[2]; + } u; +}; + +struct rc_constant_list { + struct rc_constant * Constants; + unsigned Count; + + unsigned _Reserved; +}; + +void rc_constants_init(struct rc_constant_list * c); +void rc_constants_copy(struct rc_constant_list * dst, struct rc_constant_list * src); +void rc_constants_destroy(struct rc_constant_list * c); +unsigned rc_constants_add(struct rc_constant_list * c, struct rc_constant * constant); +unsigned rc_constants_add_state(struct rc_constant_list * c, unsigned state1, unsigned state2); +unsigned rc_constants_add_immediate_vec4(struct rc_constant_list * c, const float * data); +unsigned rc_constants_add_immediate_scalar(struct rc_constant_list * c, float data, unsigned * swizzle); +void rc_constants_print(struct rc_constant_list * c); + +/** + * Compare functions. + * + * \note By design, RC_COMPARE_FUNC_xxx + GL_NEVER gives you + * the correct GL compare function. + */ +typedef enum { + RC_COMPARE_FUNC_NEVER = 0, + RC_COMPARE_FUNC_LESS, + RC_COMPARE_FUNC_EQUAL, + RC_COMPARE_FUNC_LEQUAL, + RC_COMPARE_FUNC_GREATER, + RC_COMPARE_FUNC_NOTEQUAL, + RC_COMPARE_FUNC_GEQUAL, + RC_COMPARE_FUNC_ALWAYS +} rc_compare_func; + +/** + * Coordinate wrapping modes. + * + * These are not quite the same as their GL counterparts yet. + */ +typedef enum { + RC_WRAP_NONE = 0, + RC_WRAP_REPEAT, + RC_WRAP_MIRRORED_REPEAT, + RC_WRAP_MIRRORED_CLAMP +} rc_wrap_mode; + +/** + * Stores state that influences the compilation of a fragment program. + */ +struct r300_fragment_program_external_state { + struct { + /** + * This field contains swizzle for some lowering passes + * (shadow comparison, unorm->snorm conversion) + */ + unsigned texture_swizzle:12; + + /** + * If the sampler is used as a shadow sampler, + * this field specifies the compare function. + * + * Otherwise, this field is \ref RC_COMPARE_FUNC_NEVER (aka 0). + * \sa rc_compare_func + */ + unsigned texture_compare_func : 3; + + /** + * No matter what the sampler type is, + * this field turns it into a shadow sampler. + */ + unsigned compare_mode_enabled : 1; + + /** + * If the sampler will receive non-normalized coords, + * this field is set. The scaling factor is given by + * RC_STATE_R300_TEXRECT_FACTOR. + */ + unsigned non_normalized_coords : 1; + + /** + * This field specifies wrapping modes for the sampler. + * + * If this field is \ref RC_WRAP_NONE (aka 0), no wrapping maths + * will be performed on the coordinates. + */ + unsigned wrap_mode : 3; + + /** + * The coords are scaled after applying the wrap mode emulation + * and right before texture fetch. The scaling factor is given by + * RC_STATE_R300_TEXSCALE_FACTOR. */ + unsigned clamp_and_scale_before_fetch : 1; + + /** + * Fetch RGTC1_SNORM or LATC1_SNORM as UNORM and convert UNORM -> SNORM + * in the shader. + */ + unsigned convert_unorm_to_snorm:1; + } unit[16]; + + unsigned frag_clamp:1; +}; + + + +struct r300_fragment_program_node { + int tex_offset; /**< first tex instruction */ + int tex_end; /**< last tex instruction, relative to tex_offset */ + int alu_offset; /**< first ALU instruction */ + int alu_end; /**< last ALU instruction, relative to alu_offset */ + int flags; +}; + +/** + * Stores an R300 fragment program in its compiled-to-hardware form. + */ +struct r300_fragment_program_code { + struct { + unsigned int length; /**< total # of texture instructions used */ + uint32_t inst[R400_PFS_MAX_TEX_INST]; + } tex; + + struct { + unsigned int length; /**< total # of ALU instructions used */ + struct { + uint32_t rgb_inst; + uint32_t rgb_addr; + uint32_t alpha_inst; + uint32_t alpha_addr; + uint32_t r400_ext_addr; + } inst[R400_PFS_MAX_ALU_INST]; + } alu; + + uint32_t config; /* US_CONFIG */ + uint32_t pixsize; /* US_PIXSIZE */ + uint32_t code_offset; /* US_CODE_OFFSET */ + uint32_t r400_code_offset_ext; /* US_CODE_EXT */ + uint32_t code_addr[4]; /* US_CODE_ADDR */ + /*US_CODE_BANK.R390_MODE: Enables 512 instructions and 64 temporaries + * for r400 cards */ + unsigned int r390_mode:1; +}; + + +struct r500_fragment_program_code { + struct { + uint32_t inst0; + uint32_t inst1; + uint32_t inst2; + uint32_t inst3; + uint32_t inst4; + uint32_t inst5; + } inst[R500_PFS_MAX_INST]; + + int inst_end; /* Number of instructions - 1; also, last instruction to be executed */ + + int max_temp_idx; + + uint32_t us_fc_ctrl; + + uint32_t int_constants[32]; + uint32_t int_constant_count; +}; + +struct rX00_fragment_program_code { + union { + struct r300_fragment_program_code r300; + struct r500_fragment_program_code r500; + } code; + + unsigned writes_depth:1; + + struct rc_constant_list constants; + unsigned *constants_remap_table; +}; + + +#define R300_VS_MAX_ALU 256 +#define R300_VS_MAX_ALU_DWORDS (R300_VS_MAX_ALU * 4) +#define R500_VS_MAX_ALU 1024 +#define R500_VS_MAX_ALU_DWORDS (R500_VS_MAX_ALU * 4) +#define R300_VS_MAX_TEMPS 32 +/* This is the max for all chipsets (r300-r500) */ +#define R300_VS_MAX_FC_OPS 16 +/* The r500 maximum depth is not just for loops, but any combination of loops + * and subroutine jumps. */ +#define R500_VS_MAX_FC_DEPTH 8 +#define R300_VS_MAX_LOOP_DEPTH 1 + +#define VSF_MAX_INPUTS 32 +#define VSF_MAX_OUTPUTS 32 + +struct r300_vertex_program_code { + int length; + union { + uint32_t d[R500_VS_MAX_ALU_DWORDS]; + float f[R500_VS_MAX_ALU_DWORDS]; + } body; + + int pos_end; + int num_temporaries; /* Number of temp vars used by program */ + int inputs[VSF_MAX_INPUTS]; + int outputs[VSF_MAX_OUTPUTS]; + + struct rc_constant_list constants; + unsigned *constants_remap_table; + + uint32_t InputsRead; + uint32_t OutputsWritten; + + unsigned int num_fc_ops; + uint32_t fc_ops; + union { + uint32_t r300[R300_VS_MAX_FC_OPS]; + struct { + uint32_t lw; + uint32_t uw; + } r500[R300_VS_MAX_FC_OPS]; + } fc_op_addrs; + int32_t fc_loop_index[R300_VS_MAX_FC_OPS]; +}; + +#endif /* RADEON_CODE_H */ + diff --git a/src/gallium/drivers/r300/compiler/radeon_compiler.c b/src/gallium/drivers/r300/compiler/radeon_compiler.c new file mode 100644 index 00000000000..b7936725d85 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_compiler.c @@ -0,0 +1,489 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "radeon_compiler.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "radeon_dataflow.h" +#include "radeon_program.h" +#include "radeon_program_pair.h" +#include "radeon_compiler_util.h" + + +void rc_init(struct radeon_compiler * c) +{ + memset(c, 0, sizeof(*c)); + + memory_pool_init(&c->Pool); + c->Program.Instructions.Prev = &c->Program.Instructions; + c->Program.Instructions.Next = &c->Program.Instructions; + c->Program.Instructions.U.I.Opcode = RC_OPCODE_ILLEGAL_OPCODE; +} + +void rc_destroy(struct radeon_compiler * c) +{ + rc_constants_destroy(&c->Program.Constants); + memory_pool_destroy(&c->Pool); + free(c->ErrorMsg); +} + +void rc_debug(struct radeon_compiler * c, const char * fmt, ...) +{ + va_list ap; + + if (!(c->Debug & RC_DBG_LOG)) + return; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void rc_error(struct radeon_compiler * c, const char * fmt, ...) +{ + va_list ap; + + c->Error = 1; + + if (!c->ErrorMsg) { + /* Only remember the first error */ + char buf[1024]; + int written; + + va_start(ap, fmt); + written = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if (written < sizeof(buf)) { + c->ErrorMsg = strdup(buf); + } else { + c->ErrorMsg = malloc(written + 1); + + va_start(ap, fmt); + vsnprintf(c->ErrorMsg, written + 1, fmt, ap); + va_end(ap); + } + } + + if (c->Debug & RC_DBG_LOG) { + fprintf(stderr, "r300compiler error: "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion) +{ + rc_error(c, "ICE at %s:%i: assertion failed: %s\n", file, line, assertion); + return 1; +} + +/** + * Recompute c->Program.InputsRead and c->Program.OutputsWritten + * based on which inputs and outputs are actually referenced + * in program instructions. + */ +void rc_calculate_inputs_outputs(struct radeon_compiler * c) +{ + struct rc_instruction *inst; + + c->Program.InputsRead = 0; + c->Program.OutputsWritten = 0; + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) + { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + int i; + + for (i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT) + c->Program.InputsRead |= 1 << inst->U.I.SrcReg[i].Index; + } + + if (opcode->HasDstReg) { + if (inst->U.I.DstReg.File == RC_FILE_OUTPUT) + c->Program.OutputsWritten |= 1 << inst->U.I.DstReg.Index; + } + } +} + +/** + * Rewrite the program such that everything that source the given input + * register will source new_input instead. + */ +void rc_move_input(struct radeon_compiler * c, unsigned input, struct rc_src_register new_input) +{ + struct rc_instruction * inst; + + c->Program.InputsRead &= ~(1 << input); + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned i; + + for(i = 0; i < opcode->NumSrcRegs; ++i) { + if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT && inst->U.I.SrcReg[i].Index == input) { + inst->U.I.SrcReg[i].File = new_input.File; + inst->U.I.SrcReg[i].Index = new_input.Index; + inst->U.I.SrcReg[i].Swizzle = combine_swizzles(new_input.Swizzle, inst->U.I.SrcReg[i].Swizzle); + if (!inst->U.I.SrcReg[i].Abs) { + inst->U.I.SrcReg[i].Negate ^= new_input.Negate; + inst->U.I.SrcReg[i].Abs = new_input.Abs; + } + + c->Program.InputsRead |= 1 << new_input.Index; + } + } + } +} + + +/** + * Rewrite the program such that everything that writes into the given + * output register will instead write to new_output. The new_output + * writemask is honoured. + */ +void rc_move_output(struct radeon_compiler * c, unsigned output, unsigned new_output, unsigned writemask) +{ + struct rc_instruction * inst; + + c->Program.OutputsWritten &= ~(1 << output); + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (opcode->HasDstReg) { + if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) { + inst->U.I.DstReg.Index = new_output; + inst->U.I.DstReg.WriteMask &= writemask; + + c->Program.OutputsWritten |= 1 << new_output; + } + } + } +} + + +/** + * Rewrite the program such that a given output is duplicated. + */ +void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_output) +{ + unsigned tempreg = rc_find_free_temporary(c); + struct rc_instruction * inst; + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (opcode->HasDstReg) { + if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) { + inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst->U.I.DstReg.Index = tempreg; + } + } + } + + inst = rc_insert_new_instruction(c, c->Program.Instructions.Prev); + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.DstReg.File = RC_FILE_OUTPUT; + inst->U.I.DstReg.Index = output; + + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = tempreg; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + + inst = rc_insert_new_instruction(c, c->Program.Instructions.Prev); + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.DstReg.File = RC_FILE_OUTPUT; + inst->U.I.DstReg.Index = dup_output; + + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = tempreg; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + + c->Program.OutputsWritten |= 1 << dup_output; +} + + +/** + * Introduce standard code fragment to deal with fragment.position. + */ +void rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsigned new_input, + int full_vtransform) +{ + unsigned tempregi = rc_find_free_temporary(c); + struct rc_instruction * inst_rcp; + struct rc_instruction * inst_mul; + struct rc_instruction * inst_mad; + struct rc_instruction * inst; + + c->Program.InputsRead &= ~(1 << wpos); + c->Program.InputsRead |= 1 << new_input; + + /* perspective divide */ + inst_rcp = rc_insert_new_instruction(c, &c->Program.Instructions); + inst_rcp->U.I.Opcode = RC_OPCODE_RCP; + + inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rcp->U.I.DstReg.Index = tempregi; + inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W; + + inst_rcp->U.I.SrcReg[0].File = RC_FILE_INPUT; + inst_rcp->U.I.SrcReg[0].Index = new_input; + inst_rcp->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW; + + inst_mul = rc_insert_new_instruction(c, inst_rcp); + inst_mul->U.I.Opcode = RC_OPCODE_MUL; + + inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mul->U.I.DstReg.Index = tempregi; + inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ; + + inst_mul->U.I.SrcReg[0].File = RC_FILE_INPUT; + inst_mul->U.I.SrcReg[0].Index = new_input; + + inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_mul->U.I.SrcReg[1].Index = tempregi; + inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW; + + /* viewport transformation */ + inst_mad = rc_insert_new_instruction(c, inst_mul); + inst_mad->U.I.Opcode = RC_OPCODE_MAD; + + inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mad->U.I.DstReg.Index = tempregi; + inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ; + + inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_mad->U.I.SrcReg[0].Index = tempregi; + inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0; + + inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + inst_mad->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0; + + inst_mad->U.I.SrcReg[2].File = RC_FILE_CONSTANT; + inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_XYZ0; + + if (full_vtransform) { + inst_mad->U.I.SrcReg[1].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_SCALE, 0); + inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_OFFSET, 0); + } else { + inst_mad->U.I.SrcReg[1].Index = + inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_WINDOW_DIMENSION, 0); + } + + for (inst = inst_mad->Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned i; + + for(i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT && + inst->U.I.SrcReg[i].Index == wpos) { + inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[i].Index = tempregi; + } + } + } +} + + +/** + * The FACE input in hardware contains 1 if it's a back face, 0 otherwise. + * Gallium and OpenGL define it the other way around. + * + * So let's just negate FACE at the beginning of the shader and rewrite the rest + * of the shader to read from the newly allocated temporary. + */ +void rc_transform_fragment_face(struct radeon_compiler *c, unsigned face) +{ + unsigned tempregi = rc_find_free_temporary(c); + struct rc_instruction *inst_add; + struct rc_instruction *inst; + + /* perspective divide */ + inst_add = rc_insert_new_instruction(c, &c->Program.Instructions); + inst_add->U.I.Opcode = RC_OPCODE_ADD; + + inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_add->U.I.DstReg.Index = tempregi; + inst_add->U.I.DstReg.WriteMask = RC_MASK_X; + + inst_add->U.I.SrcReg[0].File = RC_FILE_NONE; + inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111; + + inst_add->U.I.SrcReg[1].File = RC_FILE_INPUT; + inst_add->U.I.SrcReg[1].Index = face; + inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX; + inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZW; + + for (inst = inst_add->Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned i; + + for(i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT && + inst->U.I.SrcReg[i].Index == face) { + inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[i].Index = tempregi; + } + } + } +} + +static void reg_count_callback(void * userdata, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask) +{ + int *max_reg = userdata; + if (file == RC_FILE_TEMPORARY) + (int)index > *max_reg ? *max_reg = index : 0; +} + +void rc_get_stats(struct radeon_compiler *c, struct rc_program_stats *s) +{ + int max_reg = -1; + struct rc_instruction * tmp; + memset(s, 0, sizeof(*s)); + + for(tmp = c->Program.Instructions.Next; tmp != &c->Program.Instructions; + tmp = tmp->Next){ + const struct rc_opcode_info * info; + rc_for_all_reads_mask(tmp, reg_count_callback, &max_reg); + if (tmp->Type == RC_INSTRUCTION_NORMAL) { + info = rc_get_opcode_info(tmp->U.I.Opcode); + if (info->Opcode == RC_OPCODE_BEGIN_TEX) + continue; + if (tmp->U.I.PreSub.Opcode != RC_PRESUB_NONE) + s->num_presub_ops++; + } else { + if (tmp->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Used) + s->num_presub_ops++; + if (tmp->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Used) + s->num_presub_ops++; + /* Assuming alpha will never be a flow control or + * a tex instruction. */ + if (tmp->U.P.Alpha.Opcode != RC_OPCODE_NOP) + s->num_alpha_insts++; + if (tmp->U.P.RGB.Opcode != RC_OPCODE_NOP) + s->num_rgb_insts++; + info = rc_get_opcode_info(tmp->U.P.RGB.Opcode); + } + if (info->IsFlowControl) + s->num_fc_insts++; + if (info->HasTexture) + s->num_tex_insts++; + s->num_insts++; + } + s->num_temp_regs = max_reg + 1; +} + +static void print_stats(struct radeon_compiler * c) +{ + struct rc_program_stats s; + + if (c->initial_num_insts <= 5) + return; + + rc_get_stats(c, &s); + + switch (c->type) { + case RC_VERTEX_PROGRAM: + fprintf(stderr,"~~~~~~~~~ VERTEX PROGRAM ~~~~~~~~\n" + "~%4u Instructions\n" + "~%4u Flow Control Instructions\n" + "~%4u Temporary Registers\n" + "~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~\n", + s.num_insts, s.num_fc_insts, s.num_temp_regs); + break; + + case RC_FRAGMENT_PROGRAM: + fprintf(stderr,"~~~~~~~~ FRAGMENT PROGRAM ~~~~~~~\n" + "~%4u Instructions\n" + "~%4u Vector Instructions (RGB)\n" + "~%4u Scalar Instructions (Alpha)\n" + "~%4u Flow Control Instructions\n" + "~%4u Texture Instructions\n" + "~%4u Presub Operations\n" + "~%4u Temporary Registers\n" + "~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~\n", + s.num_insts, s.num_rgb_insts, s.num_alpha_insts, + s.num_fc_insts, s.num_tex_insts, s.num_presub_ops, + s.num_temp_regs); + break; + default: + assert(0); + } +} + +static const char *shader_name[RC_NUM_PROGRAM_TYPES] = { + "Vertex Program", + "Fragment Program" +}; + +void rc_run_compiler_passes(struct radeon_compiler *c, struct radeon_compiler_pass *list) +{ + for (unsigned i = 0; list[i].name; i++) { + if (list[i].predicate) { + list[i].run(c, list[i].user); + + if (c->Error) + return; + + if ((c->Debug & RC_DBG_LOG) && list[i].dump) { + fprintf(stderr, "%s: after '%s'\n", shader_name[c->type], list[i].name); + rc_print_program(&c->Program); + } + } + } +} + +/* Executes a list of compiler passes given in the parameter 'list'. */ +void rc_run_compiler(struct radeon_compiler *c, struct radeon_compiler_pass *list) +{ + struct rc_program_stats s; + + rc_get_stats(c, &s); + c->initial_num_insts = s.num_insts; + + if (c->Debug & RC_DBG_LOG) { + fprintf(stderr, "%s: before compilation\n", shader_name[c->type]); + rc_print_program(&c->Program); + } + + rc_run_compiler_passes(c, list); + + if (c->Debug & RC_DBG_STATS) + print_stats(c); +} + +void rc_validate_final_shader(struct radeon_compiler *c, void *user) +{ + /* Check the number of constants. */ + if (c->Program.Constants.Count > c->max_constants) { + rc_error(c, "Too many constants. Max: %i, Got: %i\n", + c->max_constants, c->Program.Constants.Count); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_compiler.h b/src/gallium/drivers/r300/compiler/radeon_compiler.h new file mode 100644 index 00000000000..74594af23c2 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_compiler.h @@ -0,0 +1,171 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#ifndef RADEON_COMPILER_H +#define RADEON_COMPILER_H + +#include "main/compiler.h" + +#include "memory_pool.h" +#include "radeon_code.h" +#include "radeon_program.h" +#include "radeon_emulate_loops.h" + +#define RC_DBG_LOG (1 << 0) +#define RC_DBG_STATS (1 << 1) + +struct rc_swizzle_caps; + +enum rc_program_type { + RC_VERTEX_PROGRAM, + RC_FRAGMENT_PROGRAM, + RC_NUM_PROGRAM_TYPES +}; + +struct radeon_compiler { + struct memory_pool Pool; + struct rc_program Program; + enum rc_program_type type; + unsigned Debug:2; + unsigned Error:1; + char * ErrorMsg; + + /* Hardware specification. */ + unsigned is_r400:1; + unsigned is_r500:1; + unsigned has_half_swizzles:1; + unsigned has_presub:1; + unsigned disable_optimizations:1; + unsigned max_temp_regs; + unsigned max_constants; + int max_alu_insts; + unsigned max_tex_insts; + + /* Whether to remove unused constants and empty holes in constant space. */ + unsigned remove_unused_constants:1; + + /** + * Variables used internally, not be touched by callers + * of the compiler + */ + /*@{*/ + struct rc_swizzle_caps * SwizzleCaps; + /*@}*/ + + struct emulate_loop_state loop_state; + + unsigned initial_num_insts; /* Number of instructions at start. */ +}; + +void rc_init(struct radeon_compiler * c); +void rc_destroy(struct radeon_compiler * c); + +void rc_debug(struct radeon_compiler * c, const char * fmt, ...); +void rc_error(struct radeon_compiler * c, const char * fmt, ...); + +int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion); + +/** + * This macro acts like an if-statement that can be used to implement + * non-aborting assertions in the compiler. + * + * It checks whether \p cond is true. If not, an internal compiler error is + * flagged and the if-clause is run. + * + * A typical use-case would be: + * + * if (rc_assert(c, condition-that-must-be-true)) + * return; + */ +#define rc_assert(c, cond) \ + (!(cond) && rc_if_fail_helper(c, __FILE__, __LINE__, #cond)) + +void rc_calculate_inputs_outputs(struct radeon_compiler * c); + +void rc_move_input(struct radeon_compiler * c, unsigned input, struct rc_src_register new_input); +void rc_move_output(struct radeon_compiler * c, unsigned output, unsigned new_output, unsigned writemask); +void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_output); +void rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsigned new_input, + int full_vtransform); +void rc_transform_fragment_face(struct radeon_compiler *c, unsigned face); + +struct r300_fragment_program_compiler { + struct radeon_compiler Base; + struct rX00_fragment_program_code *code; + /* Optional transformations and features. */ + struct r300_fragment_program_external_state state; + unsigned enable_shadow_ambient; + /* Register corresponding to the depthbuffer. */ + unsigned OutputDepth; + /* Registers corresponding to the four colorbuffers. */ + unsigned OutputColor[4]; + + void * UserData; + void (*AllocateHwInputs)( + struct r300_fragment_program_compiler * c, + void (*allocate)(void * data, unsigned input, unsigned hwreg), + void * mydata); +}; + +void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c); + +struct r300_vertex_program_compiler { + struct radeon_compiler Base; + struct r300_vertex_program_code *code; + uint32_t RequiredOutputs; + + void * UserData; + void (*SetHwInputOutput)(struct r300_vertex_program_compiler * c); + + int PredicateIndex; + unsigned int PredicateMask; +}; + +void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* c); +void r300_vertex_program_dump(struct radeon_compiler *compiler, void *user); + +struct radeon_compiler_pass { + const char *name; /* Name of the pass. */ + int dump; /* Dump the program if Debug == 1? */ + int predicate; /* Run this pass? */ + void (*run)(struct radeon_compiler *c, void *user); /* The main entrypoint. */ + void *user; /* Optional parameter which is passed to the run function. */ +}; + +struct rc_program_stats { + unsigned num_insts; + unsigned num_fc_insts; + unsigned num_tex_insts; + unsigned num_rgb_insts; + unsigned num_alpha_insts; + unsigned num_presub_ops; + unsigned num_temp_regs; +}; + +void rc_get_stats(struct radeon_compiler *c, struct rc_program_stats *s); + +/* Executes a list of compiler passes given in the parameter 'list'. */ +void rc_run_compiler_passes(struct radeon_compiler *c, struct radeon_compiler_pass *list); +void rc_run_compiler(struct radeon_compiler *c, struct radeon_compiler_pass *list); +void rc_validate_final_shader(struct radeon_compiler *c, void *user); + +#endif /* RADEON_COMPILER_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_compiler_util.c b/src/gallium/drivers/r300/compiler/radeon_compiler_util.c new file mode 100644 index 00000000000..2742721f800 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_compiler_util.c @@ -0,0 +1,701 @@ +/* + * Copyright 2010 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * \file + */ + +#include "radeon_compiler_util.h" + +#include "radeon_compiler.h" +#include "radeon_dataflow.h" +/** + */ +unsigned int rc_swizzle_to_writemask(unsigned int swz) +{ + unsigned int mask = 0; + unsigned int i; + + for(i = 0; i < 4; i++) { + mask |= 1 << GET_SWZ(swz, i); + } + mask &= RC_MASK_XYZW; + + return mask; +} + +rc_swizzle get_swz(unsigned int swz, rc_swizzle idx) +{ + if (idx & 0x4) + return idx; + return GET_SWZ(swz, idx); +} + +/** + * The purpose of this function is to standardize the number channels used by + * swizzles. All swizzles regardless of what instruction they are a part of + * should have 4 channels initialized with values. + * @param channels The number of channels in initial_value that have a + * meaningful value. + * @return An initialized swizzle that has all of the unused channels set to + * RC_SWIZZLE_UNUSED. + */ +unsigned int rc_init_swizzle(unsigned int initial_value, unsigned int channels) +{ + unsigned int i; + for (i = channels; i < 4; i++) { + SET_SWZ(initial_value, i, RC_SWIZZLE_UNUSED); + } + return initial_value; +} + +unsigned int combine_swizzles4(unsigned int src, + rc_swizzle swz_x, rc_swizzle swz_y, rc_swizzle swz_z, rc_swizzle swz_w) +{ + unsigned int ret = 0; + + ret |= get_swz(src, swz_x); + ret |= get_swz(src, swz_y) << 3; + ret |= get_swz(src, swz_z) << 6; + ret |= get_swz(src, swz_w) << 9; + + return ret; +} + +unsigned int combine_swizzles(unsigned int src, unsigned int swz) +{ + unsigned int ret = 0; + + ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_X)); + ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Y)) << 3; + ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Z)) << 6; + ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_W)) << 9; + + return ret; +} + +/** + * @param mask Must be either RC_MASK_X, RC_MASK_Y, RC_MASK_Z, or RC_MASK_W + */ +rc_swizzle rc_mask_to_swizzle(unsigned int mask) +{ + switch (mask) { + case RC_MASK_X: return RC_SWIZZLE_X; + case RC_MASK_Y: return RC_SWIZZLE_Y; + case RC_MASK_Z: return RC_SWIZZLE_Z; + case RC_MASK_W: return RC_SWIZZLE_W; + } + return RC_SWIZZLE_UNUSED; +} + +/* Reorder mask bits according to swizzle. */ +unsigned swizzle_mask(unsigned swizzle, unsigned mask) +{ + unsigned ret = 0; + for (unsigned chan = 0; chan < 4; ++chan) { + unsigned swz = GET_SWZ(swizzle, chan); + if (swz < 4) + ret |= GET_BIT(mask, swz) << chan; + } + return ret; +} + +static unsigned int srcs_need_rewrite(const struct rc_opcode_info * info) +{ + if (info->HasTexture) { + return 0; + } + switch (info->Opcode) { + case RC_OPCODE_DP2: + case RC_OPCODE_DP3: + case RC_OPCODE_DP4: + case RC_OPCODE_DDX: + case RC_OPCODE_DDY: + return 0; + default: + return 1; + } +} + +/** + * @return A swizzle the results from converting old_swizzle using + * conversion_swizzle + */ +unsigned int rc_adjust_channels( + unsigned int old_swizzle, + unsigned int conversion_swizzle) +{ + unsigned int i; + unsigned int new_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0); + for (i = 0; i < 4; i++) { + unsigned int new_chan = get_swz(conversion_swizzle, i); + if (new_chan == RC_SWIZZLE_UNUSED) { + continue; + } + SET_SWZ(new_swizzle, new_chan, GET_SWZ(old_swizzle, i)); + } + return new_swizzle; +} + +static unsigned int rewrite_writemask( + unsigned int old_mask, + unsigned int conversion_swizzle) +{ + unsigned int new_mask = 0; + unsigned int i; + + for (i = 0; i < 4; i++) { + if (!GET_BIT(old_mask, i) + || GET_SWZ(conversion_swizzle, i) == RC_SWIZZLE_UNUSED) { + continue; + } + new_mask |= (1 << GET_SWZ(conversion_swizzle, i)); + } + + return new_mask; +} + +/** + * This function rewrites the writemask of sub and adjusts the swizzles + * of all its source registers based on the conversion_swizzle. + * conversion_swizzle represents a mapping of the old writemask to the + * new writemask. For a detailed description of how conversion swizzles + * work see rc_rewrite_swizzle(). + */ +void rc_pair_rewrite_writemask( + struct rc_pair_sub_instruction * sub, + unsigned int conversion_swizzle) +{ + const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); + unsigned int i; + + sub->WriteMask = rewrite_writemask(sub->WriteMask, conversion_swizzle); + + if (!srcs_need_rewrite(info)) { + return ; + } + + for (i = 0; i < info->NumSrcRegs; i++) { + sub->Arg[i].Swizzle = + rc_adjust_channels(sub->Arg[i].Swizzle, + conversion_swizzle); + } +} + +static void normal_rewrite_writemask_cb( + void * userdata, + struct rc_instruction * inst, + struct rc_src_register * src) +{ + unsigned int * new_mask = (unsigned int *)userdata; + src->Swizzle = rc_adjust_channels(src->Swizzle, *new_mask); +} + +/** + * This function is the same as rc_pair_rewrite_writemask() except it + * operates on normal instructions. + */ +void rc_normal_rewrite_writemask( + struct rc_instruction * inst, + unsigned int conversion_swizzle) +{ + unsigned int new_mask; + struct rc_sub_instruction * sub = &inst->U.I; + const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); + sub->DstReg.WriteMask = + rewrite_writemask(sub->DstReg.WriteMask, conversion_swizzle); + + if (info->HasTexture) { + unsigned int i; + assert(sub->TexSwizzle == RC_SWIZZLE_XYZW); + for (i = 0; i < 4; i++) { + unsigned int swz = GET_SWZ(conversion_swizzle, i); + if (swz > 3) + continue; + SET_SWZ(sub->TexSwizzle, swz, i); + } + } + + if (!srcs_need_rewrite(info)) { + return; + } + + new_mask = sub->DstReg.WriteMask; + rc_for_all_reads_src(inst, normal_rewrite_writemask_cb, &new_mask); +} + +/** + * This function replaces each value 'swz' in swizzle with the value of + * GET_SWZ(conversion_swizzle, swz). So, if you want to change all the X's + * in swizzle to Y, then conversion_swizzle should be Y___ (0xff9). If you want + * to change all the Y's in swizzle to X, then conversion_swizzle should be + * _X__ (0xfc7). If you want to change the Y's to X and the X's to Y, then + * conversion swizzle should be YX__ (0xfc1). + * @param swizzle The swizzle to change + * @param conversion_swizzle Describes the conversion to perform on the swizzle + * @return A converted swizzle + */ +unsigned int rc_rewrite_swizzle( + unsigned int swizzle, + unsigned int conversion_swizzle) +{ + unsigned int chan; + unsigned int out_swizzle = swizzle; + + for (chan = 0; chan < 4; chan++) { + unsigned int swz = GET_SWZ(swizzle, chan); + unsigned int new_swz; + if (swz > 3) { + SET_SWZ(out_swizzle, chan, swz); + } else { + new_swz = GET_SWZ(conversion_swizzle, swz); + if (new_swz != RC_SWIZZLE_UNUSED) { + SET_SWZ(out_swizzle, chan, new_swz); + } else { + SET_SWZ(out_swizzle, chan, swz); + } + } + } + return out_swizzle; +} + +/** + * Left multiplication of a register with a swizzle + */ +struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg) +{ + struct rc_src_register tmp = srcreg; + int i; + tmp.Swizzle = 0; + tmp.Negate = 0; + for(i = 0; i < 4; ++i) { + rc_swizzle swz = GET_SWZ(swizzle, i); + if (swz < 4) { + tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3); + tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i; + } else { + tmp.Swizzle |= swz << (i*3); + } + } + return tmp; +} + +void reset_srcreg(struct rc_src_register* reg) +{ + memset(reg, 0, sizeof(struct rc_src_register)); + reg->Swizzle = RC_SWIZZLE_XYZW; +} + +unsigned int rc_src_reads_dst_mask( + rc_register_file src_file, + unsigned int src_idx, + unsigned int src_swz, + rc_register_file dst_file, + unsigned int dst_idx, + unsigned int dst_mask) +{ + if (src_file != dst_file || src_idx != dst_idx) { + return RC_MASK_NONE; + } + return dst_mask & rc_swizzle_to_writemask(src_swz); +} + +/** + * @return A bit mask specifying whether this swizzle will select from an RGB + * source, an Alpha source, or both. + */ +unsigned int rc_source_type_swz(unsigned int swizzle) +{ + unsigned int chan; + unsigned int swz = RC_SWIZZLE_UNUSED; + unsigned int ret = RC_SOURCE_NONE; + + for(chan = 0; chan < 4; chan++) { + swz = GET_SWZ(swizzle, chan); + if (swz == RC_SWIZZLE_W) { + ret |= RC_SOURCE_ALPHA; + } else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y + || swz == RC_SWIZZLE_Z) { + ret |= RC_SOURCE_RGB; + } + } + return ret; +} + +unsigned int rc_source_type_mask(unsigned int mask) +{ + unsigned int ret = RC_SOURCE_NONE; + + if (mask & RC_MASK_XYZ) + ret |= RC_SOURCE_RGB; + + if (mask & RC_MASK_W) + ret |= RC_SOURCE_ALPHA; + + return ret; +} + +struct src_select { + rc_register_file File; + int Index; + unsigned int SrcType; +}; + +struct can_use_presub_data { + struct src_select Selects[5]; + unsigned int SelectCount; + const struct rc_src_register * ReplaceReg; + unsigned int ReplaceRemoved; +}; + +static void can_use_presub_data_add_select( + struct can_use_presub_data * data, + rc_register_file file, + unsigned int index, + unsigned int src_type) +{ + struct src_select * select; + + select = &data->Selects[data->SelectCount++]; + select->File = file; + select->Index = index; + select->SrcType = src_type; +} + +/** + * This callback function counts the number of sources in inst that are + * different from the sources in can_use_presub_data->RemoveSrcs. + */ +static void can_use_presub_read_cb( + void * userdata, + struct rc_instruction * inst, + struct rc_src_register * src) +{ + struct can_use_presub_data * d = userdata; + + if (!d->ReplaceRemoved && src == d->ReplaceReg) { + d->ReplaceRemoved = 1; + return; + } + + if (src->File == RC_FILE_NONE) + return; + + can_use_presub_data_add_select(d, src->File, src->Index, + rc_source_type_swz(src->Swizzle)); +} + +unsigned int rc_inst_can_use_presub( + struct rc_instruction * inst, + rc_presubtract_op presub_op, + unsigned int presub_writemask, + const struct rc_src_register * replace_reg, + const struct rc_src_register * presub_src0, + const struct rc_src_register * presub_src1) +{ + struct can_use_presub_data d; + unsigned int num_presub_srcs; + unsigned int i; + const struct rc_opcode_info * info = + rc_get_opcode_info(inst->U.I.Opcode); + int rgb_count = 0, alpha_count = 0; + unsigned int src_type0, src_type1; + + if (presub_op == RC_PRESUB_NONE) { + return 1; + } + + if (info->HasTexture) { + return 0; + } + + /* We can't use more than one presubtract value in an + * instruction, unless the two prsubtract operations + * are the same and read from the same registers. + * XXX For now we will limit instructions to only one presubtract + * value.*/ + if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) { + return 0; + } + + memset(&d, 0, sizeof(d)); + d.ReplaceReg = replace_reg; + + rc_for_all_reads_src(inst, can_use_presub_read_cb, &d); + + num_presub_srcs = rc_presubtract_src_reg_count(presub_op); + + src_type0 = rc_source_type_swz(presub_src0->Swizzle); + can_use_presub_data_add_select(&d, + presub_src0->File, + presub_src0->Index, + src_type0); + + if (num_presub_srcs > 1) { + src_type1 = rc_source_type_swz(presub_src1->Swizzle); + can_use_presub_data_add_select(&d, + presub_src1->File, + presub_src1->Index, + src_type1); + + /* Even if both of the presub sources read from the same + * register, we still need to use 2 different source selects + * for them, so we need to increment the count to compensate. + */ + if (presub_src0->File == presub_src1->File + && presub_src0->Index == presub_src1->Index) { + if (src_type0 & src_type1 & RC_SOURCE_RGB) { + rgb_count++; + } + if (src_type0 & src_type1 & RC_SOURCE_ALPHA) { + alpha_count++; + } + } + } + + /* Count the number of source selects for Alpha and RGB. If we + * encounter two of the same source selects then we can ignore the + * first one. */ + for (i = 0; i < d.SelectCount; i++) { + unsigned int j; + unsigned int src_type = d.Selects[i].SrcType; + for (j = i + 1; j < d.SelectCount; j++) { + if (d.Selects[i].File == d.Selects[j].File + && d.Selects[i].Index == d.Selects[j].Index) { + src_type &= ~d.Selects[j].SrcType; + } + } + if (src_type & RC_SOURCE_RGB) { + rgb_count++; + } + + if (src_type & RC_SOURCE_ALPHA) { + alpha_count++; + } + } + + if (rgb_count > 3 || alpha_count > 3) { + return 0; + } + + return 1; +} + +struct max_data { + unsigned int Max; + unsigned int HasFileType; + rc_register_file File; +}; + +static void max_callback( + void * userdata, + struct rc_instruction * inst, + rc_register_file file, + unsigned int index, + unsigned int mask) +{ + struct max_data * d = (struct max_data*)userdata; + if (file == d->File && (!d->HasFileType || index > d->Max)) { + d->Max = index; + d->HasFileType = 1; + } +} + +/** + * @return The maximum index of the specified register file used by the + * program. + */ +int rc_get_max_index( + struct radeon_compiler * c, + rc_register_file file) +{ + struct max_data data; + struct rc_instruction * inst; + data.Max = 0; + data.HasFileType = 0; + data.File = file; + for (inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next) { + rc_for_all_reads_mask(inst, max_callback, &data); + rc_for_all_writes_mask(inst, max_callback, &data); + } + if (!data.HasFileType) { + return -1; + } else { + return data.Max; + } +} + +static unsigned int get_source_readmask( + struct rc_pair_sub_instruction * sub, + unsigned int source, + unsigned int src_type) +{ + unsigned int i; + unsigned int readmask = 0; + const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); + + for (i = 0; i < info->NumSrcRegs; i++) { + if (sub->Arg[i].Source != source + || src_type != rc_source_type_swz(sub->Arg[i].Swizzle)) { + continue; + } + readmask |= rc_swizzle_to_writemask(sub->Arg[i].Swizzle); + } + return readmask; +} + +/** + * This function attempts to remove a source from a pair instructions. + * @param inst + * @param src_type RC_SOURCE_RGB, RC_SOURCE_ALPHA, or both bitwise or'd + * @param source The index of the source to remove + * @param new_readmask A mask representing the components that are read by + * the source that is intended to replace the one you are removing. If you + * want to remove a source only and not replace it, this parameter should be + * zero. + * @return 1 if the source was successfully removed, 0 if it was not + */ +unsigned int rc_pair_remove_src( + struct rc_instruction * inst, + unsigned int src_type, + unsigned int source, + unsigned int new_readmask) +{ + unsigned int readmask = 0; + + readmask |= get_source_readmask(&inst->U.P.RGB, source, src_type); + readmask |= get_source_readmask(&inst->U.P.Alpha, source, src_type); + + if ((new_readmask & readmask) != readmask) + return 0; + + if (src_type & RC_SOURCE_RGB) { + memset(&inst->U.P.RGB.Src[source], 0, + sizeof(struct rc_pair_instruction_source)); + } + + if (src_type & RC_SOURCE_ALPHA) { + memset(&inst->U.P.Alpha.Src[source], 0, + sizeof(struct rc_pair_instruction_source)); + } + + return 1; +} + +/** + * @return RC_OPCODE_NOOP if inst is not a flow control instruction. + * @return The opcode of inst if it is a flow control instruction. + */ +rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst) +{ + const struct rc_opcode_info * info; + if (inst->Type == RC_INSTRUCTION_NORMAL) { + info = rc_get_opcode_info(inst->U.I.Opcode); + } else { + info = rc_get_opcode_info(inst->U.P.RGB.Opcode); + /*A flow control instruction shouldn't have an alpha + * instruction.*/ + assert(!info->IsFlowControl || + inst->U.P.Alpha.Opcode == RC_OPCODE_NOP); + } + + if (info->IsFlowControl) + return info->Opcode; + else + return RC_OPCODE_NOP; + +} + +/** + * @return The BGNLOOP instruction that starts the loop ended by endloop. + */ +struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop) +{ + unsigned int endloop_count = 0; + struct rc_instruction * inst; + for (inst = endloop->Prev; inst != endloop; inst = inst->Prev) { + rc_opcode op = rc_get_flow_control_inst(inst); + if (op == RC_OPCODE_ENDLOOP) { + endloop_count++; + } else if (op == RC_OPCODE_BGNLOOP) { + if (endloop_count == 0) { + return inst; + } else { + endloop_count--; + } + } + } + return NULL; +} + +/** + * @return The ENDLOOP instruction that ends the loop started by bgnloop. + */ +struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop) +{ + unsigned int bgnloop_count = 0; + struct rc_instruction * inst; + for (inst = bgnloop->Next; inst!=bgnloop; inst = inst->Next) { + rc_opcode op = rc_get_flow_control_inst(inst); + if (op == RC_OPCODE_BGNLOOP) { + bgnloop_count++; + } else if (op == RC_OPCODE_ENDLOOP) { + if (bgnloop_count == 0) { + return inst; + } else { + bgnloop_count--; + } + } + } + return NULL; +} + +/** + * @return A conversion swizzle for converting from old_mask->new_mask + */ +unsigned int rc_make_conversion_swizzle( + unsigned int old_mask, + unsigned int new_mask) +{ + unsigned int conversion_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0); + unsigned int old_idx; + unsigned int new_idx = 0; + for (old_idx = 0; old_idx < 4; old_idx++) { + if (!GET_BIT(old_mask, old_idx)) + continue; + for ( ; new_idx < 4; new_idx++) { + if (GET_BIT(new_mask, new_idx)) { + SET_SWZ(conversion_swizzle, old_idx, new_idx); + new_idx++; + break; + } + } + } + return conversion_swizzle; +} diff --git a/src/gallium/drivers/r300/compiler/radeon_compiler_util.h b/src/gallium/drivers/r300/compiler/radeon_compiler_util.h new file mode 100644 index 00000000000..3730aa888c0 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_compiler_util.h @@ -0,0 +1,89 @@ +#include "radeon_program_constants.h" + +#ifndef RADEON_PROGRAM_UTIL_H +#define RADEON_PROGRAM_UTIL_H + +#include "radeon_opcodes.h" + +struct radeon_compiler; +struct rc_instruction; +struct rc_pair_instruction; +struct rc_pair_sub_instruction; +struct rc_src_register; + +unsigned int rc_swizzle_to_writemask(unsigned int swz); + +rc_swizzle get_swz(unsigned int swz, rc_swizzle idx); + +unsigned int rc_init_swizzle(unsigned int initial_value, unsigned int channels); + +unsigned int combine_swizzles4(unsigned int src, + rc_swizzle swz_x, rc_swizzle swz_y, + rc_swizzle swz_z, rc_swizzle swz_w); + +unsigned int combine_swizzles(unsigned int src, unsigned int swz); + +rc_swizzle rc_mask_to_swizzle(unsigned int mask); + +unsigned swizzle_mask(unsigned swizzle, unsigned mask); + +unsigned int rc_adjust_channels( + unsigned int old_swizzle, + unsigned int conversion_swizzle); + +void rc_pair_rewrite_writemask( + struct rc_pair_sub_instruction * sub, + unsigned int conversion_swizzle); + +void rc_normal_rewrite_writemask( + struct rc_instruction * inst, + unsigned int conversion_swizzle); + +unsigned int rc_rewrite_swizzle( + unsigned int swizzle, + unsigned int new_mask); + +struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg); + +void reset_srcreg(struct rc_src_register* reg); + +unsigned int rc_src_reads_dst_mask( + rc_register_file src_file, + unsigned int src_idx, + unsigned int src_swz, + rc_register_file dst_file, + unsigned int dst_idx, + unsigned int dst_mask); + +unsigned int rc_source_type_swz(unsigned int swizzle); + +unsigned int rc_source_type_mask(unsigned int mask); + +unsigned int rc_inst_can_use_presub( + struct rc_instruction * inst, + rc_presubtract_op presub_op, + unsigned int presub_writemask, + const struct rc_src_register * replace_reg, + const struct rc_src_register * presub_src0, + const struct rc_src_register * presub_src1); + +int rc_get_max_index( + struct radeon_compiler * c, + rc_register_file file); + +unsigned int rc_pair_remove_src( + struct rc_instruction * inst, + unsigned int src_type, + unsigned int source, + unsigned int new_readmask); + +rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst); + +struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop); +struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop); + +unsigned int rc_make_conversion_swizzle( + unsigned int old_mask, + unsigned int new_mask); + +#endif /* RADEON_PROGRAM_UTIL_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_dataflow.c b/src/gallium/drivers/r300/compiler/radeon_dataflow.c new file mode 100644 index 00000000000..a8decacedaf --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_dataflow.c @@ -0,0 +1,892 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * Copyright 2010 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_dataflow.h" + +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" +#include "radeon_program.h" + +struct read_write_mask_data { + void * UserData; + rc_read_write_mask_fn Cb; +}; + +static void reads_normal_callback( + void * userdata, + struct rc_instruction * fullinst, + struct rc_src_register * src) +{ + struct read_write_mask_data * cb_data = userdata; + unsigned int refmask = 0; + unsigned int chan; + for(chan = 0; chan < 4; chan++) { + refmask |= 1 << GET_SWZ(src->Swizzle, chan); + } + refmask &= RC_MASK_XYZW; + + if (refmask) { + cb_data->Cb(cb_data->UserData, fullinst, src->File, + src->Index, refmask); + } + + if (refmask && src->RelAddr) { + cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0, + RC_MASK_X); + } +} + +static void pair_get_src_refmasks(unsigned int * refmasks, + struct rc_pair_instruction * inst, + unsigned int swz, unsigned int src) +{ + if (swz >= 4) + return; + + if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) { + if(src == RC_PAIR_PRESUB_SRC) { + unsigned int i; + int srcp_regs = + rc_presubtract_src_reg_count( + inst->RGB.Src[src].Index); + for(i = 0; i < srcp_regs; i++) { + refmasks[i] |= 1 << swz; + } + } + else { + refmasks[src] |= 1 << swz; + } + } + + if (swz == RC_SWIZZLE_W) { + if (src == RC_PAIR_PRESUB_SRC) { + unsigned int i; + int srcp_regs = rc_presubtract_src_reg_count( + inst->Alpha.Src[src].Index); + for(i = 0; i < srcp_regs; i++) { + refmasks[i] |= 1 << swz; + } + } + else { + refmasks[src] |= 1 << swz; + } + } +} + +static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) +{ + struct rc_pair_instruction * inst = &fullinst->U.P; + unsigned int refmasks[3] = { 0, 0, 0 }; + + unsigned int arg; + + for(arg = 0; arg < 3; ++arg) { + unsigned int chan; + for(chan = 0; chan < 3; ++chan) { + unsigned int swz_rgb = + GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan); + unsigned int swz_alpha = + GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan); + pair_get_src_refmasks(refmasks, inst, swz_rgb, + inst->RGB.Arg[arg].Source); + pair_get_src_refmasks(refmasks, inst, swz_alpha, + inst->Alpha.Arg[arg].Source); + } + } + + for(unsigned int src = 0; src < 3; ++src) { + if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ)) + cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index, + refmasks[src] & RC_MASK_XYZ); + + if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W)) + cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W); + } +} + +static void pair_sub_for_all_args( + struct rc_instruction * fullinst, + struct rc_pair_sub_instruction * sub, + rc_pair_read_arg_fn cb, + void * userdata) +{ + int i; + const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); + + for(i = 0; i < info->NumSrcRegs; i++) { + unsigned int src_type; + + src_type = rc_source_type_swz(sub->Arg[i].Swizzle); + + if (src_type == RC_SOURCE_NONE) + continue; + + if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) { + unsigned int presub_type; + unsigned int presub_src_count; + struct rc_pair_instruction_source * src_array; + unsigned int j; + + if (src_type & RC_SOURCE_RGB) { + presub_type = fullinst-> + U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index; + src_array = fullinst->U.P.RGB.Src; + } else { + presub_type = fullinst-> + U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index; + src_array = fullinst->U.P.Alpha.Src; + } + presub_src_count + = rc_presubtract_src_reg_count(presub_type); + for(j = 0; j < presub_src_count; j++) { + cb(userdata, fullinst, &sub->Arg[i], + &src_array[j]); + } + } else { + struct rc_pair_instruction_source * src = + rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]); + if (src) { + cb(userdata, fullinst, &sub->Arg[i], src); + } + } + } +} + +/* This function calls the callback function (cb) for each source used by + * the instruction. + * */ +void rc_for_all_reads_src( + struct rc_instruction * inst, + rc_read_src_fn cb, + void * userdata) +{ + const struct rc_opcode_info * opcode = + rc_get_opcode_info(inst->U.I.Opcode); + + /* This function only works with normal instructions. */ + if (inst->Type != RC_INSTRUCTION_NORMAL) { + assert(0); + return; + } + + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { + + if (inst->U.I.SrcReg[src].File == RC_FILE_NONE) + continue; + + if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) { + unsigned int i; + unsigned int srcp_regs = rc_presubtract_src_reg_count( + inst->U.I.PreSub.Opcode); + for( i = 0; i < srcp_regs; i++) { + cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]); + } + } else { + cb(userdata, inst, &inst->U.I.SrcReg[src]); + } + } +} + +/** + * This function calls the callback function (cb) for each arg of the RGB and + * alpha components. + */ +void rc_pair_for_all_reads_arg( + struct rc_instruction * inst, + rc_pair_read_arg_fn cb, + void * userdata) +{ + /* This function only works with pair instructions. */ + if (inst->Type != RC_INSTRUCTION_PAIR) { + assert(0); + return; + } + + pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata); + pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata); +} + +/** + * Calls a callback function for all register reads. + * + * This is conservative, i.e. if the same register is referenced multiple times, + * the callback may also be called multiple times. + * Also, the writemask of the instruction is not taken into account. + */ +void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata) +{ + if (inst->Type == RC_INSTRUCTION_NORMAL) { + struct read_write_mask_data cb_data; + cb_data.UserData = userdata; + cb_data.Cb = cb; + + rc_for_all_reads_src(inst, reads_normal_callback, &cb_data); + } else { + reads_pair(inst, cb, userdata); + } +} + + + +static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) +{ + struct rc_sub_instruction * inst = &fullinst->U.I; + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); + + if (opcode->HasDstReg && inst->DstReg.WriteMask) + cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask); + + if (inst->WriteALUResult) + cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X); +} + +static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) +{ + struct rc_pair_instruction * inst = &fullinst->U.P; + + if (inst->RGB.WriteMask) + cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask); + + if (inst->Alpha.WriteMask) + cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W); + + if (inst->WriteALUResult) + cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X); +} + +/** + * Calls a callback function for all register writes in the instruction, + * reporting writemasks to the callback function. + * + * \warning Does not report output registers for paired instructions! + */ +void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata) +{ + if (inst->Type == RC_INSTRUCTION_NORMAL) { + writes_normal(inst, cb, userdata); + } else { + writes_pair(inst, cb, userdata); + } +} + + +struct mask_to_chan_data { + void * UserData; + rc_read_write_chan_fn Fn; +}; + +static void mask_to_chan_cb(void * data, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask) +{ + struct mask_to_chan_data * d = data; + for(unsigned int chan = 0; chan < 4; ++chan) { + if (GET_BIT(mask, chan)) + d->Fn(d->UserData, inst, file, index, chan); + } +} + +/** + * Calls a callback function for all sourced register channels. + * + * This is conservative, i.e. channels may be called multiple times, + * and the writemask of the instruction is not taken into account. + */ +void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata) +{ + struct mask_to_chan_data d; + d.UserData = userdata; + d.Fn = cb; + rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d); +} + +/** + * Calls a callback function for all written register channels. + * + * \warning Does not report output registers for paired instructions! + */ +void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata) +{ + struct mask_to_chan_data d; + d.UserData = userdata; + d.Fn = cb; + rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d); +} + +static void remap_normal_instruction(struct rc_instruction * fullinst, + rc_remap_register_fn cb, void * userdata) +{ + struct rc_sub_instruction * inst = &fullinst->U.I; + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); + unsigned int remapped_presub = 0; + + if (opcode->HasDstReg) { + rc_register_file file = inst->DstReg.File; + unsigned int index = inst->DstReg.Index; + + cb(userdata, fullinst, &file, &index); + + inst->DstReg.File = file; + inst->DstReg.Index = index; + } + + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { + rc_register_file file = inst->SrcReg[src].File; + unsigned int index = inst->SrcReg[src].Index; + + if (file == RC_FILE_PRESUB) { + unsigned int i; + unsigned int srcp_srcs = rc_presubtract_src_reg_count( + inst->PreSub.Opcode); + /* Make sure we only remap presubtract sources once in + * case more than one source register reads the + * presubtract result. */ + if (remapped_presub) + continue; + + for(i = 0; i < srcp_srcs; i++) { + file = inst->PreSub.SrcReg[i].File; + index = inst->PreSub.SrcReg[i].Index; + cb(userdata, fullinst, &file, &index); + inst->PreSub.SrcReg[i].File = file; + inst->PreSub.SrcReg[i].Index = index; + } + remapped_presub = 1; + } + else { + cb(userdata, fullinst, &file, &index); + + inst->SrcReg[src].File = file; + inst->SrcReg[src].Index = index; + } + } +} + +static void remap_pair_instruction(struct rc_instruction * fullinst, + rc_remap_register_fn cb, void * userdata) +{ + struct rc_pair_instruction * inst = &fullinst->U.P; + + if (inst->RGB.WriteMask) { + rc_register_file file = RC_FILE_TEMPORARY; + unsigned int index = inst->RGB.DestIndex; + + cb(userdata, fullinst, &file, &index); + + inst->RGB.DestIndex = index; + } + + if (inst->Alpha.WriteMask) { + rc_register_file file = RC_FILE_TEMPORARY; + unsigned int index = inst->Alpha.DestIndex; + + cb(userdata, fullinst, &file, &index); + + inst->Alpha.DestIndex = index; + } + + for(unsigned int src = 0; src < 3; ++src) { + if (inst->RGB.Src[src].Used) { + rc_register_file file = inst->RGB.Src[src].File; + unsigned int index = inst->RGB.Src[src].Index; + + cb(userdata, fullinst, &file, &index); + + inst->RGB.Src[src].File = file; + inst->RGB.Src[src].Index = index; + } + + if (inst->Alpha.Src[src].Used) { + rc_register_file file = inst->Alpha.Src[src].File; + unsigned int index = inst->Alpha.Src[src].Index; + + cb(userdata, fullinst, &file, &index); + + inst->Alpha.Src[src].File = file; + inst->Alpha.Src[src].Index = index; + } + } +} + + +/** + * Remap all register accesses according to the given function. + * That is, call the function \p cb for each referenced register (both read and written) + * and update the given instruction \p inst accordingly + * if it modifies its \ref pfile and \ref pindex contents. + */ +void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata) +{ + if (inst->Type == RC_INSTRUCTION_NORMAL) + remap_normal_instruction(inst, cb, userdata); + else + remap_pair_instruction(inst, cb, userdata); +} + +struct branch_write_mask { + unsigned int IfWriteMask:4; + unsigned int ElseWriteMask:4; + unsigned int HasElse:1; +}; + +union get_readers_read_cb { + rc_read_src_fn I; + rc_pair_read_arg_fn P; +}; + +struct get_readers_callback_data { + struct radeon_compiler * C; + struct rc_reader_data * ReaderData; + rc_read_src_fn ReadNormalCB; + rc_pair_read_arg_fn ReadPairCB; + rc_read_write_mask_fn WriteCB; + rc_register_file DstFile; + unsigned int DstIndex; + unsigned int DstMask; + unsigned int AliveWriteMask; + /* For convenience, this is indexed starting at 1 */ + struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1]; +}; + +static struct rc_reader * add_reader( + struct memory_pool * pool, + struct rc_reader_data * data, + struct rc_instruction * inst, + unsigned int mask) +{ + struct rc_reader * new; + memory_pool_array_reserve(pool, struct rc_reader, data->Readers, + data->ReaderCount, data->ReadersReserved, 1); + new = &data->Readers[data->ReaderCount++]; + new->Inst = inst; + new->WriteMask = mask; + return new; +} + +static void add_reader_normal( + struct memory_pool * pool, + struct rc_reader_data * data, + struct rc_instruction * inst, + unsigned int mask, + struct rc_src_register * src) +{ + struct rc_reader * new = add_reader(pool, data, inst, mask); + new->U.I.Src = src; +} + + +static void add_reader_pair( + struct memory_pool * pool, + struct rc_reader_data * data, + struct rc_instruction * inst, + unsigned int mask, + struct rc_pair_instruction_arg * arg, + struct rc_pair_instruction_source * src) +{ + struct rc_reader * new = add_reader(pool, data, inst, mask); + new->U.P.Src = src; + new->U.P.Arg = arg; +} + +static unsigned int get_readers_read_callback( + struct get_readers_callback_data * cb_data, + unsigned int has_rel_addr, + rc_register_file file, + unsigned int index, + unsigned int swizzle) +{ + unsigned int shared_mask, read_mask; + + if (has_rel_addr) { + cb_data->ReaderData->Abort = 1; + return RC_MASK_NONE; + } + + shared_mask = rc_src_reads_dst_mask(file, index, swizzle, + cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask); + + if (shared_mask == RC_MASK_NONE) + return shared_mask; + + /* If we make it this far, it means that this source reads from the + * same register written to by d->ReaderData->Writer. */ + + read_mask = rc_swizzle_to_writemask(swizzle); + if (cb_data->ReaderData->AbortOnRead & read_mask) { + cb_data->ReaderData->Abort = 1; + return shared_mask; + } + + if (cb_data->ReaderData->LoopDepth > 0) { + cb_data->ReaderData->AbortOnWrite |= + (read_mask & cb_data->AliveWriteMask); + } + + /* XXX The behavior in this case should be configurable. */ + if ((read_mask & cb_data->AliveWriteMask) != read_mask) { + cb_data->ReaderData->Abort = 1; + return shared_mask; + } + + return shared_mask; +} + +static void get_readers_pair_read_callback( + void * userdata, + struct rc_instruction * inst, + struct rc_pair_instruction_arg * arg, + struct rc_pair_instruction_source * src) +{ + unsigned int shared_mask; + struct get_readers_callback_data * d = userdata; + + shared_mask = get_readers_read_callback(d, + 0 /*Pair Instructions don't use RelAddr*/, + src->File, src->Index, arg->Swizzle); + + if (shared_mask == RC_MASK_NONE) + return; + + if (d->ReadPairCB) + d->ReadPairCB(d->ReaderData, inst, arg, src); + + if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) + return; + + add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src); +} + +/** + * This function is used by rc_get_readers_normal() to determine whether inst + * is a reader of userdata->ReaderData->Writer + */ +static void get_readers_normal_read_callback( + void * userdata, + struct rc_instruction * inst, + struct rc_src_register * src) +{ + struct get_readers_callback_data * d = userdata; + unsigned int shared_mask; + + shared_mask = get_readers_read_callback(d, + src->RelAddr, src->File, src->Index, src->Swizzle); + + if (shared_mask == RC_MASK_NONE) + return; + /* The callback function could potentially clear d->ReaderData->Abort, + * so we need to call it before we return. */ + if (d->ReadNormalCB) + d->ReadNormalCB(d->ReaderData, inst, src); + + if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) + return; + + add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src); +} + +/** + * This function is used by rc_get_readers_normal() to determine when + * userdata->ReaderData->Writer is dead (i. e. All compontents of its + * destination register have been overwritten by other instructions). + */ +static void get_readers_write_callback( + void *userdata, + struct rc_instruction * inst, + rc_register_file file, + unsigned int index, + unsigned int mask) +{ + struct get_readers_callback_data * d = userdata; + + if (index == d->DstIndex && file == d->DstFile) { + unsigned int shared_mask = mask & d->DstMask; + d->ReaderData->AbortOnRead &= ~shared_mask; + d->AliveWriteMask &= ~shared_mask; + if (d->ReaderData->AbortOnWrite & shared_mask) { + d->ReaderData->Abort = 1; + } + } + + if(d->WriteCB) + d->WriteCB(d->ReaderData, inst, file, index, mask); +} + +static void push_branch_mask( + struct get_readers_callback_data * d, + unsigned int * branch_depth) +{ + (*branch_depth)++; + if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) { + d->ReaderData->Abort = 1; + return; + } + d->BranchMasks[*branch_depth].IfWriteMask = + d->AliveWriteMask; +} + +static void pop_branch_mask( + struct get_readers_callback_data * d, + unsigned int * branch_depth) +{ + struct branch_write_mask * masks = &d->BranchMasks[*branch_depth]; + + if (masks->HasElse) { + /* Abort on read for components that were written in the IF + * block. */ + d->ReaderData->AbortOnRead |= + masks->IfWriteMask & ~masks->ElseWriteMask; + /* Abort on read for components that were written in the ELSE + * block. */ + d->ReaderData->AbortOnRead |= + masks->ElseWriteMask & ~d->AliveWriteMask; + + d->AliveWriteMask = masks->IfWriteMask + ^ ((masks->IfWriteMask ^ masks->ElseWriteMask) + & (masks->IfWriteMask ^ d->AliveWriteMask)); + } else { + d->ReaderData->AbortOnRead |= + masks->IfWriteMask & ~d->AliveWriteMask; + d->AliveWriteMask = masks->IfWriteMask; + + } + memset(masks, 0, sizeof(struct branch_write_mask)); + (*branch_depth)--; +} + +static void get_readers_for_single_write( + void * userdata, + struct rc_instruction * writer, + rc_register_file dst_file, + unsigned int dst_index, + unsigned int dst_mask) +{ + struct rc_instruction * tmp; + unsigned int branch_depth = 0; + struct rc_instruction * endloop = NULL; + unsigned int abort_on_read_at_endloop = 0; + struct get_readers_callback_data * d = userdata; + + d->ReaderData->Writer = writer; + d->ReaderData->AbortOnRead = 0; + d->ReaderData->AbortOnWrite = 0; + d->ReaderData->LoopDepth = 0; + d->ReaderData->InElse = 0; + d->DstFile = dst_file; + d->DstIndex = dst_index; + d->DstMask = dst_mask; + d->AliveWriteMask = dst_mask; + memset(d->BranchMasks, 0, sizeof(d->BranchMasks)); + + if (!dst_mask) + return; + + for(tmp = writer->Next; tmp != &d->C->Program.Instructions; + tmp = tmp->Next){ + rc_opcode opcode = rc_get_flow_control_inst(tmp); + switch(opcode) { + case RC_OPCODE_BGNLOOP: + d->ReaderData->LoopDepth++; + push_branch_mask(d, &branch_depth); + break; + case RC_OPCODE_ENDLOOP: + if (d->ReaderData->LoopDepth > 0) { + d->ReaderData->LoopDepth--; + if (d->ReaderData->LoopDepth == 0) { + d->ReaderData->AbortOnWrite = 0; + } + pop_branch_mask(d, &branch_depth); + } else { + /* Here we have reached an ENDLOOP without + * seeing its BGNLOOP. These means that + * the writer was written inside of a loop, + * so it could have readers that are above it + * (i.e. they have a lower IP). To find these + * readers we jump to the BGNLOOP instruction + * and check each instruction until we get + * back to the writer. + */ + endloop = tmp; + tmp = rc_match_endloop(tmp); + if (!tmp) { + rc_error(d->C, "Failed to match endloop.\n"); + d->ReaderData->Abort = 1; + return; + } + abort_on_read_at_endloop = d->ReaderData->AbortOnRead; + d->ReaderData->AbortOnRead |= d->AliveWriteMask; + continue; + } + break; + case RC_OPCODE_IF: + push_branch_mask(d, &branch_depth); + break; + case RC_OPCODE_ELSE: + if (branch_depth == 0) { + d->ReaderData->InElse = 1; + } else { + unsigned int temp_mask = d->AliveWriteMask; + d->AliveWriteMask = + d->BranchMasks[branch_depth].IfWriteMask; + d->BranchMasks[branch_depth].ElseWriteMask = + temp_mask; + d->BranchMasks[branch_depth].HasElse = 1; + } + break; + case RC_OPCODE_ENDIF: + if (branch_depth == 0) { + d->ReaderData->AbortOnRead = d->AliveWriteMask; + d->ReaderData->InElse = 0; + } + else { + pop_branch_mask(d, &branch_depth); + } + break; + default: + break; + } + + if (d->ReaderData->InElse) + continue; + + if (tmp->Type == RC_INSTRUCTION_NORMAL) { + rc_for_all_reads_src(tmp, + get_readers_normal_read_callback, d); + } else { + rc_pair_for_all_reads_arg(tmp, + get_readers_pair_read_callback, d); + } + + /* This can happen when we jump from an ENDLOOP to BGNLOOP */ + if (tmp == writer) { + tmp = endloop; + endloop = NULL; + d->ReaderData->AbortOnRead = abort_on_read_at_endloop; + continue; + } + rc_for_all_writes_mask(tmp, get_readers_write_callback, d); + + if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) + return; + + if (branch_depth == 0 && !d->AliveWriteMask) + return; + } +} + +static void init_get_readers_callback_data( + struct get_readers_callback_data * d, + struct rc_reader_data * reader_data, + struct radeon_compiler * c, + rc_read_src_fn read_normal_cb, + rc_pair_read_arg_fn read_pair_cb, + rc_read_write_mask_fn write_cb) +{ + reader_data->Abort = 0; + reader_data->ReaderCount = 0; + reader_data->ReadersReserved = 0; + reader_data->Readers = NULL; + + d->C = c; + d->ReaderData = reader_data; + d->ReadNormalCB = read_normal_cb; + d->ReadPairCB = read_pair_cb; + d->WriteCB = write_cb; +} + +/** + * This function will create a list of readers via the rc_reader_data struct. + * This function will abort (set the flag data->Abort) and return if it + * encounters an instruction that reads from @param writer and also a different + * instruction. Here are some examples: + * + * writer = instruction 0; + * 0 MOV TEMP[0].xy, TEMP[1].xy + * 1 MOV TEMP[0].zw, TEMP[2].xy + * 2 MOV TEMP[3], TEMP[0] + * The Abort flag will be set on instruction 2, because it reads values written + * by instructions 0 and 1. + * + * writer = instruction 1; + * 0 IF TEMP[0].x + * 1 MOV TEMP[1], TEMP[2] + * 2 ELSE + * 3 MOV TEMP[1], TEMP[2] + * 4 ENDIF + * 5 MOV TEMP[3], TEMP[1] + * The Abort flag will be set on instruction 5, because it could read from the + * value written by either instruction 1 or 3, depending on the jump decision + * made at instruction 0. + * + * writer = instruction 0; + * 0 MOV TEMP[0], TEMP[1] + * 2 BGNLOOP + * 3 ADD TEMP[0], TEMP[0], none.1 + * 4 ENDLOOP + * The Abort flag will be set on instruction 3, because in the first iteration + * of the loop it reads the value written by instruction 0 and in all other + * iterations it reads the value written by instruction 3. + * + * @param read_cb This function will be called for for every instruction that + * has been determined to be a reader of writer. + * @param write_cb This function will be called for every instruction after + * writer. + */ +void rc_get_readers( + struct radeon_compiler * c, + struct rc_instruction * writer, + struct rc_reader_data * data, + rc_read_src_fn read_normal_cb, + rc_pair_read_arg_fn read_pair_cb, + rc_read_write_mask_fn write_cb) +{ + struct get_readers_callback_data d; + + init_get_readers_callback_data(&d, data, c, read_normal_cb, + read_pair_cb, write_cb); + + rc_for_all_writes_mask(writer, get_readers_for_single_write, &d); +} + +void rc_get_readers_sub( + struct radeon_compiler * c, + struct rc_instruction * writer, + struct rc_pair_sub_instruction * sub_writer, + struct rc_reader_data * data, + rc_read_src_fn read_normal_cb, + rc_pair_read_arg_fn read_pair_cb, + rc_read_write_mask_fn write_cb) +{ + struct get_readers_callback_data d; + + init_get_readers_callback_data(&d, data, c, read_normal_cb, + read_pair_cb, write_cb); + + if (sub_writer->WriteMask) { + get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY, + sub_writer->DestIndex, sub_writer->WriteMask); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_dataflow.h b/src/gallium/drivers/r300/compiler/radeon_dataflow.h new file mode 100644 index 00000000000..d8a627258ea --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_dataflow.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * Copyright 2010 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_DATAFLOW_H +#define RADEON_DATAFLOW_H + +#include "radeon_program_constants.h" + +struct radeon_compiler; +struct rc_instruction; +struct rc_swizzle_caps; +struct rc_src_register; +struct rc_pair_instruction_arg; +struct rc_pair_instruction_source; +struct rc_pair_sub_instruction; +struct rc_compiler; + + +/** + * Help analyze and modify the register accesses of instructions. + */ +/*@{*/ +typedef void (*rc_read_write_chan_fn)(void * userdata, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int chan); +void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata); +void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata); + +typedef void (*rc_read_write_mask_fn)(void * userdata, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask); +void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata); +void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata); + +typedef void (*rc_read_src_fn)(void * userdata, struct rc_instruction * inst, + struct rc_src_register * src); +void rc_for_all_reads_src(struct rc_instruction * inst, rc_read_src_fn cb, + void * userdata); + +typedef void (*rc_pair_read_arg_fn)(void * userdata, + struct rc_instruction * inst, struct rc_pair_instruction_arg * arg, + struct rc_pair_instruction_source * src); +void rc_pair_for_all_reads_arg(struct rc_instruction * inst, + rc_pair_read_arg_fn cb, void * userdata); + +typedef void (*rc_remap_register_fn)(void * userdata, struct rc_instruction * inst, + rc_register_file * pfile, unsigned int * pindex); +void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata); +/*@}*/ + +struct rc_reader { + struct rc_instruction * Inst; + unsigned int WriteMask; + union { + struct { + struct rc_src_register * Src; + } I; + struct { + struct rc_pair_instruction_arg * Arg; + struct rc_pair_instruction_source * Src; + } P; + } U; +}; + +struct rc_reader_data { + unsigned int Abort; + unsigned int AbortOnRead; + unsigned int AbortOnWrite; + unsigned int LoopDepth; + unsigned int InElse; + struct rc_instruction * Writer; + + unsigned int ReaderCount; + unsigned int ReadersReserved; + struct rc_reader * Readers; + + /* If this flag is enabled, rc_get_readers will exit as soon possbile + * after the Abort flag is set.*/ + unsigned int ExitOnAbort; + void * CbData; +}; + +void rc_get_readers( + struct radeon_compiler * c, + struct rc_instruction * writer, + struct rc_reader_data * data, + rc_read_src_fn read_normal_cb, + rc_pair_read_arg_fn read_pair_cb, + rc_read_write_mask_fn write_cb); + +void rc_get_readers_sub( + struct radeon_compiler * c, + struct rc_instruction * writer, + struct rc_pair_sub_instruction * sub_writer, + struct rc_reader_data * data, + rc_read_src_fn read_normal_cb, + rc_pair_read_arg_fn read_pair_cb, + rc_read_write_mask_fn write_cb); +/** + * Compiler passes based on dataflow analysis. + */ +/*@{*/ +typedef void (*rc_dataflow_mark_outputs_fn)(void * userdata, void * data, + void (*mark_fn)(void * data, unsigned int index, unsigned int mask)); +void rc_dataflow_deadcode(struct radeon_compiler * c, void *user); +void rc_dataflow_swizzles(struct radeon_compiler * c, void *user); +/*@}*/ + +void rc_optimize(struct radeon_compiler * c, void *user); + +#endif /* RADEON_DATAFLOW_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_dataflow_deadcode.c b/src/gallium/drivers/r300/compiler/radeon_dataflow_deadcode.c new file mode 100644 index 00000000000..678e1475883 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_dataflow_deadcode.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_dataflow.h" + +#include "radeon_compiler.h" + + +struct updatemask_state { + unsigned char Output[RC_REGISTER_MAX_INDEX]; + unsigned char Temporary[RC_REGISTER_MAX_INDEX]; + unsigned char Address; + unsigned char Special[RC_NUM_SPECIAL_REGISTERS]; +}; + +struct instruction_state { + unsigned char WriteMask:4; + unsigned char WriteALUResult:1; + unsigned char SrcReg[3]; +}; + +struct loopinfo { + struct updatemask_state * Breaks; + unsigned int BreakCount; + unsigned int BreaksReserved; +}; + +struct branchinfo { + unsigned int HaveElse:1; + + struct updatemask_state StoreEndif; + struct updatemask_state StoreElse; +}; + +struct deadcode_state { + struct radeon_compiler * C; + struct instruction_state * Instructions; + + struct updatemask_state R; + + struct branchinfo * BranchStack; + unsigned int BranchStackSize; + unsigned int BranchStackReserved; + + struct loopinfo * LoopStack; + unsigned int LoopStackSize; + unsigned int LoopStackReserved; +}; + + +static void or_updatemasks( + struct updatemask_state * dst, + struct updatemask_state * a, + struct updatemask_state * b) +{ + for(unsigned int i = 0; i < RC_REGISTER_MAX_INDEX; ++i) { + dst->Output[i] = a->Output[i] | b->Output[i]; + dst->Temporary[i] = a->Temporary[i] | b->Temporary[i]; + } + + for(unsigned int i = 0; i < RC_NUM_SPECIAL_REGISTERS; ++i) + dst->Special[i] = a->Special[i] | b->Special[i]; + + dst->Address = a->Address | b->Address; +} + +static void push_break(struct deadcode_state *s) +{ + struct loopinfo * loop = &s->LoopStack[s->LoopStackSize - 1]; + memory_pool_array_reserve(&s->C->Pool, struct updatemask_state, + loop->Breaks, loop->BreakCount, loop->BreaksReserved, 1); + + memcpy(&loop->Breaks[loop->BreakCount++], &s->R, sizeof(s->R)); +} + +static void push_loop(struct deadcode_state * s) +{ + memory_pool_array_reserve(&s->C->Pool, struct loopinfo, s->LoopStack, + s->LoopStackSize, s->LoopStackReserved, 1); + memset(&s->LoopStack[s->LoopStackSize++], 0, sizeof(struct loopinfo)); +} + +static void push_branch(struct deadcode_state * s) +{ + struct branchinfo * branch; + + memory_pool_array_reserve(&s->C->Pool, struct branchinfo, s->BranchStack, + s->BranchStackSize, s->BranchStackReserved, 1); + + branch = &s->BranchStack[s->BranchStackSize++]; + branch->HaveElse = 0; + memcpy(&branch->StoreEndif, &s->R, sizeof(s->R)); +} + +static unsigned char * get_used_ptr(struct deadcode_state *s, rc_register_file file, unsigned int index) +{ + if (file == RC_FILE_OUTPUT || file == RC_FILE_TEMPORARY) { + if (index >= RC_REGISTER_MAX_INDEX) { + rc_error(s->C, "%s: index %i is out of bounds for file %i\n", __FUNCTION__, index, file); + return 0; + } + + if (file == RC_FILE_OUTPUT) + return &s->R.Output[index]; + else + return &s->R.Temporary[index]; + } else if (file == RC_FILE_ADDRESS) { + return &s->R.Address; + } else if (file == RC_FILE_SPECIAL) { + if (index >= RC_NUM_SPECIAL_REGISTERS) { + rc_error(s->C, "%s: special file index %i out of bounds\n", __FUNCTION__, index); + return 0; + } + + return &s->R.Special[index]; + } + + return 0; +} + +static void mark_used(struct deadcode_state * s, rc_register_file file, unsigned int index, unsigned int mask) +{ + unsigned char * pused = get_used_ptr(s, file, index); + if (pused) + *pused |= mask; +} + +static void update_instruction(struct deadcode_state * s, struct rc_instruction * inst) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + struct instruction_state * insts = &s->Instructions[inst->IP]; + unsigned int usedmask = 0; + unsigned int srcmasks[3]; + + if (opcode->HasDstReg) { + unsigned char * pused = get_used_ptr(s, inst->U.I.DstReg.File, inst->U.I.DstReg.Index); + if (pused) { + usedmask = *pused & inst->U.I.DstReg.WriteMask; + *pused &= ~usedmask; + } + } + + insts->WriteMask |= usedmask; + + if (inst->U.I.WriteALUResult) { + unsigned char * pused = get_used_ptr(s, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT); + if (pused && *pused) { + if (inst->U.I.WriteALUResult == RC_ALURESULT_X) + usedmask |= RC_MASK_X; + else if (inst->U.I.WriteALUResult == RC_ALURESULT_W) + usedmask |= RC_MASK_W; + + *pused = 0; + insts->WriteALUResult = 1; + } + } + + rc_compute_sources_for_writemask(inst, usedmask, srcmasks); + + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { + unsigned int refmask = 0; + unsigned int newsrcmask = srcmasks[src] & ~insts->SrcReg[src]; + insts->SrcReg[src] |= newsrcmask; + + for(unsigned int chan = 0; chan < 4; ++chan) { + if (GET_BIT(newsrcmask, chan)) + refmask |= 1 << GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan); + } + + /* get rid of spurious bits from ZERO, ONE, etc. swizzles */ + refmask &= RC_MASK_XYZW; + + if (!refmask) + continue; + + mark_used(s, inst->U.I.SrcReg[src].File, inst->U.I.SrcReg[src].Index, refmask); + + if (inst->U.I.SrcReg[src].RelAddr) + mark_used(s, RC_FILE_ADDRESS, 0, RC_MASK_X); + } +} + +static void mark_output_use(void * data, unsigned int index, unsigned int mask) +{ + struct deadcode_state * s = data; + + mark_used(s, RC_FILE_OUTPUT, index, mask); +} + +void rc_dataflow_deadcode(struct radeon_compiler * c, void *user) +{ + struct deadcode_state s; + unsigned int nr_instructions; + rc_dataflow_mark_outputs_fn dce = (rc_dataflow_mark_outputs_fn)user; + unsigned int ip; + + memset(&s, 0, sizeof(s)); + s.C = c; + + nr_instructions = rc_recompute_ips(c); + s.Instructions = memory_pool_malloc(&c->Pool, sizeof(struct instruction_state)*nr_instructions); + memset(s.Instructions, 0, sizeof(struct instruction_state)*nr_instructions); + + dce(c, &s, &mark_output_use); + + for(struct rc_instruction * inst = c->Program.Instructions.Prev; + inst != &c->Program.Instructions; + inst = inst->Prev) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + + switch(opcode->Opcode){ + /* Mark all sources in the loop body as used before doing + * normal deadcode analysis. This is probably not optimal. + */ + case RC_OPCODE_ENDLOOP: + { + int endloops = 1; + struct rc_instruction *ptr; + for(ptr = inst->Prev; endloops > 0; ptr = ptr->Prev){ + opcode = rc_get_opcode_info(ptr->U.I.Opcode); + if(ptr->U.I.Opcode == RC_OPCODE_BGNLOOP){ + endloops--; + continue; + } + if(ptr->U.I.Opcode == RC_OPCODE_ENDLOOP){ + endloops++; + continue; + } + if(opcode->HasDstReg){ + int src = 0; + unsigned int srcmasks[3]; + rc_compute_sources_for_writemask(ptr, + ptr->U.I.DstReg.WriteMask, srcmasks); + for(src=0; src < opcode->NumSrcRegs; src++){ + mark_used(&s, + ptr->U.I.SrcReg[src].File, + ptr->U.I.SrcReg[src].Index, + srcmasks[src]); + } + } + } + push_loop(&s); + break; + } + case RC_OPCODE_BRK: + push_break(&s); + break; + case RC_OPCODE_BGNLOOP: + { + unsigned int i; + struct loopinfo * loop = &s.LoopStack[s.LoopStackSize-1]; + for(i = 0; i < loop->BreakCount; i++) { + or_updatemasks(&s.R, &s.R, &loop->Breaks[i]); + } + break; + } + case RC_OPCODE_CONT: + break; + case RC_OPCODE_ENDIF: + push_branch(&s); + break; + default: + if (opcode->IsFlowControl && s.BranchStackSize) { + struct branchinfo * branch = &s.BranchStack[s.BranchStackSize-1]; + if (opcode->Opcode == RC_OPCODE_IF) { + or_updatemasks(&s.R, + &s.R, + branch->HaveElse ? &branch->StoreElse : &branch->StoreEndif); + + s.BranchStackSize--; + } else if (opcode->Opcode == RC_OPCODE_ELSE) { + if (branch->HaveElse) { + rc_error(c, "%s: Multiple ELSE for one IF/ENDIF\n", __FUNCTION__); + } else { + memcpy(&branch->StoreElse, &s.R, sizeof(s.R)); + memcpy(&s.R, &branch->StoreEndif, sizeof(s.R)); + branch->HaveElse = 1; + } + } else { + rc_error(c, "%s: Unhandled control flow instruction %s\n", __FUNCTION__, opcode->Name); + } + } + } + + update_instruction(&s, inst); + } + + ip = 0; + for(struct rc_instruction * inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next, ++ip) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + int dead = 1; + unsigned int srcmasks[3]; + unsigned int usemask; + + if (!opcode->HasDstReg) { + dead = 0; + } else { + inst->U.I.DstReg.WriteMask = s.Instructions[ip].WriteMask; + if (s.Instructions[ip].WriteMask) + dead = 0; + + if (s.Instructions[ip].WriteALUResult) + dead = 0; + else + inst->U.I.WriteALUResult = RC_ALURESULT_NONE; + } + + if (dead) { + struct rc_instruction * todelete = inst; + inst = inst->Prev; + rc_remove_instruction(todelete); + continue; + } + + usemask = s.Instructions[ip].WriteMask; + + if (inst->U.I.WriteALUResult == RC_ALURESULT_X) + usemask |= RC_MASK_X; + else if (inst->U.I.WriteALUResult == RC_ALURESULT_W) + usemask |= RC_MASK_W; + + rc_compute_sources_for_writemask(inst, usemask, srcmasks); + + for(unsigned int src = 0; src < 3; ++src) { + for(unsigned int chan = 0; chan < 4; ++chan) { + if (!GET_BIT(srcmasks[src], chan)) + SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan, RC_SWIZZLE_UNUSED); + } + } + } + + rc_calculate_inputs_outputs(c); +} diff --git a/src/gallium/drivers/r300/compiler/radeon_dataflow_swizzles.c b/src/gallium/drivers/r300/compiler/radeon_dataflow_swizzles.c new file mode 100644 index 00000000000..133a9f72ec7 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_dataflow_swizzles.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_dataflow.h" + +#include "radeon_compiler.h" +#include "radeon_swizzle.h" + + +static void rewrite_source(struct radeon_compiler * c, + struct rc_instruction * inst, unsigned src) +{ + struct rc_swizzle_split split; + unsigned int tempreg = rc_find_free_temporary(c); + unsigned int usemask; + + usemask = 0; + for(unsigned int chan = 0; chan < 4; ++chan) { + if (GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan) != RC_SWIZZLE_UNUSED) + usemask |= 1 << chan; + } + + c->SwizzleCaps->Split(inst->U.I.SrcReg[src], usemask, &split); + + for(unsigned int phase = 0; phase < split.NumPhases; ++phase) { + struct rc_instruction * mov = rc_insert_new_instruction(c, inst->Prev); + unsigned int phase_refmask; + unsigned int masked_negate; + + mov->U.I.Opcode = RC_OPCODE_MOV; + mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + mov->U.I.DstReg.Index = tempreg; + mov->U.I.DstReg.WriteMask = split.Phase[phase]; + mov->U.I.SrcReg[0] = inst->U.I.SrcReg[src]; + mov->U.I.PreSub = inst->U.I.PreSub; + + phase_refmask = 0; + for(unsigned int chan = 0; chan < 4; ++chan) { + if (!GET_BIT(split.Phase[phase], chan)) + SET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED); + else + phase_refmask |= 1 << GET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan); + } + + phase_refmask &= RC_MASK_XYZW; + + masked_negate = split.Phase[phase] & mov->U.I.SrcReg[0].Negate; + if (masked_negate == 0) + mov->U.I.SrcReg[0].Negate = 0; + else if (masked_negate == split.Phase[phase]) + mov->U.I.SrcReg[0].Negate = RC_MASK_XYZW; + + } + + inst->U.I.SrcReg[src].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[src].Index = tempreg; + inst->U.I.SrcReg[src].Swizzle = 0; + inst->U.I.SrcReg[src].Negate = RC_MASK_NONE; + inst->U.I.SrcReg[src].Abs = 0; + for(unsigned int chan = 0; chan < 4; ++chan) { + SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan, + GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED); + } +} + +void rc_dataflow_swizzles(struct radeon_compiler * c, void *user) +{ + struct rc_instruction * inst; + + for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned int src; + + for(src = 0; src < opcode->NumSrcRegs; ++src) { + if (!c->SwizzleCaps->IsNative(inst->U.I.Opcode, inst->U.I.SrcReg[src])) + rewrite_source(c, inst, src); + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_emulate_branches.c b/src/gallium/drivers/r300/compiler/radeon_emulate_branches.c new file mode 100644 index 00000000000..7bede344f30 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_emulate_branches.c @@ -0,0 +1,342 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "radeon_emulate_branches.h" + +#include <stdio.h> + +#include "radeon_compiler.h" +#include "radeon_dataflow.h" + +#define VERBOSE 0 + +#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) + + +struct proxy_info { + unsigned int Proxied:1; + unsigned int Index:RC_REGISTER_INDEX_BITS; +}; + +struct register_proxies { + struct proxy_info Temporary[RC_REGISTER_MAX_INDEX]; +}; + +struct branch_info { + struct rc_instruction * If; + struct rc_instruction * Else; +}; + +struct emulate_branch_state { + struct radeon_compiler * C; + + struct branch_info * Branches; + unsigned int BranchCount; + unsigned int BranchReserved; +}; + + +static void handle_if(struct emulate_branch_state * s, struct rc_instruction * inst) +{ + struct branch_info * branch; + struct rc_instruction * inst_mov; + + memory_pool_array_reserve(&s->C->Pool, struct branch_info, + s->Branches, s->BranchCount, s->BranchReserved, 1); + + DBG("%s\n", __FUNCTION__); + + branch = &s->Branches[s->BranchCount++]; + memset(branch, 0, sizeof(struct branch_info)); + branch->If = inst; + + /* Make a safety copy of the decision register, because we will need + * it at ENDIF time and it might be overwritten in both branches. */ + inst_mov = rc_insert_new_instruction(s->C, inst->Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = rc_find_free_temporary(s->C); + inst_mov->U.I.DstReg.WriteMask = RC_MASK_X; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = inst_mov->U.I.DstReg.Index; + inst->U.I.SrcReg[0].Swizzle = 0; + inst->U.I.SrcReg[0].Abs = 0; + inst->U.I.SrcReg[0].Negate = 0; +} + +static void handle_else(struct emulate_branch_state * s, struct rc_instruction * inst) +{ + struct branch_info * branch; + + if (!s->BranchCount) { + rc_error(s->C, "Encountered ELSE outside of branches"); + return; + } + + DBG("%s\n", __FUNCTION__); + + branch = &s->Branches[s->BranchCount - 1]; + branch->Else = inst; +} + + +struct state_and_proxies { + struct emulate_branch_state * S; + struct register_proxies * Proxies; +}; + +static struct proxy_info * get_proxy_info(struct state_and_proxies * sap, + rc_register_file file, unsigned int index) +{ + if (file == RC_FILE_TEMPORARY) { + return &sap->Proxies->Temporary[index]; + } else { + return 0; + } +} + +static void scan_write(void * userdata, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int comp) +{ + struct state_and_proxies * sap = userdata; + struct proxy_info * proxy = get_proxy_info(sap, file, index); + + if (proxy && !proxy->Proxied) { + proxy->Proxied = 1; + proxy->Index = rc_find_free_temporary(sap->S->C); + } +} + +static void remap_proxy_function(void * userdata, struct rc_instruction * inst, + rc_register_file * pfile, unsigned int * pindex) +{ + struct state_and_proxies * sap = userdata; + struct proxy_info * proxy = get_proxy_info(sap, *pfile, *pindex); + + if (proxy && proxy->Proxied) { + *pfile = RC_FILE_TEMPORARY; + *pindex = proxy->Index; + } +} + +/** + * Redirect all writes in the instruction range [begin, end) to proxy + * temporary registers. + */ +static void allocate_and_insert_proxies(struct emulate_branch_state * s, + struct register_proxies * proxies, + struct rc_instruction * begin, + struct rc_instruction * end) +{ + struct state_and_proxies sap; + + sap.S = s; + sap.Proxies = proxies; + + for(struct rc_instruction * inst = begin; inst != end; inst = inst->Next) { + rc_for_all_writes_mask(inst, scan_write, &sap); + rc_remap_registers(inst, remap_proxy_function, &sap); + } + + for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) { + if (proxies->Temporary[index].Proxied) { + struct rc_instruction * inst_mov = rc_insert_new_instruction(s->C, begin->Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = proxies->Temporary[index].Index; + inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZW; + inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_mov->U.I.SrcReg[0].Index = index; + } + } +} + + +static void inject_cmp(struct emulate_branch_state * s, + struct rc_instruction * inst_if, + struct rc_instruction * inst_endif, + rc_register_file file, unsigned int index, + struct proxy_info ifproxy, + struct proxy_info elseproxy) +{ + struct rc_instruction * inst_cmp = rc_insert_new_instruction(s->C, inst_endif); + inst_cmp->U.I.Opcode = RC_OPCODE_CMP; + inst_cmp->U.I.DstReg.File = file; + inst_cmp->U.I.DstReg.Index = index; + inst_cmp->U.I.DstReg.WriteMask = RC_MASK_XYZW; + inst_cmp->U.I.SrcReg[0] = inst_if->U.I.SrcReg[0]; + inst_cmp->U.I.SrcReg[0].Abs = 1; + inst_cmp->U.I.SrcReg[0].Negate = RC_MASK_XYZW; + inst_cmp->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_cmp->U.I.SrcReg[1].Index = ifproxy.Proxied ? ifproxy.Index : index; + inst_cmp->U.I.SrcReg[2].File = RC_FILE_TEMPORARY; + inst_cmp->U.I.SrcReg[2].Index = elseproxy.Proxied ? elseproxy.Index : index; +} + +static void handle_endif(struct emulate_branch_state * s, struct rc_instruction * inst) +{ + struct branch_info * branch; + struct register_proxies IfProxies; + struct register_proxies ElseProxies; + + if (!s->BranchCount) { + rc_error(s->C, "Encountered ENDIF outside of branches"); + return; + } + + DBG("%s\n", __FUNCTION__); + + branch = &s->Branches[s->BranchCount - 1]; + + memset(&IfProxies, 0, sizeof(IfProxies)); + memset(&ElseProxies, 0, sizeof(ElseProxies)); + + allocate_and_insert_proxies(s, &IfProxies, branch->If->Next, branch->Else ? branch->Else : inst); + + if (branch->Else) + allocate_and_insert_proxies(s, &ElseProxies, branch->Else->Next, inst); + + /* Insert the CMP instructions at the end. */ + for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) { + if (IfProxies.Temporary[index].Proxied || ElseProxies.Temporary[index].Proxied) { + inject_cmp(s, branch->If, inst, RC_FILE_TEMPORARY, index, + IfProxies.Temporary[index], ElseProxies.Temporary[index]); + } + } + + /* Remove all traces of the branch instructions */ + rc_remove_instruction(branch->If); + if (branch->Else) + rc_remove_instruction(branch->Else); + rc_remove_instruction(inst); + + s->BranchCount--; + + if (VERBOSE) { + DBG("Program after ENDIF handling:\n"); + rc_print_program(&s->C->Program); + } +} + + +struct remap_output_data { + unsigned int Output:RC_REGISTER_INDEX_BITS; + unsigned int Temporary:RC_REGISTER_INDEX_BITS; +}; + +static void remap_output_function(void * userdata, struct rc_instruction * inst, + rc_register_file * pfile, unsigned int * pindex) +{ + struct remap_output_data * data = userdata; + + if (*pfile == RC_FILE_OUTPUT && *pindex == data->Output) { + *pfile = RC_FILE_TEMPORARY; + *pindex = data->Temporary; + } +} + + +/** + * Output registers cannot be read from and so cannot be dealt with like + * temporary registers. + * + * We do the simplest thing: If an output registers is written within + * a branch, then *all* writes to this register are proxied to a + * temporary register, and a final MOV is appended to the end of + * the program. + */ +static void fix_output_writes(struct emulate_branch_state * s, struct rc_instruction * inst) +{ + const struct rc_opcode_info * opcode; + + if (!s->BranchCount) + return; + + opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (!opcode->HasDstReg) + return; + + if (inst->U.I.DstReg.File == RC_FILE_OUTPUT) { + struct remap_output_data remap; + struct rc_instruction * inst_mov; + + remap.Output = inst->U.I.DstReg.Index; + remap.Temporary = rc_find_free_temporary(s->C); + + for(struct rc_instruction * inst = s->C->Program.Instructions.Next; + inst != &s->C->Program.Instructions; + inst = inst->Next) { + rc_remap_registers(inst, &remap_output_function, &remap); + } + + inst_mov = rc_insert_new_instruction(s->C, s->C->Program.Instructions.Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_OUTPUT; + inst_mov->U.I.DstReg.Index = remap.Output; + inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZW; + inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_mov->U.I.SrcReg[0].Index = remap.Temporary; + } +} + +/** + * Remove branch instructions; instead, execute both branches + * on different register sets and choose between their results + * using CMP instructions in place of the original ENDIF. + */ +void rc_emulate_branches(struct radeon_compiler *c, void *user) +{ + struct emulate_branch_state s; + struct rc_instruction * ptr; + + memset(&s, 0, sizeof(s)); + s.C = c; + + /* Untypical loop because we may remove the current instruction */ + ptr = c->Program.Instructions.Next; + while(ptr != &c->Program.Instructions) { + struct rc_instruction * inst = ptr; + ptr = ptr->Next; + + if (inst->Type == RC_INSTRUCTION_NORMAL) { + switch(inst->U.I.Opcode) { + case RC_OPCODE_IF: + handle_if(&s, inst); + break; + case RC_OPCODE_ELSE: + handle_else(&s, inst); + break; + case RC_OPCODE_ENDIF: + handle_endif(&s, inst); + break; + default: + fix_output_writes(&s, inst); + break; + } + } else { + rc_error(c, "%s: unhandled instruction type\n", __FUNCTION__); + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_emulate_branches.h b/src/gallium/drivers/r300/compiler/radeon_emulate_branches.h new file mode 100644 index 00000000000..818ab84d0cd --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_emulate_branches.h @@ -0,0 +1,30 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#ifndef RADEON_EMULATE_BRANCHES_H +#define RADEON_EMULATE_BRANCHES_H + +struct radeon_compiler; + +void rc_emulate_branches(struct radeon_compiler *c, void *user); + +#endif /* RADEON_EMULATE_BRANCHES_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_emulate_loops.c b/src/gallium/drivers/r300/compiler/radeon_emulate_loops.c new file mode 100644 index 00000000000..205eecd1129 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_emulate_loops.c @@ -0,0 +1,522 @@ +/* + * Copyright 2010 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * \file + */ + +#include "radeon_emulate_loops.h" + +#include "radeon_compiler.h" +#include "radeon_dataflow.h" + +#define VERBOSE 0 + +#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) + +struct const_value { + struct radeon_compiler * C; + struct rc_src_register * Src; + float Value; + int HasValue; +}; + +struct count_inst { + struct radeon_compiler * C; + int Index; + rc_swizzle Swz; + float Amount; + int Unknown; +}; + +static float get_constant_value(struct radeon_compiler * c, + struct rc_src_register * src, + int chan) +{ + float base = 1.0f; + int swz = GET_SWZ(src->Swizzle, chan); + if(swz >= 4 || src->Index >= c->Program.Constants.Count ){ + rc_error(c, "get_constant_value: Can't find a value.\n"); + return 0.0f; + } + if(GET_BIT(src->Negate, chan)){ + base = -1.0f; + } + return base * + c->Program.Constants.Constants[src->Index].u.Immediate[swz]; +} + +static int src_reg_is_immediate(struct rc_src_register * src, + struct radeon_compiler * c) +{ + return src->File == RC_FILE_CONSTANT && + c->Program.Constants.Constants[src->Index].Type==RC_CONSTANT_IMMEDIATE; +} + +static unsigned int loop_max_possible_iterations(struct radeon_compiler *c, + struct loop_info * loop) +{ + unsigned int total_i = rc_recompute_ips(c); + unsigned int loop_i = (loop->EndLoop->IP - loop->BeginLoop->IP) - 1; + /* +1 because the program already has one iteration of the loop. */ + return 1 + ((c->max_alu_insts - total_i) / loop_i); +} + +static void unroll_loop(struct radeon_compiler * c, struct loop_info * loop, + unsigned int iterations) +{ + unsigned int i; + struct rc_instruction * ptr; + struct rc_instruction * first = loop->BeginLoop->Next; + struct rc_instruction * last = loop->EndLoop->Prev; + struct rc_instruction * append_to = last; + rc_remove_instruction(loop->BeginLoop); + rc_remove_instruction(loop->EndLoop); + for( i = 1; i < iterations; i++){ + for(ptr = first; ptr != last->Next; ptr = ptr->Next){ + struct rc_instruction *new = rc_alloc_instruction(c); + memcpy(new, ptr, sizeof(struct rc_instruction)); + rc_insert_instruction(append_to, new); + append_to = new; + } + } +} + + +static void update_const_value(void * data, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask) +{ + struct const_value * value = data; + if(value->Src->File != file || + value->Src->Index != index || + !(1 << GET_SWZ(value->Src->Swizzle, 0) & mask)){ + return; + } + switch(inst->U.I.Opcode){ + case RC_OPCODE_MOV: + if(!src_reg_is_immediate(&inst->U.I.SrcReg[0], value->C)){ + return; + } + value->HasValue = 1; + value->Value = + get_constant_value(value->C, &inst->U.I.SrcReg[0], 0); + break; + } +} + +static void get_incr_amount(void * data, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask) +{ + struct count_inst * count_inst = data; + int amnt_src_index; + const struct rc_opcode_info * opcode; + float amount; + + if(file != RC_FILE_TEMPORARY || + count_inst->Index != index || + (1 << GET_SWZ(count_inst->Swz,0) != mask)){ + return; + } + /* Find the index of the counter register. */ + opcode = rc_get_opcode_info(inst->U.I.Opcode); + if(opcode->NumSrcRegs != 2){ + count_inst->Unknown = 1; + return; + } + if(inst->U.I.SrcReg[0].File == RC_FILE_TEMPORARY && + inst->U.I.SrcReg[0].Index == count_inst->Index && + inst->U.I.SrcReg[0].Swizzle == count_inst->Swz){ + amnt_src_index = 1; + } else if( inst->U.I.SrcReg[1].File == RC_FILE_TEMPORARY && + inst->U.I.SrcReg[1].Index == count_inst->Index && + inst->U.I.SrcReg[1].Swizzle == count_inst->Swz){ + amnt_src_index = 0; + } + else{ + count_inst->Unknown = 1; + return; + } + if(src_reg_is_immediate(&inst->U.I.SrcReg[amnt_src_index], + count_inst->C)){ + amount = get_constant_value(count_inst->C, + &inst->U.I.SrcReg[amnt_src_index], 0); + } + else{ + count_inst->Unknown = 1 ; + return; + } + switch(inst->U.I.Opcode){ + case RC_OPCODE_ADD: + count_inst->Amount += amount; + break; + case RC_OPCODE_SUB: + if(amnt_src_index == 0){ + count_inst->Unknown = 0; + return; + } + count_inst->Amount -= amount; + break; + default: + count_inst->Unknown = 1; + return; + } +} + +/** + * If c->max_alu_inst is -1, then all eligible loops will be unrolled regardless + * of how many iterations they have. + */ +static int try_unroll_loop(struct radeon_compiler * c, struct loop_info * loop) +{ + int end_loops; + int iterations; + struct count_inst count_inst; + float limit_value; + struct rc_src_register * counter; + struct rc_src_register * limit; + struct const_value counter_value; + struct rc_instruction * inst; + + /* Find the counter and the upper limit */ + + if(src_reg_is_immediate(&loop->Cond->U.I.SrcReg[0], c)){ + limit = &loop->Cond->U.I.SrcReg[0]; + counter = &loop->Cond->U.I.SrcReg[1]; + } + else if(src_reg_is_immediate(&loop->Cond->U.I.SrcReg[1], c)){ + limit = &loop->Cond->U.I.SrcReg[1]; + counter = &loop->Cond->U.I.SrcReg[0]; + } + else{ + DBG("No constant limit.\n"); + return 0; + } + + /* Find the initial value of the counter */ + counter_value.Src = counter; + counter_value.Value = 0.0f; + counter_value.HasValue = 0; + counter_value.C = c; + for(inst = c->Program.Instructions.Next; inst != loop->BeginLoop; + inst = inst->Next){ + rc_for_all_writes_mask(inst, update_const_value, &counter_value); + } + if(!counter_value.HasValue){ + DBG("Initial counter value cannot be determined.\n"); + return 0; + } + DBG("Initial counter value is %f\n", counter_value.Value); + /* Determine how the counter is modified each loop */ + count_inst.C = c; + count_inst.Index = counter->Index; + count_inst.Swz = counter->Swizzle; + count_inst.Amount = 0.0f; + count_inst.Unknown = 0; + end_loops = 1; + for(inst = loop->BeginLoop->Next; end_loops > 0; inst = inst->Next){ + switch(inst->U.I.Opcode){ + /* XXX In the future we might want to try to unroll nested + * loops here.*/ + case RC_OPCODE_BGNLOOP: + end_loops++; + break; + case RC_OPCODE_ENDLOOP: + loop->EndLoop = inst; + end_loops--; + break; + case RC_OPCODE_BRK: + /* Don't unroll loops if it has a BRK instruction + * other one used when testing the main conditional + * of the loop. */ + + /* Make sure we haven't entered a nested loops. */ + if(inst != loop->Brk && end_loops == 1) { + return 0; + } + break; + /* XXX Check if the counter is modified within an if statement. + */ + case RC_OPCODE_IF: + break; + default: + rc_for_all_writes_mask(inst, get_incr_amount, &count_inst); + if(count_inst.Unknown){ + return 0; + } + break; + } + } + /* Infinite loop */ + if(count_inst.Amount == 0.0f){ + return 0; + } + DBG("Counter is increased by %f each iteration.\n", count_inst.Amount); + /* Calculate the number of iterations of this loop. Keeping this + * simple, since we only support increment and decrement loops. + */ + limit_value = get_constant_value(c, limit, 0); + DBG("Limit is %f.\n", limit_value); + /* The iteration calculations are opposite of what you would expect. + * In a normal loop, if the condition is met, then loop continues, but + * with our loops, if the condition is met, the is exited. */ + switch(loop->Cond->U.I.Opcode){ + case RC_OPCODE_SGE: + case RC_OPCODE_SLE: + iterations = (int) ceilf((limit_value - counter_value.Value) / + count_inst.Amount); + break; + + case RC_OPCODE_SGT: + case RC_OPCODE_SLT: + iterations = (int) floorf((limit_value - counter_value.Value) / + count_inst.Amount) + 1; + break; + default: + return 0; + } + + if (c->max_alu_insts > 0 + && iterations > loop_max_possible_iterations(c, loop)) { + return 0; + } + + DBG("Loop will have %d iterations.\n", iterations); + + /* Prepare loop for unrolling */ + rc_remove_instruction(loop->Cond); + rc_remove_instruction(loop->If); + rc_remove_instruction(loop->Brk); + rc_remove_instruction(loop->EndIf); + + unroll_loop(c, loop, iterations); + loop->EndLoop = NULL; + return 1; +} + +/** + * @param c + * @param loop + * @param inst A pointer to a BGNLOOP instruction. + * @return 1 if all of the members of loop where set. + * @return 0 if there was an error and some members of loop are still NULL. + */ +static int build_loop_info(struct radeon_compiler * c, struct loop_info * loop, + struct rc_instruction * inst) +{ + struct rc_instruction * ptr; + + if(inst->U.I.Opcode != RC_OPCODE_BGNLOOP){ + rc_error(c, "%s: expected BGNLOOP", __FUNCTION__); + return 0; + } + + memset(loop, 0, sizeof(struct loop_info)); + + loop->BeginLoop = inst; + + for(ptr = loop->BeginLoop->Next; !loop->EndLoop; ptr = ptr->Next) { + + if (ptr == &c->Program.Instructions) { + rc_error(c, "%s: BGNLOOP without an ENDLOOOP.\n", + __FUNCTION__); + return 0; + } + + switch(ptr->U.I.Opcode){ + case RC_OPCODE_BGNLOOP: + { + /* Nested loop, skip ahead to the end. */ + unsigned int loop_depth = 1; + for(ptr = ptr->Next; ptr != &c->Program.Instructions; + ptr = ptr->Next){ + if (ptr->U.I.Opcode == RC_OPCODE_BGNLOOP) { + loop_depth++; + } else if (ptr->U.I.Opcode == RC_OPCODE_ENDLOOP) { + if (!--loop_depth) { + break; + } + } + } + if (ptr == &c->Program.Instructions) { + rc_error(c, "%s: BGNLOOP without an ENDLOOOP\n", + __FUNCTION__); + return 0; + } + break; + } + case RC_OPCODE_BRK: + if(ptr->Next->U.I.Opcode != RC_OPCODE_ENDIF + || ptr->Prev->U.I.Opcode != RC_OPCODE_IF + || loop->Brk){ + continue; + } + loop->Brk = ptr; + loop->If = ptr->Prev; + loop->EndIf = ptr->Next; + switch(loop->If->Prev->U.I.Opcode){ + case RC_OPCODE_SLT: + case RC_OPCODE_SGE: + case RC_OPCODE_SGT: + case RC_OPCODE_SLE: + case RC_OPCODE_SEQ: + case RC_OPCODE_SNE: + break; + default: + return 0; + } + loop->Cond = loop->If->Prev; + break; + + case RC_OPCODE_ENDLOOP: + loop->EndLoop = ptr; + break; + } + } + + if (loop->BeginLoop && loop->Brk && loop->If && loop->EndIf + && loop->Cond && loop->EndLoop) { + return 1; + } + return 0; +} + +/** + * This function prepares a loop to be unrolled by converting it into an if + * statement. Here is an outline of the conversion process: + * BGNLOOP; -> BGNLOOP; + * <Additional conditional code> -> <Additional conditional code> + * SGE/SLT temp[0], temp[1], temp[2]; -> SLT/SGE temp[0], temp[1], temp[2]; + * IF temp[0]; -> IF temp[0]; + * BRK; -> + * ENDIF; -> <Loop Body> + * <Loop Body> -> ENDIF; + * ENDLOOP; -> ENDLOOP + * + * @param inst A pointer to a BGNLOOP instruction. + * @return 1 for success, 0 for failure + */ +static int transform_loop(struct emulate_loop_state * s, + struct rc_instruction * inst) +{ + struct loop_info * loop; + + memory_pool_array_reserve(&s->C->Pool, struct loop_info, + s->Loops, s->LoopCount, s->LoopReserved, 1); + + loop = &s->Loops[s->LoopCount++]; + + if (!build_loop_info(s->C, loop, inst)) { + rc_error(s->C, "Failed to build loop info\n"); + return 0; + } + + if(try_unroll_loop(s->C, loop)){ + return 1; + } + + /* Reverse the conditional instruction */ + switch(loop->Cond->U.I.Opcode){ + case RC_OPCODE_SGE: + loop->Cond->U.I.Opcode = RC_OPCODE_SLT; + break; + case RC_OPCODE_SLT: + loop->Cond->U.I.Opcode = RC_OPCODE_SGE; + break; + case RC_OPCODE_SLE: + loop->Cond->U.I.Opcode = RC_OPCODE_SGT; + break; + case RC_OPCODE_SGT: + loop->Cond->U.I.Opcode = RC_OPCODE_SLE; + break; + case RC_OPCODE_SEQ: + loop->Cond->U.I.Opcode = RC_OPCODE_SNE; + break; + case RC_OPCODE_SNE: + loop->Cond->U.I.Opcode = RC_OPCODE_SEQ; + break; + default: + rc_error(s->C, "loop->Cond is not a conditional.\n"); + return 0; + } + + /* Prepare the loop to be emulated */ + rc_remove_instruction(loop->Brk); + rc_remove_instruction(loop->EndIf); + rc_insert_instruction(loop->EndLoop->Prev, loop->EndIf); + return 1; +} + +void rc_transform_loops(struct radeon_compiler *c, void *user) +{ + struct emulate_loop_state * s = &c->loop_state; + struct rc_instruction * ptr; + + memset(s, 0, sizeof(struct emulate_loop_state)); + s->C = c; + for(ptr = s->C->Program.Instructions.Next; + ptr != &s->C->Program.Instructions; ptr = ptr->Next) { + if(ptr->Type == RC_INSTRUCTION_NORMAL && + ptr->U.I.Opcode == RC_OPCODE_BGNLOOP){ + if (!transform_loop(s, ptr)) + return; + } + } +} + +void rc_unroll_loops(struct radeon_compiler *c, void *user) +{ + struct rc_instruction * inst; + struct loop_info loop; + + for(inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + + if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP) { + if (build_loop_info(c, &loop, inst)) { + try_unroll_loop(c, &loop); + } + } + } +} + +void rc_emulate_loops(struct radeon_compiler *c, void *user) +{ + struct emulate_loop_state * s = &c->loop_state; + int i; + /* Iterate backwards of the list of loops so that loops that nested + * loops are unrolled first. + */ + for( i = s->LoopCount - 1; i >= 0; i-- ){ + unsigned int iterations; + + if(!s->Loops[i].EndLoop){ + continue; + } + iterations = loop_max_possible_iterations(s->C, &s->Loops[i]); + unroll_loop(s->C, &s->Loops[i], iterations); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_emulate_loops.h b/src/gallium/drivers/r300/compiler/radeon_emulate_loops.h new file mode 100644 index 00000000000..cd800c059d9 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_emulate_loops.h @@ -0,0 +1,32 @@ + + +#ifndef RADEON_EMULATE_LOOPS_H +#define RADEON_EMULATE_LOOPS_H + +#define MAX_ITERATIONS 8 + +struct radeon_compiler; + +struct loop_info { + struct rc_instruction * BeginLoop; + struct rc_instruction * Cond; + struct rc_instruction * If; + struct rc_instruction * Brk; + struct rc_instruction * EndIf; + struct rc_instruction * EndLoop; +}; + +struct emulate_loop_state { + struct radeon_compiler * C; + struct loop_info * Loops; + unsigned int LoopCount; + unsigned int LoopReserved; +}; + +void rc_transform_loops(struct radeon_compiler *c, void *user); + +void rc_unroll_loops(struct radeon_compiler * c, void *user); + +void rc_emulate_loops(struct radeon_compiler * c, void *user); + +#endif /* RADEON_EMULATE_LOOPS_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_list.c b/src/gallium/drivers/r300/compiler/radeon_list.c new file mode 100644 index 00000000000..811c908a81a --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_list.c @@ -0,0 +1,90 @@ +/* + * Copyright 2011 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_list.h" + +#include <stdlib.h> +#include <stdio.h> + +#include "memory_pool.h" + +struct rc_list * rc_list(struct memory_pool * pool, void * item) +{ + struct rc_list * new = memory_pool_malloc(pool, sizeof(struct rc_list)); + new->Item = item; + new->Next = NULL; + new->Prev = NULL; + + return new; +} + +void rc_list_add(struct rc_list ** list, struct rc_list * new_value) +{ + struct rc_list * temp; + + if (*list == NULL) { + *list = new_value; + return; + } + + for (temp = *list; temp->Next; temp = temp->Next); + + temp->Next = new_value; + new_value->Prev = temp; +} + +void rc_list_remove(struct rc_list ** list, struct rc_list * rm_value) +{ + if (*list == rm_value) { + *list = rm_value->Next; + return; + } + + rm_value->Prev->Next = rm_value->Next; + if (rm_value->Next) { + rm_value->Next->Prev = rm_value->Prev; + } +} + +unsigned int rc_list_count(struct rc_list * list) +{ + unsigned int count = 0; + while (list) { + count++; + list = list->Next; + } + return count; +} + +void rc_list_print(struct rc_list * list) +{ + while(list) { + fprintf(stderr, "%p->", list->Item); + list = list->Next; + } + fprintf(stderr, "\n"); +} diff --git a/src/gallium/drivers/r300/compiler/radeon_list.h b/src/gallium/drivers/r300/compiler/radeon_list.h new file mode 100644 index 00000000000..b3c8f89cc68 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_list.h @@ -0,0 +1,46 @@ +/* + * Copyright 2011 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_LIST_H +#define RADEON_LIST_H + +struct memory_pool; + +struct rc_list { + void * Item; + struct rc_list * Prev; + struct rc_list * Next; +}; + +struct rc_list * rc_list(struct memory_pool * pool, void * item); +void rc_list_add(struct rc_list ** list, struct rc_list * new_value); +void rc_list_remove(struct rc_list ** list, struct rc_list * rm_value); +unsigned int rc_list_count(struct rc_list * list); +void rc_list_print(struct rc_list * list); + +#endif /* RADEON_LIST_H */ + diff --git a/src/gallium/drivers/r300/compiler/radeon_opcodes.c b/src/gallium/drivers/r300/compiler/radeon_opcodes.c new file mode 100644 index 00000000000..afd78ad79dd --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_opcodes.c @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_opcodes.h" +#include "radeon_program.h" + +#include "radeon_program_constants.h" + +struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = { + { + .Opcode = RC_OPCODE_NOP, + .Name = "NOP" + }, + { + .Opcode = RC_OPCODE_ILLEGAL_OPCODE, + .Name = "ILLEGAL OPCODE" + }, + { + .Opcode = RC_OPCODE_ABS, + .Name = "ABS", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_ADD, + .Name = "ADD", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_ARL, + .Name = "ARL", + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_CEIL, + .Name = "CEIL", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_CLAMP, + .Name = "CLAMP", + .NumSrcRegs = 3, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_CMP, + .Name = "CMP", + .NumSrcRegs = 3, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_CND, + .Name = "CND", + .NumSrcRegs = 3, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_COS, + .Name = "COS", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_DDX, + .Name = "DDX", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_DDY, + .Name = "DDY", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_DP2, + .Name = "DP2", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_DP3, + .Name = "DP3", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_DP4, + .Name = "DP4", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_DPH, + .Name = "DPH", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_DST, + .Name = "DST", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_EX2, + .Name = "EX2", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_EXP, + .Name = "EXP", + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_FLR, + .Name = "FLR", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_FRC, + .Name = "FRC", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_KIL, + .Name = "KIL", + .NumSrcRegs = 1 + }, + { + .Opcode = RC_OPCODE_LG2, + .Name = "LG2", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_LIT, + .Name = "LIT", + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_LOG, + .Name = "LOG", + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_LRP, + .Name = "LRP", + .NumSrcRegs = 3, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_MAD, + .Name = "MAD", + .NumSrcRegs = 3, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_MAX, + .Name = "MAX", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_MIN, + .Name = "MIN", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_MOV, + .Name = "MOV", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_MUL, + .Name = "MUL", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_POW, + .Name = "POW", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_RCP, + .Name = "RCP", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_RSQ, + .Name = "RSQ", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_SCS, + .Name = "SCS", + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_SEQ, + .Name = "SEQ", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SFL, + .Name = "SFL", + .NumSrcRegs = 0, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SGE, + .Name = "SGE", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SGT, + .Name = "SGT", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SIN, + .Name = "SIN", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsStandardScalar = 1 + }, + { + .Opcode = RC_OPCODE_SLE, + .Name = "SLE", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SLT, + .Name = "SLT", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SNE, + .Name = "SNE", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SSG, + .Name = "SSG", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SUB, + .Name = "SUB", + .NumSrcRegs = 2, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_SWZ, + .Name = "SWZ", + .NumSrcRegs = 1, + .HasDstReg = 1, + .IsComponentwise = 1 + }, + { + .Opcode = RC_OPCODE_XPD, + .Name = "XPD", + .NumSrcRegs = 2, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_TEX, + .Name = "TEX", + .HasTexture = 1, + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_TXB, + .Name = "TXB", + .HasTexture = 1, + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_TXD, + .Name = "TXD", + .HasTexture = 1, + .NumSrcRegs = 3, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_TXL, + .Name = "TXL", + .HasTexture = 1, + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_TXP, + .Name = "TXP", + .HasTexture = 1, + .NumSrcRegs = 1, + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_IF, + .Name = "IF", + .IsFlowControl = 1, + .NumSrcRegs = 1 + }, + { + .Opcode = RC_OPCODE_ELSE, + .Name = "ELSE", + .IsFlowControl = 1, + .NumSrcRegs = 0 + }, + { + .Opcode = RC_OPCODE_ENDIF, + .Name = "ENDIF", + .IsFlowControl = 1, + .NumSrcRegs = 0 + }, + { + .Opcode = RC_OPCODE_BGNLOOP, + .Name = "BGNLOOP", + .IsFlowControl = 1, + .NumSrcRegs = 0 + }, + { + .Opcode = RC_OPCODE_BRK, + .Name = "BRK", + .IsFlowControl = 1, + .NumSrcRegs = 0 + }, + { + .Opcode = RC_OPCODE_ENDLOOP, + .Name = "ENDLOOP", + .IsFlowControl = 1, + .NumSrcRegs = 0, + }, + { + .Opcode = RC_OPCODE_CONT, + .Name = "CONT", + .IsFlowControl = 1, + .NumSrcRegs = 0 + }, + { + .Opcode = RC_OPCODE_REPL_ALPHA, + .Name = "REPL_ALPHA", + .HasDstReg = 1 + }, + { + .Opcode = RC_OPCODE_BEGIN_TEX, + .Name = "BEGIN_TEX" + }, + { + .Opcode = RC_OPCODE_KILP, + .Name = "KILP", + } +}; + +void rc_compute_sources_for_writemask( + const struct rc_instruction *inst, + unsigned int writemask, + unsigned int *srcmasks) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + srcmasks[0] = 0; + srcmasks[1] = 0; + srcmasks[2] = 0; + + if (opcode->Opcode == RC_OPCODE_KIL) + srcmasks[0] |= RC_MASK_XYZW; + else if (opcode->Opcode == RC_OPCODE_IF) + srcmasks[0] |= RC_MASK_X; + + if (!writemask) + return; + + if (opcode->IsComponentwise) { + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) + srcmasks[src] |= writemask; + } else if (opcode->IsStandardScalar) { + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) + srcmasks[src] |= RC_MASK_X; + } else { + switch(opcode->Opcode) { + case RC_OPCODE_ARL: + srcmasks[0] |= RC_MASK_X; + break; + case RC_OPCODE_DP2: + srcmasks[0] |= RC_MASK_XY; + srcmasks[1] |= RC_MASK_XY; + break; + case RC_OPCODE_DP3: + case RC_OPCODE_XPD: + srcmasks[0] |= RC_MASK_XYZ; + srcmasks[1] |= RC_MASK_XYZ; + break; + case RC_OPCODE_DP4: + srcmasks[0] |= RC_MASK_XYZW; + srcmasks[1] |= RC_MASK_XYZW; + break; + case RC_OPCODE_DPH: + srcmasks[0] |= RC_MASK_XYZ; + srcmasks[1] |= RC_MASK_XYZW; + break; + case RC_OPCODE_TXB: + case RC_OPCODE_TXP: + case RC_OPCODE_TXL: + srcmasks[0] |= RC_MASK_W; + /* Fall through */ + case RC_OPCODE_TEX: + switch (inst->U.I.TexSrcTarget) { + case RC_TEXTURE_1D: + srcmasks[0] |= RC_MASK_X; + break; + case RC_TEXTURE_2D: + case RC_TEXTURE_RECT: + case RC_TEXTURE_1D_ARRAY: + srcmasks[0] |= RC_MASK_XY; + break; + case RC_TEXTURE_3D: + case RC_TEXTURE_CUBE: + case RC_TEXTURE_2D_ARRAY: + srcmasks[0] |= RC_MASK_XYZ; + break; + } + break; + case RC_OPCODE_TXD: + switch (inst->U.I.TexSrcTarget) { + case RC_TEXTURE_1D_ARRAY: + srcmasks[0] |= RC_MASK_Y; + /* Fall through. */ + case RC_TEXTURE_1D: + srcmasks[0] |= RC_MASK_X; + srcmasks[1] |= RC_MASK_X; + srcmasks[2] |= RC_MASK_X; + break; + case RC_TEXTURE_2D_ARRAY: + srcmasks[0] |= RC_MASK_Z; + /* Fall through. */ + case RC_TEXTURE_2D: + case RC_TEXTURE_RECT: + srcmasks[0] |= RC_MASK_XY; + srcmasks[1] |= RC_MASK_XY; + srcmasks[2] |= RC_MASK_XY; + break; + case RC_TEXTURE_3D: + case RC_TEXTURE_CUBE: + srcmasks[0] |= RC_MASK_XYZ; + srcmasks[1] |= RC_MASK_XYZ; + srcmasks[2] |= RC_MASK_XYZ; + break; + } + break; + case RC_OPCODE_DST: + srcmasks[0] |= RC_MASK_Y | RC_MASK_Z; + srcmasks[1] |= RC_MASK_Y | RC_MASK_W; + break; + case RC_OPCODE_EXP: + case RC_OPCODE_LOG: + srcmasks[0] |= RC_MASK_XY; + break; + case RC_OPCODE_LIT: + srcmasks[0] |= RC_MASK_X | RC_MASK_Y | RC_MASK_W; + break; + default: + break; + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_opcodes.h b/src/gallium/drivers/r300/compiler/radeon_opcodes.h new file mode 100644 index 00000000000..b5868820611 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_opcodes.h @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_OPCODES_H +#define RADEON_OPCODES_H + +#include <assert.h> + +/** + * Opcodes understood by the Radeon compiler. + */ +typedef enum { + RC_OPCODE_NOP = 0, + RC_OPCODE_ILLEGAL_OPCODE, + + /** vec4 instruction: dst.c = abs(src0.c); */ + RC_OPCODE_ABS, + + /** vec4 instruction: dst.c = src0.c + src1.c; */ + RC_OPCODE_ADD, + + /** special instruction: load address register + * dst.x = floor(src.x), where dst must be an address register */ + RC_OPCODE_ARL, + + /** vec4 instruction: dst.c = ceil(src0.c) */ + RC_OPCODE_CEIL, + + /** vec4 instruction: dst.c = clamp(src0.c, src1.c, src2.c) */ + RC_OPCODE_CLAMP, + + /** vec4 instruction: dst.c = src0.c < 0.0 ? src1.c : src2.c */ + RC_OPCODE_CMP, + + /** vec4 instruction: dst.c = src2.c > 0.5 ? src0.c : src1.c */ + RC_OPCODE_CND, + + /** scalar instruction: dst = cos(src0.x) */ + RC_OPCODE_COS, + + /** special instruction: take vec4 partial derivative in X direction + * dst.c = d src0.c / dx */ + RC_OPCODE_DDX, + + /** special instruction: take vec4 partial derivative in Y direction + * dst.c = d src0.c / dy */ + RC_OPCODE_DDY, + + /** scalar instruction: dst = src0.x*src1.x + src0.y*src1.y */ + RC_OPCODE_DP2, + + /** scalar instruction: dst = src0.x*src1.x + src0.y*src1.y + src0.z*src1.z */ + RC_OPCODE_DP3, + + /** scalar instruction: dst = src0.x*src1.x + src0.y*src1.y + src0.z*src1.z + src0.w*src1.w */ + RC_OPCODE_DP4, + + /** scalar instruction: dst = src0.x*src1.x + src0.y*src1.y + src0.z*src1.z + src1.w */ + RC_OPCODE_DPH, + + /** special instruction, see ARB_fragment_program */ + RC_OPCODE_DST, + + /** scalar instruction: dst = 2**src0.x */ + RC_OPCODE_EX2, + + /** special instruction, see ARB_vertex_program */ + RC_OPCODE_EXP, + + /** vec4 instruction: dst.c = floor(src0.c) */ + RC_OPCODE_FLR, + + /** vec4 instruction: dst.c = src0.c - floor(src0.c) */ + RC_OPCODE_FRC, + + /** special instruction: stop execution if any component of src0 is negative */ + RC_OPCODE_KIL, + + /** scalar instruction: dst = log_2(src0.x) */ + RC_OPCODE_LG2, + + /** special instruction, see ARB_vertex_program */ + RC_OPCODE_LIT, + + /** special instruction, see ARB_vertex_program */ + RC_OPCODE_LOG, + + /** vec4 instruction: dst.c = src0.c*src1.c + (1 - src0.c)*src2.c */ + RC_OPCODE_LRP, + + /** vec4 instruction: dst.c = src0.c*src1.c + src2.c */ + RC_OPCODE_MAD, + + /** vec4 instruction: dst.c = max(src0.c, src1.c) */ + RC_OPCODE_MAX, + + /** vec4 instruction: dst.c = min(src0.c, src1.c) */ + RC_OPCODE_MIN, + + /** vec4 instruction: dst.c = src0.c */ + RC_OPCODE_MOV, + + /** vec4 instruction: dst.c = src0.c*src1.c */ + RC_OPCODE_MUL, + + /** scalar instruction: dst = src0.x ** src1.x */ + RC_OPCODE_POW, + + /** scalar instruction: dst = 1 / src0.x */ + RC_OPCODE_RCP, + + /** scalar instruction: dst = 1 / sqrt(src0.x) */ + RC_OPCODE_RSQ, + + /** special instruction, see ARB_fragment_program */ + RC_OPCODE_SCS, + + /** vec4 instruction: dst.c = (src0.c == src1.c) ? 1.0 : 0.0 */ + RC_OPCODE_SEQ, + + /** vec4 instruction: dst.c = 0.0 */ + RC_OPCODE_SFL, + + /** vec4 instruction: dst.c = (src0.c >= src1.c) ? 1.0 : 0.0 */ + RC_OPCODE_SGE, + + /** vec4 instruction: dst.c = (src0.c > src1.c) ? 1.0 : 0.0 */ + RC_OPCODE_SGT, + + /** scalar instruction: dst = sin(src0.x) */ + RC_OPCODE_SIN, + + /** vec4 instruction: dst.c = (src0.c <= src1.c) ? 1.0 : 0.0 */ + RC_OPCODE_SLE, + + /** vec4 instruction: dst.c = (src0.c < src1.c) ? 1.0 : 0.0 */ + RC_OPCODE_SLT, + + /** vec4 instruction: dst.c = (src0.c != src1.c) ? 1.0 : 0.0 */ + RC_OPCODE_SNE, + + /** vec4 instruction: dst.c = (src0.c < 0 ?) -1 : ((src0.c > 0) : 1 : 0) */ + RC_OPCODE_SSG, + + /** vec4 instruction: dst.c = src0.c - src1.c */ + RC_OPCODE_SUB, + + /** vec4 instruction: dst.c = src0.c */ + RC_OPCODE_SWZ, + + /** special instruction, see ARB_fragment_program */ + RC_OPCODE_XPD, + + RC_OPCODE_TEX, + RC_OPCODE_TXB, + RC_OPCODE_TXD, + RC_OPCODE_TXL, + RC_OPCODE_TXP, + + /** branch instruction: + * If src0.x != 0.0, continue with the next instruction; + * otherwise, jump to matching RC_OPCODE_ELSE or RC_OPCODE_ENDIF. + */ + RC_OPCODE_IF, + + /** branch instruction: jump to matching RC_OPCODE_ENDIF */ + RC_OPCODE_ELSE, + + /** branch instruction: has no effect */ + RC_OPCODE_ENDIF, + + RC_OPCODE_BGNLOOP, + + RC_OPCODE_BRK, + + RC_OPCODE_ENDLOOP, + + RC_OPCODE_CONT, + + /** special instruction, used in R300-R500 fragment program pair instructions + * indicates that the result of the alpha operation shall be replicated + * across all other channels */ + RC_OPCODE_REPL_ALPHA, + + /** special instruction, used in R300-R500 fragment programs + * to indicate the start of a block of texture instructions that + * can run simultaneously. */ + RC_OPCODE_BEGIN_TEX, + + /** Stop execution of the shader (GLSL discard) */ + RC_OPCODE_KILP, + + MAX_RC_OPCODE +} rc_opcode; + + +struct rc_opcode_info { + rc_opcode Opcode; + const char * Name; + + /** true if the instruction reads from a texture. + * + * \note This is false for the KIL instruction, even though KIL is + * a texture instruction from a hardware point of view. */ + unsigned int HasTexture:1; + + unsigned int NumSrcRegs:2; + unsigned int HasDstReg:1; + + /** true if this instruction affects control flow */ + unsigned int IsFlowControl:1; + + /** true if this is a vector instruction that operates on components in parallel + * without any cross-component interaction */ + unsigned int IsComponentwise:1; + + /** true if this instruction sources only its operands X components + * to compute one result which is smeared across all output channels */ + unsigned int IsStandardScalar:1; +}; + +extern struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE]; + +static inline const struct rc_opcode_info * rc_get_opcode_info(rc_opcode opcode) +{ + assert((unsigned int)opcode < MAX_RC_OPCODE); + assert(rc_opcodes[opcode].Opcode == opcode); + + return &rc_opcodes[opcode]; +} + +struct rc_instruction; + +void rc_compute_sources_for_writemask( + const struct rc_instruction *inst, + unsigned int writemask, + unsigned int *srcmasks); + +#endif /* RADEON_OPCODES_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_optimize.c b/src/gallium/drivers/r300/compiler/radeon_optimize.c new file mode 100644 index 00000000000..39dcb21d4f4 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_optimize.c @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * Copyright 2010 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_dataflow.h" + +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" +#include "radeon_swizzle.h" + +struct src_clobbered_reads_cb_data { + rc_register_file File; + unsigned int Index; + unsigned int Mask; + struct rc_reader_data * ReaderData; +}; + +typedef void (*rc_presub_replace_fn)(struct rc_instruction *, + struct rc_instruction *, + unsigned int); + +static struct rc_src_register chain_srcregs(struct rc_src_register outer, struct rc_src_register inner) +{ + struct rc_src_register combine; + combine.File = inner.File; + combine.Index = inner.Index; + combine.RelAddr = inner.RelAddr; + if (outer.Abs) { + combine.Abs = 1; + combine.Negate = outer.Negate; + } else { + combine.Abs = inner.Abs; + combine.Negate = swizzle_mask(outer.Swizzle, inner.Negate); + combine.Negate ^= outer.Negate; + } + combine.Swizzle = combine_swizzles(inner.Swizzle, outer.Swizzle); + return combine; +} + +static void copy_propagate_scan_read(void * data, struct rc_instruction * inst, + struct rc_src_register * src) +{ + rc_register_file file = src->File; + struct rc_reader_data * reader_data = data; + + if(!rc_inst_can_use_presub(inst, + reader_data->Writer->U.I.PreSub.Opcode, + rc_swizzle_to_writemask(src->Swizzle), + src, + &reader_data->Writer->U.I.PreSub.SrcReg[0], + &reader_data->Writer->U.I.PreSub.SrcReg[1])) { + reader_data->Abort = 1; + return; + } + + /* XXX This could probably be handled better. */ + if (file == RC_FILE_ADDRESS) { + reader_data->Abort = 1; + return; + } + + /* These instructions cannot read from the constants file. + * see radeonTransformTEX() + */ + if(reader_data->Writer->U.I.SrcReg[0].File != RC_FILE_TEMPORARY && + reader_data->Writer->U.I.SrcReg[0].File != RC_FILE_INPUT && + (inst->U.I.Opcode == RC_OPCODE_TEX || + inst->U.I.Opcode == RC_OPCODE_TXB || + inst->U.I.Opcode == RC_OPCODE_TXP || + inst->U.I.Opcode == RC_OPCODE_TXD || + inst->U.I.Opcode == RC_OPCODE_TXL || + inst->U.I.Opcode == RC_OPCODE_KIL)){ + reader_data->Abort = 1; + return; + } +} + +static void src_clobbered_reads_cb( + void * data, + struct rc_instruction * inst, + struct rc_src_register * src) +{ + struct src_clobbered_reads_cb_data * sc_data = data; + + if (src->File == sc_data->File + && src->Index == sc_data->Index + && (rc_swizzle_to_writemask(src->Swizzle) & sc_data->Mask)) { + + sc_data->ReaderData->AbortOnRead = RC_MASK_XYZW; + } + + if (src->RelAddr && sc_data->File == RC_FILE_ADDRESS) { + sc_data->ReaderData->AbortOnRead = RC_MASK_XYZW; + } +} + +static void is_src_clobbered_scan_write( + void * data, + struct rc_instruction * inst, + rc_register_file file, + unsigned int index, + unsigned int mask) +{ + struct src_clobbered_reads_cb_data sc_data; + struct rc_reader_data * reader_data = data; + sc_data.File = file; + sc_data.Index = index; + sc_data.Mask = mask; + sc_data.ReaderData = reader_data; + rc_for_all_reads_src(reader_data->Writer, + src_clobbered_reads_cb, &sc_data); +} + +static void copy_propagate(struct radeon_compiler * c, struct rc_instruction * inst_mov) +{ + struct rc_reader_data reader_data; + unsigned int i; + + if (inst_mov->U.I.DstReg.File != RC_FILE_TEMPORARY || + inst_mov->U.I.WriteALUResult || + inst_mov->U.I.SaturateMode) + return; + + /* Get a list of all the readers of this MOV instruction. */ + reader_data.ExitOnAbort = 1; + rc_get_readers(c, inst_mov, &reader_data, + copy_propagate_scan_read, NULL, + is_src_clobbered_scan_write); + + if (reader_data.Abort || reader_data.ReaderCount == 0) + return; + + /* Propagate the MOV instruction. */ + for (i = 0; i < reader_data.ReaderCount; i++) { + struct rc_instruction * inst = reader_data.Readers[i].Inst; + *reader_data.Readers[i].U.I.Src = chain_srcregs(*reader_data.Readers[i].U.I.Src, inst_mov->U.I.SrcReg[0]); + + if (inst_mov->U.I.SrcReg[0].File == RC_FILE_PRESUB) + inst->U.I.PreSub = inst_mov->U.I.PreSub; + } + + /* Finally, remove the original MOV instruction */ + rc_remove_instruction(inst_mov); +} + +/** + * Check if a source register is actually always the same + * swizzle constant. + */ +static int is_src_uniform_constant(struct rc_src_register src, + rc_swizzle * pswz, unsigned int * pnegate) +{ + int have_used = 0; + + if (src.File != RC_FILE_NONE) { + *pswz = 0; + return 0; + } + + for(unsigned int chan = 0; chan < 4; ++chan) { + unsigned int swz = GET_SWZ(src.Swizzle, chan); + if (swz < 4) { + *pswz = 0; + return 0; + } + if (swz == RC_SWIZZLE_UNUSED) + continue; + + if (!have_used) { + *pswz = swz; + *pnegate = GET_BIT(src.Negate, chan); + have_used = 1; + } else { + if (swz != *pswz || *pnegate != GET_BIT(src.Negate, chan)) { + *pswz = 0; + return 0; + } + } + } + + return 1; +} + +static void constant_folding_mad(struct rc_instruction * inst) +{ + rc_swizzle swz = 0; + unsigned int negate= 0; + + if (is_src_uniform_constant(inst->U.I.SrcReg[2], &swz, &negate)) { + if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MUL; + return; + } + } + + if (is_src_uniform_constant(inst->U.I.SrcReg[1], &swz, &negate)) { + if (swz == RC_SWIZZLE_ONE) { + inst->U.I.Opcode = RC_OPCODE_ADD; + if (negate) + inst->U.I.SrcReg[0].Negate ^= RC_MASK_XYZW; + inst->U.I.SrcReg[1] = inst->U.I.SrcReg[2]; + return; + } else if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.SrcReg[0] = inst->U.I.SrcReg[2]; + return; + } + } + + if (is_src_uniform_constant(inst->U.I.SrcReg[0], &swz, &negate)) { + if (swz == RC_SWIZZLE_ONE) { + inst->U.I.Opcode = RC_OPCODE_ADD; + if (negate) + inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; + inst->U.I.SrcReg[0] = inst->U.I.SrcReg[2]; + return; + } else if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.SrcReg[0] = inst->U.I.SrcReg[2]; + return; + } + } +} + +static void constant_folding_mul(struct rc_instruction * inst) +{ + rc_swizzle swz = 0; + unsigned int negate = 0; + + if (is_src_uniform_constant(inst->U.I.SrcReg[0], &swz, &negate)) { + if (swz == RC_SWIZZLE_ONE) { + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.SrcReg[0] = inst->U.I.SrcReg[1]; + if (negate) + inst->U.I.SrcReg[0].Negate ^= RC_MASK_XYZW; + return; + } else if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000; + return; + } + } + + if (is_src_uniform_constant(inst->U.I.SrcReg[1], &swz, &negate)) { + if (swz == RC_SWIZZLE_ONE) { + inst->U.I.Opcode = RC_OPCODE_MOV; + if (negate) + inst->U.I.SrcReg[0].Negate ^= RC_MASK_XYZW; + return; + } else if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000; + return; + } + } +} + +static void constant_folding_add(struct rc_instruction * inst) +{ + rc_swizzle swz = 0; + unsigned int negate = 0; + + if (is_src_uniform_constant(inst->U.I.SrcReg[0], &swz, &negate)) { + if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MOV; + inst->U.I.SrcReg[0] = inst->U.I.SrcReg[1]; + return; + } + } + + if (is_src_uniform_constant(inst->U.I.SrcReg[1], &swz, &negate)) { + if (swz == RC_SWIZZLE_ZERO) { + inst->U.I.Opcode = RC_OPCODE_MOV; + return; + } + } +} + +/** + * Replace 0.0, 1.0 and 0.5 immediate constants by their + * respective swizzles. Simplify instructions like ADD dst, src, 0; + */ +static void constant_folding(struct radeon_compiler * c, struct rc_instruction * inst) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned int i; + + /* Replace 0.0, 1.0 and 0.5 immediates by their explicit swizzles */ + for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { + struct rc_constant * constant; + struct rc_src_register newsrc; + int have_real_reference; + unsigned int chan; + + /* If there are only 0, 0.5, 1, or _ swizzles, mark the source as a constant. */ + for (chan = 0; chan < 4; ++chan) + if (GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan) <= 3) + break; + if (chan == 4) { + inst->U.I.SrcReg[src].File = RC_FILE_NONE; + continue; + } + + /* Convert immediates to swizzles. */ + if (inst->U.I.SrcReg[src].File != RC_FILE_CONSTANT || + inst->U.I.SrcReg[src].RelAddr || + inst->U.I.SrcReg[src].Index >= c->Program.Constants.Count) + continue; + + constant = + &c->Program.Constants.Constants[inst->U.I.SrcReg[src].Index]; + + if (constant->Type != RC_CONSTANT_IMMEDIATE) + continue; + + newsrc = inst->U.I.SrcReg[src]; + have_real_reference = 0; + for (chan = 0; chan < 4; ++chan) { + unsigned int swz = GET_SWZ(newsrc.Swizzle, chan); + unsigned int newswz; + float imm; + float baseimm; + + if (swz >= 4) + continue; + + imm = constant->u.Immediate[swz]; + baseimm = imm; + if (imm < 0.0) + baseimm = -baseimm; + + if (baseimm == 0.0) { + newswz = RC_SWIZZLE_ZERO; + } else if (baseimm == 1.0) { + newswz = RC_SWIZZLE_ONE; + } else if (baseimm == 0.5 && c->has_half_swizzles) { + newswz = RC_SWIZZLE_HALF; + } else { + have_real_reference = 1; + continue; + } + + SET_SWZ(newsrc.Swizzle, chan, newswz); + if (imm < 0.0 && !newsrc.Abs) + newsrc.Negate ^= 1 << chan; + } + + if (!have_real_reference) { + newsrc.File = RC_FILE_NONE; + newsrc.Index = 0; + } + + /* don't make the swizzle worse */ + if (!c->SwizzleCaps->IsNative(inst->U.I.Opcode, newsrc) && + c->SwizzleCaps->IsNative(inst->U.I.Opcode, inst->U.I.SrcReg[src])) + continue; + + inst->U.I.SrcReg[src] = newsrc; + } + + /* Simplify instructions based on constants */ + if (inst->U.I.Opcode == RC_OPCODE_MAD) + constant_folding_mad(inst); + + /* note: MAD can simplify to MUL or ADD */ + if (inst->U.I.Opcode == RC_OPCODE_MUL) + constant_folding_mul(inst); + else if (inst->U.I.Opcode == RC_OPCODE_ADD) + constant_folding_add(inst); + + /* In case this instruction has been converted, make sure all of the + * registers that are no longer used are empty. */ + opcode = rc_get_opcode_info(inst->U.I.Opcode); + for(i = opcode->NumSrcRegs; i < 3; i++) { + memset(&inst->U.I.SrcReg[i], 0, sizeof(struct rc_src_register)); + } +} + +/** + * If src and dst use the same register, this function returns a writemask that + * indicates wich components are read by src. Otherwise zero is returned. + */ +static unsigned int src_reads_dst_mask(struct rc_src_register src, + struct rc_dst_register dst) +{ + if (dst.File != src.File || dst.Index != src.Index) { + return 0; + } + return rc_swizzle_to_writemask(src.Swizzle); +} + +/* Return 1 if the source registers has a constant swizzle (e.g. 0, 0.5, 1.0) + * in any of its channels. Return 0 otherwise. */ +static int src_has_const_swz(struct rc_src_register src) { + int chan; + for(chan = 0; chan < 4; chan++) { + unsigned int swz = GET_SWZ(src.Swizzle, chan); + if (swz == RC_SWIZZLE_ZERO || swz == RC_SWIZZLE_HALF + || swz == RC_SWIZZLE_ONE) { + return 1; + } + } + return 0; +} + +static void presub_scan_read( + void * data, + struct rc_instruction * inst, + struct rc_src_register * src) +{ + struct rc_reader_data * reader_data = data; + rc_presubtract_op * presub_opcode = reader_data->CbData; + + if (!rc_inst_can_use_presub(inst, *presub_opcode, + reader_data->Writer->U.I.DstReg.WriteMask, + src, + &reader_data->Writer->U.I.SrcReg[0], + &reader_data->Writer->U.I.SrcReg[1])) { + reader_data->Abort = 1; + return; + } +} + +static int presub_helper( + struct radeon_compiler * c, + struct rc_instruction * inst_add, + rc_presubtract_op presub_opcode, + rc_presub_replace_fn presub_replace) +{ + struct rc_reader_data reader_data; + unsigned int i; + rc_presubtract_op cb_op = presub_opcode; + + reader_data.CbData = &cb_op; + reader_data.ExitOnAbort = 1; + rc_get_readers(c, inst_add, &reader_data, presub_scan_read, NULL, + is_src_clobbered_scan_write); + + if (reader_data.Abort || reader_data.ReaderCount == 0) + return 0; + + for(i = 0; i < reader_data.ReaderCount; i++) { + unsigned int src_index; + struct rc_reader reader = reader_data.Readers[i]; + const struct rc_opcode_info * info = + rc_get_opcode_info(reader.Inst->U.I.Opcode); + + for (src_index = 0; src_index < info->NumSrcRegs; src_index++) { + if (&reader.Inst->U.I.SrcReg[src_index] == reader.U.I.Src) + presub_replace(inst_add, reader.Inst, src_index); + } + } + return 1; +} + +/* This function assumes that inst_add->U.I.SrcReg[0] and + * inst_add->U.I.SrcReg[1] aren't both negative. */ +static void presub_replace_add( + struct rc_instruction * inst_add, + struct rc_instruction * inst_reader, + unsigned int src_index) +{ + rc_presubtract_op presub_opcode; + if (inst_add->U.I.SrcReg[1].Negate || inst_add->U.I.SrcReg[0].Negate) + presub_opcode = RC_PRESUB_SUB; + else + presub_opcode = RC_PRESUB_ADD; + + if (inst_add->U.I.SrcReg[1].Negate) { + inst_reader->U.I.PreSub.SrcReg[0] = inst_add->U.I.SrcReg[1]; + inst_reader->U.I.PreSub.SrcReg[1] = inst_add->U.I.SrcReg[0]; + } else { + inst_reader->U.I.PreSub.SrcReg[0] = inst_add->U.I.SrcReg[0]; + inst_reader->U.I.PreSub.SrcReg[1] = inst_add->U.I.SrcReg[1]; + } + inst_reader->U.I.PreSub.SrcReg[0].Negate = 0; + inst_reader->U.I.PreSub.SrcReg[1].Negate = 0; + inst_reader->U.I.PreSub.Opcode = presub_opcode; + inst_reader->U.I.SrcReg[src_index] = + chain_srcregs(inst_reader->U.I.SrcReg[src_index], + inst_reader->U.I.PreSub.SrcReg[0]); + inst_reader->U.I.SrcReg[src_index].File = RC_FILE_PRESUB; + inst_reader->U.I.SrcReg[src_index].Index = presub_opcode; +} + +static int is_presub_candidate( + struct radeon_compiler * c, + struct rc_instruction * inst) +{ + const struct rc_opcode_info * info = rc_get_opcode_info(inst->U.I.Opcode); + unsigned int i; + unsigned int is_constant[2] = {0, 0}; + + assert(inst->U.I.Opcode == RC_OPCODE_ADD); + + if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE + || inst->U.I.SaturateMode + || inst->U.I.WriteALUResult) { + return 0; + } + + /* If both sources use a constant swizzle, then we can't convert it to + * a presubtract operation. In fact for the ADD and SUB presubtract + * operations neither source can contain a constant swizzle. This + * specific case is checked in peephole_add_presub_add() when + * we make sure the swizzles for both sources are equal, so we + * don't need to worry about it here. */ + for (i = 0; i < 2; i++) { + int chan; + for (chan = 0; chan < 4; chan++) { + rc_swizzle swz = + get_swz(inst->U.I.SrcReg[i].Swizzle, chan); + if (swz == RC_SWIZZLE_ONE + || swz == RC_SWIZZLE_ZERO + || swz == RC_SWIZZLE_HALF) { + is_constant[i] = 1; + } + } + } + if (is_constant[0] && is_constant[1]) + return 0; + + for(i = 0; i < info->NumSrcRegs; i++) { + struct rc_src_register src = inst->U.I.SrcReg[i]; + if (src_reads_dst_mask(src, inst->U.I.DstReg)) + return 0; + + src.File = RC_FILE_PRESUB; + if (!c->SwizzleCaps->IsNative(inst->U.I.Opcode, src)) + return 0; + } + return 1; +} + +static int peephole_add_presub_add( + struct radeon_compiler * c, + struct rc_instruction * inst_add) +{ + unsigned dstmask = inst_add->U.I.DstReg.WriteMask; + unsigned src0_neg = inst_add->U.I.SrcReg[0].Negate & dstmask; + unsigned src1_neg = inst_add->U.I.SrcReg[1].Negate & dstmask; + + if (inst_add->U.I.SrcReg[0].Swizzle != inst_add->U.I.SrcReg[1].Swizzle) + return 0; + + /* src0 and src1 can't have absolute values */ + if (inst_add->U.I.SrcReg[0].Abs || inst_add->U.I.SrcReg[1].Abs) + return 0; + + /* presub_replace_add() assumes only one is negative */ + if (inst_add->U.I.SrcReg[0].Negate && inst_add->U.I.SrcReg[1].Negate) + return 0; + + /* if src0 is negative, at least all bits of dstmask have to be set */ + if (inst_add->U.I.SrcReg[0].Negate && src0_neg != dstmask) + return 0; + + /* if src1 is negative, at least all bits of dstmask have to be set */ + if (inst_add->U.I.SrcReg[1].Negate && src1_neg != dstmask) + return 0; + + if (!is_presub_candidate(c, inst_add)) + return 0; + + if (presub_helper(c, inst_add, RC_PRESUB_ADD, presub_replace_add)) { + rc_remove_instruction(inst_add); + return 1; + } + return 0; +} + +static void presub_replace_inv( + struct rc_instruction * inst_add, + struct rc_instruction * inst_reader, + unsigned int src_index) +{ + /* We must be careful not to modify inst_add, since it + * is possible it will remain part of the program.*/ + inst_reader->U.I.PreSub.SrcReg[0] = inst_add->U.I.SrcReg[1]; + inst_reader->U.I.PreSub.SrcReg[0].Negate = 0; + inst_reader->U.I.PreSub.Opcode = RC_PRESUB_INV; + inst_reader->U.I.SrcReg[src_index] = chain_srcregs(inst_reader->U.I.SrcReg[src_index], + inst_reader->U.I.PreSub.SrcReg[0]); + + inst_reader->U.I.SrcReg[src_index].File = RC_FILE_PRESUB; + inst_reader->U.I.SrcReg[src_index].Index = RC_PRESUB_INV; +} + +/** + * PRESUB_INV: ADD TEMP[0], none.1, -TEMP[1] + * Use the presubtract 1 - src0 for all readers of TEMP[0]. The first source + * of the add instruction must have the constatnt 1 swizzle. This function + * does not check const registers to see if their value is 1.0, so it should + * be called after the constant_folding optimization. + * @return + * 0 if the ADD instruction is still part of the program. + * 1 if the ADD instruction is no longer part of the program. + */ +static int peephole_add_presub_inv( + struct radeon_compiler * c, + struct rc_instruction * inst_add) +{ + unsigned int i, swz; + + if (!is_presub_candidate(c, inst_add)) + return 0; + + /* Check if src0 is 1. */ + /* XXX It would be nice to use is_src_uniform_constant here, but that + * function only works if the register's file is RC_FILE_NONE */ + for(i = 0; i < 4; i++ ) { + swz = GET_SWZ(inst_add->U.I.SrcReg[0].Swizzle, i); + if(((1 << i) & inst_add->U.I.DstReg.WriteMask) + && swz != RC_SWIZZLE_ONE) { + return 0; + } + } + + /* Check src1. */ + if ((inst_add->U.I.SrcReg[1].Negate & inst_add->U.I.DstReg.WriteMask) != + inst_add->U.I.DstReg.WriteMask + || inst_add->U.I.SrcReg[1].Abs + || (inst_add->U.I.SrcReg[1].File != RC_FILE_TEMPORARY + && inst_add->U.I.SrcReg[1].File != RC_FILE_CONSTANT) + || src_has_const_swz(inst_add->U.I.SrcReg[1])) { + + return 0; + } + + if (presub_helper(c, inst_add, RC_PRESUB_INV, presub_replace_inv)) { + rc_remove_instruction(inst_add); + return 1; + } + return 0; +} + +/** + * @return + * 0 if inst is still part of the program. + * 1 if inst is no longer part of the program. + */ +static int peephole(struct radeon_compiler * c, struct rc_instruction * inst) +{ + switch(inst->U.I.Opcode){ + case RC_OPCODE_ADD: + if (c->has_presub) { + if(peephole_add_presub_inv(c, inst)) + return 1; + if(peephole_add_presub_add(c, inst)) + return 1; + } + break; + default: + break; + } + return 0; +} + +void rc_optimize(struct radeon_compiler * c, void *user) +{ + struct rc_instruction * inst = c->Program.Instructions.Next; + while(inst != &c->Program.Instructions) { + struct rc_instruction * cur = inst; + inst = inst->Next; + + constant_folding(c, cur); + + if(peephole(c, cur)) + continue; + + if (cur->U.I.Opcode == RC_OPCODE_MOV) { + copy_propagate(c, cur); + /* cur may no longer be part of the program */ + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_dead_sources.c b/src/gallium/drivers/r300/compiler/radeon_pair_dead_sources.c new file mode 100644 index 00000000000..1e9a2c09d44 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_pair_dead_sources.c @@ -0,0 +1,62 @@ + +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" +#include "radeon_opcodes.h" +#include "radeon_program_pair.h" + +static void mark_used_presub(struct rc_pair_sub_instruction * sub) +{ + if (sub->Src[RC_PAIR_PRESUB_SRC].Used) { + unsigned int presub_reg_count = rc_presubtract_src_reg_count( + sub->Src[RC_PAIR_PRESUB_SRC].Index); + unsigned int i; + for (i = 0; i < presub_reg_count; i++) { + sub->Src[i].Used = 1; + } + } +} + +static void mark_used( + struct rc_instruction * inst, + struct rc_pair_sub_instruction * sub) +{ + unsigned int i; + const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); + for (i = 0; i < info->NumSrcRegs; i++) { + unsigned int src_type = rc_source_type_swz(sub->Arg[i].Swizzle); + if (src_type & RC_SOURCE_RGB) { + inst->U.P.RGB.Src[sub->Arg[i].Source].Used = 1; + } + + if (src_type & RC_SOURCE_ALPHA) { + inst->U.P.Alpha.Src[sub->Arg[i].Source].Used = 1; + } + } +} + +/** + * This pass finds sources that are not used by their instruction and marks + * them as unused. + */ +void rc_pair_remove_dead_sources(struct radeon_compiler * c, void *user) +{ + struct rc_instruction * inst; + for (inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next) { + unsigned int i; + if (inst->Type == RC_INSTRUCTION_NORMAL) + continue; + + /* Mark all sources as unused */ + for (i = 0; i < 4; i++) { + inst->U.P.RGB.Src[i].Used = 0; + inst->U.P.Alpha.Src[i].Used = 0; + } + mark_used(inst, &inst->U.P.RGB); + mark_used(inst, &inst->U.P.Alpha); + + mark_used_presub(&inst->U.P.RGB); + mark_used_presub(&inst->U.P.Alpha); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c new file mode 100644 index 00000000000..49983d6ce75 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c @@ -0,0 +1,706 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * Copyright 2011 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_program_pair.h" + +#include <stdio.h> + +#include "main/glheader.h" +#include "program/register_allocate.h" +#include "ralloc.h" + +#include "r300_fragprog_swizzle.h" +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" +#include "radeon_dataflow.h" +#include "radeon_list.h" +#include "radeon_variable.h" + +#define VERBOSE 0 + +#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) + + + +struct register_info { + struct live_intervals Live[4]; + + unsigned int Used:1; + unsigned int Allocated:1; + unsigned int File:3; + unsigned int Index:RC_REGISTER_INDEX_BITS; + unsigned int Writemask; +}; + +struct regalloc_state { + struct radeon_compiler * C; + + struct register_info * Input; + unsigned int NumInputs; + + struct register_info * Temporary; + unsigned int NumTemporaries; + + unsigned int Simple; + int LoopEnd; +}; + +enum rc_reg_class { + RC_REG_CLASS_SINGLE, + RC_REG_CLASS_DOUBLE, + RC_REG_CLASS_TRIPLE, + RC_REG_CLASS_ALPHA, + RC_REG_CLASS_SINGLE_PLUS_ALPHA, + RC_REG_CLASS_DOUBLE_PLUS_ALPHA, + RC_REG_CLASS_TRIPLE_PLUS_ALPHA, + RC_REG_CLASS_X, + RC_REG_CLASS_Y, + RC_REG_CLASS_Z, + RC_REG_CLASS_XY, + RC_REG_CLASS_YZ, + RC_REG_CLASS_XZ, + RC_REG_CLASS_XW, + RC_REG_CLASS_YW, + RC_REG_CLASS_ZW, + RC_REG_CLASS_XYW, + RC_REG_CLASS_YZW, + RC_REG_CLASS_XZW, + RC_REG_CLASS_COUNT +}; + +struct rc_class { + enum rc_reg_class Class; + + unsigned int WritemaskCount; + + /** This is 1 if this class is being used by the register allocator + * and 0 otherwise */ + unsigned int Used; + + /** This is the ID number assigned to this class by ra. */ + unsigned int Id; + + /** List of writemasks that belong to this class */ + unsigned int Writemasks[3]; + + +}; + +static void print_live_intervals(struct live_intervals * src) +{ + if (!src || !src->Used) { + DBG("(null)"); + return; + } + + DBG("(%i,%i)", src->Start, src->End); +} + +static int overlap_live_intervals(struct live_intervals * a, struct live_intervals * b) +{ + if (VERBOSE) { + DBG("overlap_live_intervals: "); + print_live_intervals(a); + DBG(" to "); + print_live_intervals(b); + DBG("\n"); + } + + if (!a->Used || !b->Used) { + DBG(" unused interval\n"); + return 0; + } + + if (a->Start > b->Start) { + if (a->Start < b->End) { + DBG(" overlap\n"); + return 1; + } + } else if (b->Start > a->Start) { + if (b->Start < a->End) { + DBG(" overlap\n"); + return 1; + } + } else { /* a->Start == b->Start */ + if (a->Start != a->End && b->Start != b->End) { + DBG(" overlap\n"); + return 1; + } + } + + DBG(" no overlap\n"); + + return 0; +} + +static void scan_read_callback(void * data, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int mask) +{ + struct regalloc_state * s = data; + struct register_info * reg; + unsigned int i; + + if (file != RC_FILE_INPUT) + return; + + s->Input[index].Used = 1; + reg = &s->Input[index]; + + for (i = 0; i < 4; i++) { + if (!((mask >> i) & 0x1)) { + continue; + } + reg->Live[i].Used = 1; + reg->Live[i].Start = 0; + reg->Live[i].End = + s->LoopEnd > inst->IP ? s->LoopEnd : inst->IP; + } +} + +static void remap_register(void * data, struct rc_instruction * inst, + rc_register_file * file, unsigned int * index) +{ + struct regalloc_state * s = data; + const struct register_info * reg; + + if (*file == RC_FILE_TEMPORARY && s->Simple) + reg = &s->Temporary[*index]; + else if (*file == RC_FILE_INPUT) + reg = &s->Input[*index]; + else + return; + + if (reg->Allocated) { + *index = reg->Index; + } +} + +static void alloc_input_simple(void * data, unsigned int input, + unsigned int hwreg) +{ + struct regalloc_state * s = data; + + if (input >= s->NumInputs) + return; + + s->Input[input].Allocated = 1; + s->Input[input].File = RC_FILE_TEMPORARY; + s->Input[input].Index = hwreg; +} + +/* This functions offsets the temporary register indices by the number + * of input registers, because input registers are actually temporaries and + * should not occupy the same space. + * + * This pass is supposed to be used to maintain correct allocation of inputs + * if the standard register allocation is disabled. */ +static void do_regalloc_inputs_only(struct regalloc_state * s) +{ + for (unsigned i = 0; i < s->NumTemporaries; i++) { + s->Temporary[i].Allocated = 1; + s->Temporary[i].File = RC_FILE_TEMPORARY; + s->Temporary[i].Index = i + s->NumInputs; + } +} + +static unsigned int is_derivative(rc_opcode op) +{ + return (op == RC_OPCODE_DDX || op == RC_OPCODE_DDY); +} + +static int find_class( + struct rc_class * classes, + unsigned int writemask, + unsigned int max_writemask_count) +{ + unsigned int i; + for (i = 0; i < RC_REG_CLASS_COUNT; i++) { + unsigned int j; + if (classes[i].WritemaskCount > max_writemask_count) { + continue; + } + for (j = 0; j < 3; j++) { + if (classes[i].Writemasks[j] == writemask) { + return i; + } + } + } + return -1; +} + +static enum rc_reg_class variable_get_class( + struct rc_variable * variable, + struct rc_class * classes) +{ + unsigned int i; + unsigned int can_change_writemask= 1; + unsigned int writemask = rc_variable_writemask_sum(variable); + struct rc_list * readers = rc_variable_readers_union(variable); + int class_index; + + if (!variable->C->is_r500) { + struct rc_class c; + /* The assumption here is that if an instruction has type + * RC_INSTRUCTION_NORMAL then it is a TEX instruction. + * r300 and r400 can't swizzle the result of a TEX lookup. */ + if (variable->Inst->Type == RC_INSTRUCTION_NORMAL) { + writemask = RC_MASK_XYZW; + } + + /* Check if it is possible to do swizzle packing for r300/r400 + * without creating non-native swizzles. */ + class_index = find_class(classes, writemask, 3); + if (class_index < 0) { + goto error; + } + c = classes[class_index]; + for (i = 0; i < c.WritemaskCount; i++) { + int j; + unsigned int conversion_swizzle = + rc_make_conversion_swizzle( + writemask, c.Writemasks[i]); + for (j = 0; j < variable->ReaderCount; j++) { + unsigned int old_swizzle; + unsigned int new_swizzle; + struct rc_reader r = variable->Readers[j]; + if (r.Inst->Type == RC_INSTRUCTION_PAIR ) { + old_swizzle = r.U.P.Arg->Swizzle; + } else { + old_swizzle = r.U.I.Src->Swizzle; + } + new_swizzle = rc_adjust_channels( + old_swizzle, conversion_swizzle); + if (!r300_swizzle_is_native_basic(new_swizzle)) { + can_change_writemask = 0; + break; + } + } + if (!can_change_writemask) { + break; + } + } + } + + if (variable->Inst->Type == RC_INSTRUCTION_PAIR) { + /* DDX/DDY seem to always fail when their writemasks are + * changed.*/ + if (is_derivative(variable->Inst->U.P.RGB.Opcode) + || is_derivative(variable->Inst->U.P.Alpha.Opcode)) { + can_change_writemask = 0; + } + } + for ( ; readers; readers = readers->Next) { + struct rc_reader * r = readers->Item; + if (r->Inst->Type == RC_INSTRUCTION_PAIR) { + if (r->U.P.Arg->Source == RC_PAIR_PRESUB_SRC) { + can_change_writemask = 0; + break; + } + /* DDX/DDY also fail when their swizzles are changed. */ + if (is_derivative(r->Inst->U.P.RGB.Opcode) + || is_derivative(r->Inst->U.P.Alpha.Opcode)) { + can_change_writemask = 0; + break; + } + } + } + + class_index = find_class(classes, writemask, + can_change_writemask ? 3 : 1); + if (class_index > -1) { + return classes[class_index].Class; + } else { +error: + rc_error(variable->C, + "Could not find class for index=%u mask=%u\n", + variable->Dst.Index, writemask); + return 0; + } +} + +static unsigned int overlap_live_intervals_array( + struct live_intervals * a, + struct live_intervals * b) +{ + unsigned int a_chan, b_chan; + for (a_chan = 0; a_chan < 4; a_chan++) { + for (b_chan = 0; b_chan < 4; b_chan++) { + if (overlap_live_intervals(&a[a_chan], &b[b_chan])) { + return 1; + } + } + } + return 0; +} + +static unsigned int reg_get_index(int reg) +{ + return reg / RC_MASK_XYZW; +} + +static unsigned int reg_get_writemask(int reg) +{ + return (reg % RC_MASK_XYZW) + 1; +} + +static int get_reg_id(unsigned int index, unsigned int writemask) +{ + assert(writemask); + if (writemask == 0) { + return 0; + } + return (index * RC_MASK_XYZW) + (writemask - 1); +} + +#if VERBOSE +static void print_reg(int reg) +{ + unsigned int index = reg_get_index(reg); + unsigned int mask = reg_get_writemask(reg); + fprintf(stderr, "Temp[%u].%c%c%c%c", index, + mask & RC_MASK_X ? 'x' : '_', + mask & RC_MASK_Y ? 'y' : '_', + mask & RC_MASK_Z ? 'z' : '_', + mask & RC_MASK_W ? 'w' : '_'); +} +#endif + +static void add_register_conflicts( + struct ra_regs * regs, + unsigned int max_temp_regs) +{ + unsigned int index, a_mask, b_mask; + for (index = 0; index < max_temp_regs; index++) { + for(a_mask = 1; a_mask <= RC_MASK_XYZW; a_mask++) { + for (b_mask = a_mask + 1; b_mask <= RC_MASK_XYZW; + b_mask++) { + if (a_mask & b_mask) { + ra_add_reg_conflict(regs, + get_reg_id(index, a_mask), + get_reg_id(index, b_mask)); + } + } + } + } +} + +static void do_advanced_regalloc(struct regalloc_state * s) +{ + struct rc_class rc_class_list [] = { + {RC_REG_CLASS_SINGLE, 3, 0, 0, + {RC_MASK_X, + RC_MASK_Y, + RC_MASK_Z}}, + {RC_REG_CLASS_DOUBLE, 3, 0, 0, + {RC_MASK_X | RC_MASK_Y, + RC_MASK_X | RC_MASK_Z, + RC_MASK_Y | RC_MASK_Z}}, + {RC_REG_CLASS_TRIPLE, 1, 0, 0, + {RC_MASK_X | RC_MASK_Y | RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_ALPHA, 1, 0, 0, + {RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_SINGLE_PLUS_ALPHA, 3, 0, 0, + {RC_MASK_X | RC_MASK_W, + RC_MASK_Y | RC_MASK_W, + RC_MASK_Z | RC_MASK_W}}, + {RC_REG_CLASS_DOUBLE_PLUS_ALPHA, 3, 0, 0, + {RC_MASK_X | RC_MASK_Y | RC_MASK_W, + RC_MASK_X | RC_MASK_Z | RC_MASK_W, + RC_MASK_Y | RC_MASK_Z | RC_MASK_W}}, + {RC_REG_CLASS_TRIPLE_PLUS_ALPHA, 1, 0, 0, + {RC_MASK_X | RC_MASK_Y | RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_X, 1, 0, 0, + {RC_MASK_X, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_Y, 1, 0, 0, + {RC_MASK_Y, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_Z, 1, 0, 0, + {RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XY, 1, 0, 0, + {RC_MASK_X | RC_MASK_Y, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_YZ, 1, 0, 0, + {RC_MASK_Y | RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XZ, 1, 0, 0, + {RC_MASK_X | RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XW, 1, 0, 0, + {RC_MASK_X | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_YW, 1, 0, 0, + {RC_MASK_Y | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_ZW, 1, 0, 0, + {RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XYW, 1, 0, 0, + {RC_MASK_X | RC_MASK_Y | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_YZW, 1, 0, 0, + {RC_MASK_Y | RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XZW, 1, 0, 0, + {RC_MASK_X | RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}} + }; + + unsigned int i, j, index, input_node, node_count, node_index; + unsigned int * node_classes; + unsigned int * input_classes; + struct rc_instruction * inst; + struct rc_list * var_ptr; + struct rc_list * variables; + struct ra_regs * regs; + struct ra_graph * graph; + + /* Allocate the main ra data structure */ + regs = ra_alloc_reg_set(s->C->max_temp_regs * RC_MASK_XYZW); + + /* Get list of program variables */ + variables = rc_get_variables(s->C); + node_count = rc_list_count(variables); + node_classes = memory_pool_malloc(&s->C->Pool, + node_count * sizeof(unsigned int)); + input_classes = memory_pool_malloc(&s->C->Pool, + s->NumInputs * sizeof(unsigned int)); + + for (var_ptr = variables, node_index = 0; var_ptr; + var_ptr = var_ptr->Next, node_index++) { + unsigned int class_index; + /* Compute the live intervals */ + rc_variable_compute_live_intervals(var_ptr->Item); + + class_index = variable_get_class(var_ptr->Item, rc_class_list); + + /* If we haven't used this register class yet, mark it + * as used and allocate space for it. */ + if (!rc_class_list[class_index].Used) { + rc_class_list[class_index].Used = 1; + rc_class_list[class_index].Id = ra_alloc_reg_class(regs); + } + + node_classes[node_index] = rc_class_list[class_index].Id; + } + + + /* Assign registers to the classes */ + for (i = 0; i < RC_REG_CLASS_COUNT; i++) { + struct rc_class class = rc_class_list[i]; + if (!class.Used) { + continue; + } + + for (index = 0; index < s->C->max_temp_regs; index++) { + for (j = 0; j < class.WritemaskCount; j++) { + int reg_id = get_reg_id(index, + class.Writemasks[j]); + ra_class_add_reg(regs, class.Id, reg_id); + } + } + } + + /* Add register conflicts */ + add_register_conflicts(regs, s->C->max_temp_regs); + + /* Calculate live intervals for input registers */ + for (inst = s->C->Program.Instructions.Next; + inst != &s->C->Program.Instructions; + inst = inst->Next) { + rc_opcode op = rc_get_flow_control_inst(inst); + if (op == RC_OPCODE_BGNLOOP) { + struct rc_instruction * endloop = + rc_match_bgnloop(inst); + if (endloop->IP > s->LoopEnd) { + s->LoopEnd = endloop->IP; + } + } + rc_for_all_reads_mask(inst, scan_read_callback, s); + } + + /* Create classes for input registers */ + for (i = 0; i < s->NumInputs; i++) { + unsigned int chan, class_id, writemask = 0; + for (chan = 0; chan < 4; chan++) { + if (s->Input[i].Live[chan].Used) { + writemask |= (1 << chan); + } + } + s->Input[i].Writemask = writemask; + if (!writemask) { + continue; + } + + class_id = ra_alloc_reg_class(regs); + input_classes[i] = class_id; + ra_class_add_reg(regs, class_id, + get_reg_id(s->Input[i].Index, writemask)); + } + + ra_set_finalize(regs); + + graph = ra_alloc_interference_graph(regs, node_count + s->NumInputs); + + /* Build the interference graph */ + for (var_ptr = variables, node_index = 0; var_ptr; + var_ptr = var_ptr->Next,node_index++) { + struct rc_list * a, * b; + unsigned int b_index; + + ra_set_node_class(graph, node_index, node_classes[node_index]); + + for (a = var_ptr, b = var_ptr->Next, b_index = node_index + 1; + b; b = b->Next, b_index++) { + struct rc_variable * var_a = a->Item; + while (var_a) { + struct rc_variable * var_b = b->Item; + while (var_b) { + if (overlap_live_intervals_array(var_a->Live, var_b->Live)) { + ra_add_node_interference(graph, + node_index, b_index); + } + var_b = var_b->Friend; + } + var_a = var_a->Friend; + } + } + } + + /* Add input registers to the interference graph */ + for (i = 0, input_node = 0; i< s->NumInputs; i++) { + if (!s->Input[i].Writemask) { + continue; + } + ra_set_node_class(graph, node_count + input_node, + input_classes[i]); + for (var_ptr = variables, node_index = 0; + var_ptr; var_ptr = var_ptr->Next, node_index++) { + struct rc_variable * var = var_ptr->Item; + if (overlap_live_intervals_array(s->Input[i].Live, + var->Live)) { + ra_add_node_interference(graph, node_index, + node_count + input_node); + } + } + /* Manually allocate a register for this input */ + ra_set_node_reg(graph, node_count + input_node, get_reg_id( + s->Input[i].Index, s->Input[i].Writemask)); + input_node++; + } + + if (!ra_allocate_no_spills(graph)) { + rc_error(s->C, "Ran out of hardware temporaries\n"); + return; + } + + /* Rewrite the registers */ + for (var_ptr = variables, node_index = 0; var_ptr; + var_ptr = var_ptr->Next, node_index++) { + int reg = ra_get_node_reg(graph, node_index); + unsigned int writemask = reg_get_writemask(reg); + unsigned int index = reg_get_index(reg); + struct rc_variable * var = var_ptr->Item; + + if (!s->C->is_r500 && var->Inst->Type == RC_INSTRUCTION_NORMAL) { + writemask = rc_variable_writemask_sum(var); + } + + if (var->Dst.File == RC_FILE_INPUT) { + continue; + } + rc_variable_change_dst(var, index, writemask); + } + + ralloc_free(graph); + ralloc_free(regs); +} + +/** + * @param user This parameter should be a pointer to an integer value. If this + * integer value is zero, then a simple register allocator will be used that + * only allocates space for input registers (\sa do_regalloc_inputs_only). If + * user is non-zero, then the regular register allocator will be used + * (\sa do_regalloc). + */ +void rc_pair_regalloc(struct radeon_compiler *cc, void *user) +{ + struct r300_fragment_program_compiler *c = + (struct r300_fragment_program_compiler*)cc; + struct regalloc_state s; + int * do_full_regalloc = (int*)user; + + memset(&s, 0, sizeof(s)); + s.C = cc; + s.NumInputs = rc_get_max_index(cc, RC_FILE_INPUT) + 1; + s.Input = memory_pool_malloc(&cc->Pool, + s.NumInputs * sizeof(struct register_info)); + memset(s.Input, 0, s.NumInputs * sizeof(struct register_info)); + + s.NumTemporaries = rc_get_max_index(cc, RC_FILE_TEMPORARY) + 1; + s.Temporary = memory_pool_malloc(&cc->Pool, + s.NumTemporaries * sizeof(struct register_info)); + memset(s.Temporary, 0, s.NumTemporaries * sizeof(struct register_info)); + + rc_recompute_ips(s.C); + + c->AllocateHwInputs(c, &alloc_input_simple, &s); + if (*do_full_regalloc) { + do_advanced_regalloc(&s); + } else { + s.Simple = 1; + do_regalloc_inputs_only(&s); + } + + /* Rewrite inputs and if we are doing the simple allocation, rewrite + * temporaries too. */ + for (struct rc_instruction *inst = s.C->Program.Instructions.Next; + inst != &s.C->Program.Instructions; + inst = inst->Next) { + rc_remap_registers(inst, &remap_register, &s); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c b/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c new file mode 100644 index 00000000000..25cd52c9cd4 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c @@ -0,0 +1,1010 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_program_pair.h" + +#include <stdio.h> + +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" +#include "radeon_dataflow.h" + + +#define VERBOSE 0 + +#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) + +struct schedule_instruction { + struct rc_instruction * Instruction; + + /** Next instruction in the linked list of ready instructions. */ + struct schedule_instruction *NextReady; + + /** Values that this instruction reads and writes */ + struct reg_value * WriteValues[4]; + struct reg_value * ReadValues[12]; + unsigned int NumWriteValues:3; + unsigned int NumReadValues:4; + + /** + * Number of (read and write) dependencies that must be resolved before + * this instruction can be scheduled. + */ + unsigned int NumDependencies:5; + + /** List of all readers (see rc_get_readers() for the definition of + * "all readers"), even those outside the basic block this instruction + * lives in. */ + struct rc_reader_data GlobalReaders; +}; + + +/** + * Used to keep track of which instructions read a value. + */ +struct reg_value_reader { + struct schedule_instruction *Reader; + struct reg_value_reader *Next; +}; + +/** + * Used to keep track which values are stored in each component of a + * RC_FILE_TEMPORARY. + */ +struct reg_value { + struct schedule_instruction * Writer; + + /** + * Unordered linked list of instructions that read from this value. + * When this value becomes available, we increase all readers' + * dependency count. + */ + struct reg_value_reader *Readers; + + /** + * Number of readers of this value. This is decremented each time + * a reader of the value is committed. + * When the reader cound reaches zero, the dependency count + * of the instruction writing \ref Next is decremented. + */ + unsigned int NumReaders; + + struct reg_value *Next; /**< Pointer to the next value to be written to the same register */ +}; + +struct register_state { + struct reg_value * Values[4]; +}; + +struct remap_reg { + struct rc_instruciont * Inst; + unsigned int OldIndex:(RC_REGISTER_INDEX_BITS+1); + unsigned int OldSwizzle:3; + unsigned int NewIndex:(RC_REGISTER_INDEX_BITS+1); + unsigned int NewSwizzle:3; + unsigned int OnlyTexReads:1; + struct remap_reg * Next; +}; + +struct schedule_state { + struct radeon_compiler * C; + struct schedule_instruction * Current; + + struct register_state Temporary[RC_REGISTER_MAX_INDEX]; + + /** + * Linked lists of instructions that can be scheduled right now, + * based on which ALU/TEX resources they require. + */ + /*@{*/ + struct schedule_instruction *ReadyFullALU; + struct schedule_instruction *ReadyRGB; + struct schedule_instruction *ReadyAlpha; + struct schedule_instruction *ReadyTEX; + /*@}*/ +}; + +static struct reg_value ** get_reg_valuep(struct schedule_state * s, + rc_register_file file, unsigned int index, unsigned int chan) +{ + if (file != RC_FILE_TEMPORARY) + return 0; + + if (index >= RC_REGISTER_MAX_INDEX) { + rc_error(s->C, "%s: index %i out of bounds\n", __FUNCTION__, index); + return 0; + } + + return &s->Temporary[index].Values[chan]; +} + +static void add_inst_to_list(struct schedule_instruction ** list, struct schedule_instruction * inst) +{ + inst->NextReady = *list; + *list = inst; +} + +static void add_inst_to_list_end(struct schedule_instruction ** list, + struct schedule_instruction * inst) +{ + if(!*list){ + *list = inst; + }else{ + struct schedule_instruction * temp = *list; + while(temp->NextReady){ + temp = temp->NextReady; + } + temp->NextReady = inst; + } +} + +static void instruction_ready(struct schedule_state * s, struct schedule_instruction * sinst) +{ + DBG("%i is now ready\n", sinst->Instruction->IP); + + /* Adding Ready TEX instructions to the end of the "Ready List" helps + * us emit TEX instructions in blocks without losing our place. */ + if (sinst->Instruction->Type == RC_INSTRUCTION_NORMAL) + add_inst_to_list_end(&s->ReadyTEX, sinst); + else if (sinst->Instruction->U.P.Alpha.Opcode == RC_OPCODE_NOP) + add_inst_to_list(&s->ReadyRGB, sinst); + else if (sinst->Instruction->U.P.RGB.Opcode == RC_OPCODE_NOP) + add_inst_to_list(&s->ReadyAlpha, sinst); + else + add_inst_to_list(&s->ReadyFullALU, sinst); +} + +static void decrease_dependencies(struct schedule_state * s, struct schedule_instruction * sinst) +{ + assert(sinst->NumDependencies > 0); + sinst->NumDependencies--; + if (!sinst->NumDependencies) + instruction_ready(s, sinst); +} + +/** + * This function decreases the dependencies of the next instruction that + * wants to write to each of sinst's read values. + */ +static void commit_update_reads(struct schedule_state * s, + struct schedule_instruction * sinst){ + unsigned int i; + for(i = 0; i < sinst->NumReadValues; ++i) { + struct reg_value * v = sinst->ReadValues[i]; + assert(v->NumReaders > 0); + v->NumReaders--; + if (!v->NumReaders) { + if (v->Next) + decrease_dependencies(s, v->Next->Writer); + } + } +} + +static void commit_update_writes(struct schedule_state * s, + struct schedule_instruction * sinst){ + unsigned int i; + for(i = 0; i < sinst->NumWriteValues; ++i) { + struct reg_value * v = sinst->WriteValues[i]; + if (v->NumReaders) { + for(struct reg_value_reader * r = v->Readers; r; r = r->Next) { + decrease_dependencies(s, r->Reader); + } + } else { + /* This happens in instruction sequences of the type + * OP r.x, ...; + * OP r.x, r.x, ...; + * See also the subtlety in how instructions that both + * read and write the same register are scanned. + */ + if (v->Next) + decrease_dependencies(s, v->Next->Writer); + } + } +} + +static void commit_alu_instruction(struct schedule_state * s, struct schedule_instruction * sinst) +{ + DBG("%i: commit\n", sinst->Instruction->IP); + + commit_update_reads(s, sinst); + + commit_update_writes(s, sinst); +} + +/** + * Emit all ready texture instructions in a single block. + * + * Emit as a single block to (hopefully) sample many textures in parallel, + * and to avoid hardware indirections on R300. + */ +static void emit_all_tex(struct schedule_state * s, struct rc_instruction * before) +{ + struct schedule_instruction *readytex; + struct rc_instruction * inst_begin; + + assert(s->ReadyTEX); + + /* Node marker for R300 */ + inst_begin = rc_insert_new_instruction(s->C, before->Prev); + inst_begin->U.I.Opcode = RC_OPCODE_BEGIN_TEX; + + /* Link texture instructions back in */ + readytex = s->ReadyTEX; + while(readytex) { + rc_insert_instruction(before->Prev, readytex->Instruction); + DBG("%i: commit TEX reads\n", readytex->Instruction->IP); + + /* All of the TEX instructions in the same TEX block have + * their source registers read from before any of the + * instructions in that block write to their destination + * registers. This means that when we commit a TEX + * instruction, any other TEX instruction that wants to write + * to one of the committed instruction's source register can be + * marked as ready and should be emitted in the same TEX + * block. This prevents the following sequence from being + * emitted in two different TEX blocks: + * 0: TEX temp[0].xyz, temp[1].xy__, 2D[0]; + * 1: TEX temp[1].xyz, temp[2].xy__, 2D[0]; + */ + commit_update_reads(s, readytex); + readytex = readytex->NextReady; + } + readytex = s->ReadyTEX; + s->ReadyTEX = 0; + while(readytex){ + DBG("%i: commit TEX writes\n", readytex->Instruction->IP); + commit_update_writes(s, readytex); + readytex = readytex->NextReady; + } +} + +/* This is a helper function for destructive_merge_instructions(). It helps + * merge presubtract sources from two instructions and makes sure the + * presubtract sources end up in the correct spot. This function assumes that + * dst_full is an rgb instruction, meaning that it has a vector instruction(rgb) + * but no scalar instruction (alpha). + * @return 0 if merging the presubtract sources fails. + * @retrun 1 if merging the presubtract sources succeeds. + */ +static int merge_presub_sources( + struct rc_pair_instruction * dst_full, + struct rc_pair_sub_instruction src, + unsigned int type) +{ + unsigned int srcp_src, srcp_regs, is_rgb, is_alpha; + struct rc_pair_sub_instruction * dst_sub; + const struct rc_opcode_info * info; + + assert(dst_full->Alpha.Opcode == RC_OPCODE_NOP); + + switch(type) { + case RC_SOURCE_RGB: + is_rgb = 1; + is_alpha = 0; + dst_sub = &dst_full->RGB; + break; + case RC_SOURCE_ALPHA: + is_rgb = 0; + is_alpha = 1; + dst_sub = &dst_full->Alpha; + break; + default: + assert(0); + return 0; + } + + info = rc_get_opcode_info(dst_full->RGB.Opcode); + + if (dst_sub->Src[RC_PAIR_PRESUB_SRC].Used) + return 0; + + srcp_regs = rc_presubtract_src_reg_count( + src.Src[RC_PAIR_PRESUB_SRC].Index); + for(srcp_src = 0; srcp_src < srcp_regs; srcp_src++) { + unsigned int arg; + int free_source; + unsigned int one_way = 0; + struct rc_pair_instruction_source srcp = src.Src[srcp_src]; + struct rc_pair_instruction_source temp; + + free_source = rc_pair_alloc_source(dst_full, is_rgb, is_alpha, + srcp.File, srcp.Index); + + /* If free_source < 0 then there are no free source + * slots. */ + if (free_source < 0) + return 0; + + temp = dst_sub->Src[srcp_src]; + dst_sub->Src[srcp_src] = dst_sub->Src[free_source]; + + /* srcp needs src0 and src1 to be the same */ + if (free_source < srcp_src) { + if (!temp.Used) + continue; + free_source = rc_pair_alloc_source(dst_full, is_rgb, + is_alpha, temp.File, temp.Index); + if (free_source < 0) + return 0; + one_way = 1; + } else { + dst_sub->Src[free_source] = temp; + } + + /* If free_source == srcp_src, then the presubtract + * source is already in the correct place. */ + if (free_source == srcp_src) + continue; + + /* Shuffle the sources, so we can put the + * presubtract source in the correct place. */ + for(arg = 0; arg < info->NumSrcRegs; arg++) { + /*If this arg does not read from an rgb source, + * do nothing. */ + if (!(rc_source_type_swz(dst_full->RGB.Arg[arg].Swizzle) + & type)) { + continue; + } + + if (dst_full->RGB.Arg[arg].Source == srcp_src) + dst_full->RGB.Arg[arg].Source = free_source; + /* We need to do this just in case register + * is one of the sources already, but in the + * wrong spot. */ + else if(dst_full->RGB.Arg[arg].Source == free_source + && !one_way) { + dst_full->RGB.Arg[arg].Source = srcp_src; + } + } + } + return 1; +} + + +/* This function assumes that rgb.Alpha and alpha.RGB are unused */ +static int destructive_merge_instructions( + struct rc_pair_instruction * rgb, + struct rc_pair_instruction * alpha) +{ + const struct rc_opcode_info * opcode; + + assert(rgb->Alpha.Opcode == RC_OPCODE_NOP); + assert(alpha->RGB.Opcode == RC_OPCODE_NOP); + + /* Presubtract registers need to be merged first so that registers + * needed by the presubtract operation can be placed in src0 and/or + * src1. */ + + /* Merge the rgb presubtract registers. */ + if (alpha->RGB.Src[RC_PAIR_PRESUB_SRC].Used) { + if (!merge_presub_sources(rgb, alpha->RGB, RC_SOURCE_RGB)) { + return 0; + } + } + /* Merge the alpha presubtract registers */ + if (alpha->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) { + if(!merge_presub_sources(rgb, alpha->Alpha, RC_SOURCE_ALPHA)){ + return 0; + } + } + + /* Copy alpha args into rgb */ + opcode = rc_get_opcode_info(alpha->Alpha.Opcode); + + for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) { + unsigned int srcrgb = 0; + unsigned int srcalpha = 0; + unsigned int oldsrc = alpha->Alpha.Arg[arg].Source; + rc_register_file file = 0; + unsigned int index = 0; + int source; + + if (GET_SWZ(alpha->Alpha.Arg[arg].Swizzle, 0) < 3) { + srcrgb = 1; + file = alpha->RGB.Src[oldsrc].File; + index = alpha->RGB.Src[oldsrc].Index; + } else if (GET_SWZ(alpha->Alpha.Arg[arg].Swizzle, 0) < 4) { + srcalpha = 1; + file = alpha->Alpha.Src[oldsrc].File; + index = alpha->Alpha.Src[oldsrc].Index; + } + + source = rc_pair_alloc_source(rgb, srcrgb, srcalpha, file, index); + if (source < 0) + return 0; + + rgb->Alpha.Arg[arg].Source = source; + rgb->Alpha.Arg[arg].Swizzle = alpha->Alpha.Arg[arg].Swizzle; + rgb->Alpha.Arg[arg].Abs = alpha->Alpha.Arg[arg].Abs; + rgb->Alpha.Arg[arg].Negate = alpha->Alpha.Arg[arg].Negate; + } + + /* Copy alpha opcode into rgb */ + rgb->Alpha.Opcode = alpha->Alpha.Opcode; + rgb->Alpha.DestIndex = alpha->Alpha.DestIndex; + rgb->Alpha.WriteMask = alpha->Alpha.WriteMask; + rgb->Alpha.OutputWriteMask = alpha->Alpha.OutputWriteMask; + rgb->Alpha.DepthWriteMask = alpha->Alpha.DepthWriteMask; + rgb->Alpha.Saturate = alpha->Alpha.Saturate; + + /* Merge ALU result writing */ + if (alpha->WriteALUResult) { + if (rgb->WriteALUResult) + return 0; + + rgb->WriteALUResult = alpha->WriteALUResult; + rgb->ALUResultCompare = alpha->ALUResultCompare; + } + + return 1; +} + +/** + * Try to merge the given instructions into the rgb instructions. + * + * Return true on success; on failure, return false, and keep + * the instructions untouched. + */ +static int merge_instructions(struct rc_pair_instruction * rgb, struct rc_pair_instruction * alpha) +{ + struct rc_pair_instruction backup; + + /*Instructions can't write output registers and ALU result at the + * same time. */ + if ((rgb->WriteALUResult && alpha->Alpha.OutputWriteMask) + || (rgb->RGB.OutputWriteMask && alpha->WriteALUResult)) { + return 0; + } + memcpy(&backup, rgb, sizeof(struct rc_pair_instruction)); + + if (destructive_merge_instructions(rgb, alpha)) + return 1; + + memcpy(rgb, &backup, sizeof(struct rc_pair_instruction)); + return 0; +} + +static void presub_nop(struct rc_instruction * emitted) { + int prev_rgb_index, prev_alpha_index, i, num_src; + + /* We don't need a nop if the previous instruction is a TEX. */ + if (emitted->Prev->Type != RC_INSTRUCTION_PAIR) { + return; + } + if (emitted->Prev->U.P.RGB.WriteMask) + prev_rgb_index = emitted->Prev->U.P.RGB.DestIndex; + else + prev_rgb_index = -1; + if (emitted->Prev->U.P.Alpha.WriteMask) + prev_alpha_index = emitted->Prev->U.P.Alpha.DestIndex; + else + prev_alpha_index = 1; + + /* Check the previous rgb instruction */ + if (emitted->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Used) { + num_src = rc_presubtract_src_reg_count( + emitted->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index); + for (i = 0; i < num_src; i++) { + unsigned int index = emitted->U.P.RGB.Src[i].Index; + if (emitted->U.P.RGB.Src[i].File == RC_FILE_TEMPORARY + && (index == prev_rgb_index + || index == prev_alpha_index)) { + emitted->Prev->U.P.Nop = 1; + return; + } + } + } + + /* Check the previous alpha instruction. */ + if (!emitted->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Used) + return; + + num_src = rc_presubtract_src_reg_count( + emitted->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index); + for (i = 0; i < num_src; i++) { + unsigned int index = emitted->U.P.Alpha.Src[i].Index; + if(emitted->U.P.Alpha.Src[i].File == RC_FILE_TEMPORARY + && (index == prev_rgb_index || index == prev_alpha_index)) { + emitted->Prev->U.P.Nop = 1; + return; + } + } +} + +static void rgb_to_alpha_remap ( + struct rc_instruction * inst, + struct rc_pair_instruction_arg * arg, + rc_register_file old_file, + rc_swizzle old_swz, + unsigned int new_index) +{ + int new_src_index; + unsigned int i; + + for (i = 0; i < 3; i++) { + if (get_swz(arg->Swizzle, i) == old_swz) { + SET_SWZ(arg->Swizzle, i, RC_SWIZZLE_W); + } + } + new_src_index = rc_pair_alloc_source(&inst->U.P, 0, 1, + old_file, new_index); + /* This conversion is not possible, we must have made a mistake in + * is_rgb_to_alpha_possible. */ + if (new_src_index < 0) { + assert(0); + return; + } + + arg->Source = new_src_index; +} + +static int can_remap(unsigned int opcode) +{ + switch(opcode) { + case RC_OPCODE_DDX: + case RC_OPCODE_DDY: + return 0; + default: + return 1; + } +} + +static int can_convert_opcode_to_alpha(unsigned int opcode) +{ + switch(opcode) { + case RC_OPCODE_DDX: + case RC_OPCODE_DDY: + case RC_OPCODE_DP2: + case RC_OPCODE_DP3: + case RC_OPCODE_DP4: + case RC_OPCODE_DPH: + return 0; + default: + return 1; + } +} + +static void is_rgb_to_alpha_possible( + void * userdata, + struct rc_instruction * inst, + struct rc_pair_instruction_arg * arg, + struct rc_pair_instruction_source * src) +{ + unsigned int chan_count = 0; + unsigned int alpha_sources = 0; + unsigned int i; + struct rc_reader_data * reader_data = userdata; + + if (!can_remap(inst->U.P.RGB.Opcode) + || !can_remap(inst->U.P.Alpha.Opcode)) { + reader_data->Abort = 1; + return; + } + + if (!src) + return; + + /* XXX There are some cases where we can still do the conversion if + * a reader reads from a presubtract source, but for now we'll prevent + * it. */ + if (arg->Source == RC_PAIR_PRESUB_SRC) { + reader_data->Abort = 1; + return; + } + + /* Make sure the source only reads from one component. + * XXX We should allow the source to read from the same component twice. + * XXX If the index we will be converting to is the same as the + * current index, then it is OK to read from more than one component. + */ + for (i = 0; i < 3; i++) { + rc_swizzle swz = get_swz(arg->Swizzle, i); + switch(swz) { + case RC_SWIZZLE_X: + case RC_SWIZZLE_Y: + case RC_SWIZZLE_Z: + case RC_SWIZZLE_W: + chan_count++; + break; + default: + break; + } + } + if (chan_count > 1) { + reader_data->Abort = 1; + return; + } + + /* Make sure there are enough alpha sources. + * XXX If we know what register all the readers are going + * to be remapped to, then in some situations we can still do + * the subsitution, even if all 3 alpha sources are being used.*/ + for (i = 0; i < 3; i++) { + if (inst->U.P.Alpha.Src[i].Used) { + alpha_sources++; + } + } + if (alpha_sources > 2) { + reader_data->Abort = 1; + return; + } +} + +static int convert_rgb_to_alpha( + struct schedule_state * s, + struct schedule_instruction * sched_inst) +{ + struct rc_pair_instruction * pair_inst = &sched_inst->Instruction->U.P; + unsigned int old_mask = pair_inst->RGB.WriteMask; + unsigned int old_swz = rc_mask_to_swizzle(old_mask); + const struct rc_opcode_info * info = + rc_get_opcode_info(pair_inst->RGB.Opcode); + int new_index = -1; + unsigned int i; + + if (sched_inst->GlobalReaders.Abort) + return 0; + + if (!pair_inst->RGB.WriteMask) + return 0; + + if (!can_convert_opcode_to_alpha(pair_inst->RGB.Opcode) + || !can_convert_opcode_to_alpha(pair_inst->Alpha.Opcode)) { + return 0; + } + + assert(sched_inst->NumWriteValues == 1); + + if (!sched_inst->WriteValues[0]) { + assert(0); + return 0; + } + + /* We start at the old index, because if we can reuse the same + * register and just change the swizzle then it is more likely we + * will be able to convert all the readers. */ + for (i = pair_inst->RGB.DestIndex; i < RC_REGISTER_MAX_INDEX; i++) { + struct reg_value ** new_regvalp = get_reg_valuep( + s, RC_FILE_TEMPORARY, i, 3); + if (!*new_regvalp) { + struct reg_value ** old_regvalp = + get_reg_valuep(s, + RC_FILE_TEMPORARY, + pair_inst->RGB.DestIndex, + rc_mask_to_swizzle(old_mask)); + new_index = i; + *new_regvalp = *old_regvalp; + *old_regvalp = NULL; + new_regvalp = get_reg_valuep(s, RC_FILE_TEMPORARY, i, 3); + break; + } + } + if (new_index < 0) { + return 0; + } + + pair_inst->Alpha.Opcode = pair_inst->RGB.Opcode; + pair_inst->Alpha.DestIndex = new_index; + pair_inst->Alpha.WriteMask = RC_MASK_W; + pair_inst->Alpha.Target = pair_inst->RGB.Target; + pair_inst->Alpha.OutputWriteMask = pair_inst->RGB.OutputWriteMask; + pair_inst->Alpha.DepthWriteMask = pair_inst->RGB.DepthWriteMask; + pair_inst->Alpha.Saturate = pair_inst->RGB.Saturate; + memcpy(pair_inst->Alpha.Arg, pair_inst->RGB.Arg, + sizeof(pair_inst->Alpha.Arg)); + /* Move the swizzles into the first chan */ + for (i = 0; i < info->NumSrcRegs; i++) { + unsigned int j; + for (j = 0; j < 3; j++) { + unsigned int swz = get_swz(pair_inst->Alpha.Arg[i].Swizzle, j); + if (swz != RC_SWIZZLE_UNUSED) { + pair_inst->Alpha.Arg[i].Swizzle = + rc_init_swizzle(swz, 1); + break; + } + } + } + pair_inst->RGB.Opcode = RC_OPCODE_NOP; + pair_inst->RGB.DestIndex = 0; + pair_inst->RGB.WriteMask = 0; + pair_inst->RGB.Target = 0; + pair_inst->RGB.OutputWriteMask = 0; + pair_inst->RGB.DepthWriteMask = 0; + pair_inst->RGB.Saturate = 0; + memset(pair_inst->RGB.Arg, 0, sizeof(pair_inst->RGB.Arg)); + + for(i = 0; i < sched_inst->GlobalReaders.ReaderCount; i++) { + struct rc_reader reader = sched_inst->GlobalReaders.Readers[i]; + rgb_to_alpha_remap(reader.Inst, reader.U.P.Arg, + RC_FILE_TEMPORARY, old_swz, new_index); + } + return 1; +} + +/** + * Find a good ALU instruction or pair of ALU instruction and emit it. + * + * Prefer emitting full ALU instructions, so that when we reach a point + * where no full ALU instruction can be emitted, we have more candidates + * for RGB/Alpha pairing. + */ +static void emit_one_alu(struct schedule_state *s, struct rc_instruction * before) +{ + struct schedule_instruction * sinst; + + if (s->ReadyFullALU) { + sinst = s->ReadyFullALU; + s->ReadyFullALU = s->ReadyFullALU->NextReady; + rc_insert_instruction(before->Prev, sinst->Instruction); + commit_alu_instruction(s, sinst); + } else { + struct schedule_instruction **prgb; + struct schedule_instruction **palpha; + struct schedule_instruction *prev; +pair: + /* Some pairings might fail because they require too + * many source slots; try all possible pairings if necessary */ + for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) { + for(palpha = &s->ReadyAlpha; *palpha; palpha = &(*palpha)->NextReady) { + struct schedule_instruction * psirgb = *prgb; + struct schedule_instruction * psialpha = *palpha; + + if (!merge_instructions(&psirgb->Instruction->U.P, &psialpha->Instruction->U.P)) + continue; + + *prgb = (*prgb)->NextReady; + *palpha = (*palpha)->NextReady; + rc_insert_instruction(before->Prev, psirgb->Instruction); + commit_alu_instruction(s, psirgb); + commit_alu_instruction(s, psialpha); + goto success; + } + } + prev = NULL; + /* No success in pairing, now try to convert one of the RGB + * instructions to an Alpha so we can pair it with another RGB. + */ + if (s->ReadyRGB && s->ReadyRGB->NextReady) { + for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) { + if ((*prgb)->NumWriteValues == 1) { + struct schedule_instruction * prgb_next; + if (!convert_rgb_to_alpha(s, *prgb)) + goto cont_loop; + prgb_next = (*prgb)->NextReady; + /* Add instruction to the Alpha ready list. */ + (*prgb)->NextReady = s->ReadyAlpha; + s->ReadyAlpha = *prgb; + /* Remove instruction from the RGB ready list.*/ + if (prev) + prev->NextReady = prgb_next; + else + s->ReadyRGB = prgb_next; + goto pair; + } +cont_loop: + prev = *prgb; + } + } + /* Still no success in pairing, just take the first RGB + * or alpha instruction. */ + if (s->ReadyRGB) { + sinst = s->ReadyRGB; + s->ReadyRGB = s->ReadyRGB->NextReady; + } else if (s->ReadyAlpha) { + sinst = s->ReadyAlpha; + s->ReadyAlpha = s->ReadyAlpha->NextReady; + } else { + /*XXX Something real bad has happened. */ + assert(0); + } + + rc_insert_instruction(before->Prev, sinst->Instruction); + commit_alu_instruction(s, sinst); + success: ; + } + /* If the instruction we just emitted uses a presubtract value, and + * the presubtract sources were written by the previous intstruction, + * the previous instruction needs a nop. */ + presub_nop(before->Prev); +} + +static void scan_read(void * data, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int chan) +{ + struct schedule_state * s = data; + struct reg_value ** v = get_reg_valuep(s, file, index, chan); + struct reg_value_reader * reader; + + if (!v) + return; + + if (*v && (*v)->Writer == s->Current) { + /* The instruction reads and writes to a register component. + * In this case, we only want to increment dependencies by one. + */ + return; + } + + DBG("%i: read %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan); + + reader = memory_pool_malloc(&s->C->Pool, sizeof(*reader)); + reader->Reader = s->Current; + if (!*v) { + /* In this situation, the instruction reads from a register + * that hasn't been written to or read from in the current + * block. */ + *v = memory_pool_malloc(&s->C->Pool, sizeof(struct reg_value)); + memset(*v, 0, sizeof(struct reg_value)); + (*v)->Readers = reader; + } else { + reader->Next = (*v)->Readers; + (*v)->Readers = reader; + /* Only update the current instruction's dependencies if the + * register it reads from has been written to in this block. */ + if ((*v)->Writer) { + s->Current->NumDependencies++; + } + } + (*v)->NumReaders++; + + if (s->Current->NumReadValues >= 12) { + rc_error(s->C, "%s: NumReadValues overflow\n", __FUNCTION__); + } else { + s->Current->ReadValues[s->Current->NumReadValues++] = *v; + } +} + +static void scan_write(void * data, struct rc_instruction * inst, + rc_register_file file, unsigned int index, unsigned int chan) +{ + struct schedule_state * s = data; + struct reg_value ** pv = get_reg_valuep(s, file, index, chan); + struct reg_value * newv; + + if (!pv) + return; + + DBG("%i: write %i[%i] chan %i\n", s->Current->Instruction->IP, file, index, chan); + + newv = memory_pool_malloc(&s->C->Pool, sizeof(*newv)); + memset(newv, 0, sizeof(*newv)); + + newv->Writer = s->Current; + + if (*pv) { + (*pv)->Next = newv; + s->Current->NumDependencies++; + } + + *pv = newv; + + if (s->Current->NumWriteValues >= 4) { + rc_error(s->C, "%s: NumWriteValues overflow\n", __FUNCTION__); + } else { + s->Current->WriteValues[s->Current->NumWriteValues++] = newv; + } +} + +static void is_rgb_to_alpha_possible_normal( + void * userdata, + struct rc_instruction * inst, + struct rc_src_register * src) +{ + struct rc_reader_data * reader_data = userdata; + reader_data->Abort = 1; + +} + +static void schedule_block(struct r300_fragment_program_compiler * c, + struct rc_instruction * begin, struct rc_instruction * end) +{ + struct schedule_state s; + unsigned int ip; + + memset(&s, 0, sizeof(s)); + s.C = &c->Base; + + /* Scan instructions for data dependencies */ + ip = 0; + for(struct rc_instruction * inst = begin; inst != end; inst = inst->Next) { + s.Current = memory_pool_malloc(&c->Base.Pool, sizeof(*s.Current)); + memset(s.Current, 0, sizeof(struct schedule_instruction)); + + s.Current->Instruction = inst; + inst->IP = ip++; + + DBG("%i: Scanning\n", inst->IP); + + /* The order of things here is subtle and maybe slightly + * counter-intuitive, to account for the case where an + * instruction writes to the same register as it reads + * from. */ + rc_for_all_writes_chan(inst, &scan_write, &s); + rc_for_all_reads_chan(inst, &scan_read, &s); + + DBG("%i: Has %i dependencies\n", inst->IP, s.Current->NumDependencies); + + if (!s.Current->NumDependencies) + instruction_ready(&s, s.Current); + + /* Get global readers for possible RGB->Alpha conversion. */ + s.Current->GlobalReaders.ExitOnAbort = 1; + rc_get_readers(s.C, inst, &s.Current->GlobalReaders, + is_rgb_to_alpha_possible_normal, + is_rgb_to_alpha_possible, NULL); + } + + /* Temporarily unlink all instructions */ + begin->Prev->Next = end; + end->Prev = begin->Prev; + + /* Schedule instructions back */ + while(!s.C->Error && + (s.ReadyTEX || s.ReadyRGB || s.ReadyAlpha || s.ReadyFullALU)) { + if (s.ReadyTEX) + emit_all_tex(&s, end); + + while(!s.C->Error && (s.ReadyFullALU || s.ReadyRGB || s.ReadyAlpha)) + emit_one_alu(&s, end); + } +} + +static int is_controlflow(struct rc_instruction * inst) +{ + if (inst->Type == RC_INSTRUCTION_NORMAL) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + return opcode->IsFlowControl; + } + return 0; +} + +void rc_pair_schedule(struct radeon_compiler *cc, void *user) +{ + struct schedule_state s; + + struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)cc; + struct rc_instruction * inst = c->Base.Program.Instructions.Next; + + memset(&s, 0, sizeof(s)); + s.C = &c->Base; + while(inst != &c->Base.Program.Instructions) { + struct rc_instruction * first; + + if (is_controlflow(inst)) { + inst = inst->Next; + continue; + } + + first = inst; + + while(inst != &c->Base.Program.Instructions && !is_controlflow(inst)) + inst = inst->Next; + + DBG("Schedule one block\n"); + schedule_block(c, first, inst); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_translate.c b/src/gallium/drivers/r300/compiler/radeon_pair_translate.c new file mode 100644 index 00000000000..2dae56a2428 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_pair_translate.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_program_pair.h" + +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" + + +/** + * Finally rewrite ADD, MOV, MUL as the appropriate native instruction + * and reverse the order of arguments for CMP. + */ +static void final_rewrite(struct rc_sub_instruction *inst) +{ + struct rc_src_register tmp; + + switch(inst->Opcode) { + case RC_OPCODE_ADD: + inst->SrcReg[2] = inst->SrcReg[1]; + inst->SrcReg[1].File = RC_FILE_NONE; + inst->SrcReg[1].Swizzle = RC_SWIZZLE_1111; + inst->SrcReg[1].Negate = RC_MASK_NONE; + inst->Opcode = RC_OPCODE_MAD; + break; + case RC_OPCODE_CMP: + tmp = inst->SrcReg[2]; + inst->SrcReg[2] = inst->SrcReg[0]; + inst->SrcReg[0] = tmp; + break; + case RC_OPCODE_MOV: + /* AMD say we should use CMP. + * However, when we transform + * KIL -r0; + * into + * CMP tmp, -r0, -r0, 0; + * KIL tmp; + * we get incorrect behaviour on R500 when r0 == 0.0. + * It appears that the R500 KIL hardware treats -0.0 as less + * than zero. + */ + inst->SrcReg[1].File = RC_FILE_NONE; + inst->SrcReg[1].Swizzle = RC_SWIZZLE_1111; + inst->SrcReg[2].File = RC_FILE_NONE; + inst->SrcReg[2].Swizzle = RC_SWIZZLE_0000; + inst->Opcode = RC_OPCODE_MAD; + break; + case RC_OPCODE_MUL: + inst->SrcReg[2].File = RC_FILE_NONE; + inst->SrcReg[2].Swizzle = RC_SWIZZLE_0000; + inst->Opcode = RC_OPCODE_MAD; + break; + default: + /* nothing to do */ + break; + } +} + + +/** + * Classify an instruction according to which ALUs etc. it needs + */ +static void classify_instruction(struct rc_sub_instruction * inst, + int * needrgb, int * needalpha, int * istranscendent) +{ + *needrgb = (inst->DstReg.WriteMask & RC_MASK_XYZ) ? 1 : 0; + *needalpha = (inst->DstReg.WriteMask & RC_MASK_W) ? 1 : 0; + *istranscendent = 0; + + if (inst->WriteALUResult == RC_ALURESULT_X) + *needrgb = 1; + else if (inst->WriteALUResult == RC_ALURESULT_W) + *needalpha = 1; + + switch(inst->Opcode) { + case RC_OPCODE_ADD: + case RC_OPCODE_CMP: + case RC_OPCODE_CND: + case RC_OPCODE_DDX: + case RC_OPCODE_DDY: + case RC_OPCODE_FRC: + case RC_OPCODE_MAD: + case RC_OPCODE_MAX: + case RC_OPCODE_MIN: + case RC_OPCODE_MOV: + case RC_OPCODE_MUL: + break; + case RC_OPCODE_COS: + case RC_OPCODE_EX2: + case RC_OPCODE_LG2: + case RC_OPCODE_RCP: + case RC_OPCODE_RSQ: + case RC_OPCODE_SIN: + *istranscendent = 1; + *needalpha = 1; + break; + case RC_OPCODE_DP4: + *needalpha = 1; + /* fall through */ + case RC_OPCODE_DP3: + *needrgb = 1; + break; + default: + break; + } +} + +static void src_uses(struct rc_src_register src, unsigned int * rgb, + unsigned int * alpha) +{ + int j; + for(j = 0; j < 4; ++j) { + unsigned int swz = GET_SWZ(src.Swizzle, j); + if (swz < 3) + *rgb = 1; + else if (swz < 4) + *alpha = 1; + } +} + +/** + * Fill the given ALU instruction's opcodes and source operands into the given pair, + * if possible. + */ +static void set_pair_instruction(struct r300_fragment_program_compiler *c, + struct rc_pair_instruction * pair, + struct rc_sub_instruction * inst) +{ + int needrgb, needalpha, istranscendent; + const struct rc_opcode_info * opcode; + int i; + + memset(pair, 0, sizeof(struct rc_pair_instruction)); + + classify_instruction(inst, &needrgb, &needalpha, &istranscendent); + + if (needrgb) { + if (istranscendent) + pair->RGB.Opcode = RC_OPCODE_REPL_ALPHA; + else + pair->RGB.Opcode = inst->Opcode; + if (inst->SaturateMode == RC_SATURATE_ZERO_ONE) + pair->RGB.Saturate = 1; + } + if (needalpha) { + pair->Alpha.Opcode = inst->Opcode; + if (inst->SaturateMode == RC_SATURATE_ZERO_ONE) + pair->Alpha.Saturate = 1; + } + + opcode = rc_get_opcode_info(inst->Opcode); + + /* Presubtract handling: + * We need to make sure that the values used by the presubtract + * operation end up in src0 or src1. */ + if(inst->PreSub.Opcode != RC_PRESUB_NONE) { + /* rc_pair_alloc_source() will fill in data for + * pair->{RGB,ALPHA}.Src[RC_PAIR_PRESUB_SRC] */ + int j; + for(j = 0; j < 3; j++) { + int src_regs; + if(inst->SrcReg[j].File != RC_FILE_PRESUB) + continue; + + src_regs = rc_presubtract_src_reg_count( + inst->PreSub.Opcode); + for(i = 0; i < src_regs; i++) { + unsigned int rgb = 0; + unsigned int alpha = 0; + src_uses(inst->SrcReg[j], &rgb, &alpha); + if(rgb) { + pair->RGB.Src[i].File = + inst->PreSub.SrcReg[i].File; + pair->RGB.Src[i].Index = + inst->PreSub.SrcReg[i].Index; + pair->RGB.Src[i].Used = 1; + } + if(alpha) { + pair->Alpha.Src[i].File = + inst->PreSub.SrcReg[i].File; + pair->Alpha.Src[i].Index = + inst->PreSub.SrcReg[i].Index; + pair->Alpha.Src[i].Used = 1; + } + } + } + } + + for(i = 0; i < opcode->NumSrcRegs; ++i) { + int source; + if (needrgb && !istranscendent) { + unsigned int srcrgb = 0; + unsigned int srcalpha = 0; + unsigned int srcmask = 0; + int j; + /* We don't care about the alpha channel here. We only + * want the part of the swizzle that writes to rgb, + * since we are creating an rgb instruction. */ + for(j = 0; j < 3; ++j) { + unsigned int swz = GET_SWZ(inst->SrcReg[i].Swizzle, j); + + if (swz < RC_SWIZZLE_W) + srcrgb = 1; + else if (swz == RC_SWIZZLE_W) + srcalpha = 1; + + if (swz < RC_SWIZZLE_UNUSED) + srcmask |= 1 << j; + } + source = rc_pair_alloc_source(pair, srcrgb, srcalpha, + inst->SrcReg[i].File, inst->SrcReg[i].Index); + if (source < 0) { + rc_error(&c->Base, "Failed to translate " + "rgb instruction.\n"); + return; + } + pair->RGB.Arg[i].Source = source; + pair->RGB.Arg[i].Swizzle = + rc_init_swizzle(inst->SrcReg[i].Swizzle, 3); + pair->RGB.Arg[i].Abs = inst->SrcReg[i].Abs; + pair->RGB.Arg[i].Negate = !!(srcmask & inst->SrcReg[i].Negate & (RC_MASK_X | RC_MASK_Y | RC_MASK_Z)); + } + if (needalpha) { + unsigned int srcrgb = 0; + unsigned int srcalpha = 0; + unsigned int swz = GET_SWZ(inst->SrcReg[i].Swizzle, istranscendent ? 0 : 3); + if (swz < 3) + srcrgb = 1; + else if (swz < 4) + srcalpha = 1; + source = rc_pair_alloc_source(pair, srcrgb, srcalpha, + inst->SrcReg[i].File, inst->SrcReg[i].Index); + if (source < 0) { + rc_error(&c->Base, "Failed to translate " + "alpha instruction.\n"); + return; + } + pair->Alpha.Arg[i].Source = source; + pair->Alpha.Arg[i].Swizzle = rc_init_swizzle(swz, 1); + pair->Alpha.Arg[i].Abs = inst->SrcReg[i].Abs; + pair->Alpha.Arg[i].Negate = !!(inst->SrcReg[i].Negate & RC_MASK_W); + } + } + + /* Destination handling */ + if (inst->DstReg.File == RC_FILE_OUTPUT) { + if (inst->DstReg.Index == c->OutputDepth) { + pair->Alpha.DepthWriteMask |= GET_BIT(inst->DstReg.WriteMask, 3); + } else { + for (i = 0; i < 4; i++) { + if (inst->DstReg.Index == c->OutputColor[i]) { + pair->RGB.Target = i; + pair->Alpha.Target = i; + pair->RGB.OutputWriteMask |= + inst->DstReg.WriteMask & RC_MASK_XYZ; + pair->Alpha.OutputWriteMask |= + GET_BIT(inst->DstReg.WriteMask, 3); + break; + } + } + } + } else { + if (needrgb) { + pair->RGB.DestIndex = inst->DstReg.Index; + pair->RGB.WriteMask |= inst->DstReg.WriteMask & RC_MASK_XYZ; + } + + if (needalpha) { + pair->Alpha.WriteMask |= (GET_BIT(inst->DstReg.WriteMask, 3) << 3); + if (pair->Alpha.WriteMask) { + pair->Alpha.DestIndex = inst->DstReg.Index; + } + } + } + + if (inst->WriteALUResult) { + pair->WriteALUResult = inst->WriteALUResult; + pair->ALUResultCompare = inst->ALUResultCompare; + } +} + + +static void check_opcode_support(struct r300_fragment_program_compiler *c, + struct rc_sub_instruction *inst) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); + + if (opcode->HasDstReg) { + if (inst->SaturateMode == RC_SATURATE_MINUS_PLUS_ONE) { + rc_error(&c->Base, "Fragment program does not support signed Saturate.\n"); + return; + } + } + + for (unsigned i = 0; i < opcode->NumSrcRegs; i++) { + if (inst->SrcReg[i].RelAddr) { + rc_error(&c->Base, "Fragment program does not support relative addressing " + " of source operands.\n"); + return; + } + } +} + + +/** + * Translate all ALU instructions into corresponding pair instructions, + * performing no other changes. + */ +void rc_pair_translate(struct radeon_compiler *cc, void *user) +{ + struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)cc; + + for(struct rc_instruction * inst = c->Base.Program.Instructions.Next; + inst != &c->Base.Program.Instructions; + inst = inst->Next) { + const struct rc_opcode_info * opcode; + struct rc_sub_instruction copy; + + if (inst->Type != RC_INSTRUCTION_NORMAL) + continue; + + opcode = rc_get_opcode_info(inst->U.I.Opcode); + + if (opcode->HasTexture || opcode->IsFlowControl || opcode->Opcode == RC_OPCODE_KIL) + continue; + + copy = inst->U.I; + + check_opcode_support(c, ©); + + final_rewrite(©); + inst->Type = RC_INSTRUCTION_PAIR; + set_pair_instruction(c, &inst->U.P, ©); + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_program.c b/src/gallium/drivers/r300/compiler/radeon_program.c new file mode 100644 index 00000000000..fe5756ebc45 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_program.h" + +#include <stdio.h> + +#include "radeon_compiler.h" +#include "radeon_dataflow.h" + + +/** + * Transform the given clause in the following way: + * 1. Replace it with an empty clause + * 2. For every instruction in the original clause, try the given + * transformations in order. + * 3. If one of the transformations returns GL_TRUE, assume that it + * has emitted the appropriate instruction(s) into the new clause; + * otherwise, copy the instruction verbatim. + * + * \note The transformation is currently not recursive; in other words, + * instructions emitted by transformations are not transformed. + * + * \note The transform is called 'local' because it can only look at + * one instruction at a time. + */ +void rc_local_transform( + struct radeon_compiler * c, + void *user) +{ + struct radeon_program_transformation *transformations = + (struct radeon_program_transformation*)user; + struct rc_instruction * inst = c->Program.Instructions.Next; + + while(inst != &c->Program.Instructions) { + struct rc_instruction * current = inst; + int i; + + inst = inst->Next; + + for(i = 0; transformations[i].function; ++i) { + struct radeon_program_transformation* t = transformations + i; + + if (t->function(c, current, t->userData)) + break; + } + } +} + +struct get_used_temporaries_data { + unsigned char * Used; + unsigned int UsedLength; +}; + +static void get_used_temporaries_cb( + void * userdata, + struct rc_instruction * inst, + rc_register_file file, + unsigned int index, + unsigned int mask) +{ + struct get_used_temporaries_data * d = userdata; + + if (file != RC_FILE_TEMPORARY) + return; + + if (index >= d->UsedLength) + return; + + d->Used[index] |= mask; +} + +/** + * This function fills in the parameter 'used' with a writemask that + * represent which components of each temporary register are used by the + * program. This is meant to be combined with rc_find_free_temporary_list as a + * more efficient version of rc_find_free_temporary. + * @param used The function does not initialize this parameter. + */ +void rc_get_used_temporaries( + struct radeon_compiler * c, + unsigned char * used, + unsigned int used_length) +{ + struct rc_instruction * inst; + struct get_used_temporaries_data d; + d.Used = used; + d.UsedLength = used_length; + + for(inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + + rc_for_all_reads_mask(inst, get_used_temporaries_cb, &d); + rc_for_all_writes_mask(inst, get_used_temporaries_cb, &d); + } +} + +/* Search a list of used temporaries for a free one + * \sa rc_get_used_temporaries + * @note If this functions finds a free temporary, it will mark it as used + * in the used temporary list (param 'used') + * @param used list of used temporaries + * @param used_length number of items in param 'used' + * @param mask which components must be free in the temporary index that is + * returned. + * @return -1 If there are no more free temporaries, otherwise the index of + * a temporary register where the components specified in param 'mask' are + * not being used. + */ +int rc_find_free_temporary_list( + struct radeon_compiler * c, + unsigned char * used, + unsigned int used_length, + unsigned int mask) +{ + int i; + for(i = 0; i < used_length; i++) { + if ((~used[i] & mask) == mask) { + used[i] |= mask; + return i; + } + } + return -1; +} + +unsigned int rc_find_free_temporary(struct radeon_compiler * c) +{ + unsigned char used[RC_REGISTER_MAX_INDEX]; + int free; + + memset(used, 0, sizeof(used)); + + rc_get_used_temporaries(c, used, RC_REGISTER_MAX_INDEX); + + free = rc_find_free_temporary_list(c, used, RC_REGISTER_MAX_INDEX, + RC_MASK_XYZW); + if (free < 0) { + rc_error(c, "Ran out of temporary registers\n"); + return 0; + } + return free; +} + + +struct rc_instruction *rc_alloc_instruction(struct radeon_compiler * c) +{ + struct rc_instruction * inst = memory_pool_malloc(&c->Pool, sizeof(struct rc_instruction)); + + memset(inst, 0, sizeof(struct rc_instruction)); + + inst->U.I.Opcode = RC_OPCODE_ILLEGAL_OPCODE; + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW; + inst->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZW; + inst->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_XYZW; + + return inst; +} + +void rc_insert_instruction(struct rc_instruction * after, struct rc_instruction * inst) +{ + inst->Prev = after; + inst->Next = after->Next; + + inst->Prev->Next = inst; + inst->Next->Prev = inst; +} + +struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, struct rc_instruction * after) +{ + struct rc_instruction * inst = rc_alloc_instruction(c); + + rc_insert_instruction(after, inst); + + return inst; +} + +void rc_remove_instruction(struct rc_instruction * inst) +{ + inst->Prev->Next = inst->Next; + inst->Next->Prev = inst->Prev; +} + +/** + * Return the number of instructions in the program. + */ +unsigned int rc_recompute_ips(struct radeon_compiler * c) +{ + unsigned int ip = 0; + struct rc_instruction * inst; + + for(inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next) { + inst->IP = ip++; + } + + c->Program.Instructions.IP = 0xcafedead; + + return ip; +} diff --git a/src/gallium/drivers/r300/compiler/radeon_program.h b/src/gallium/drivers/r300/compiler/radeon_program.h new file mode 100644 index 00000000000..b899eccbf53 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __RADEON_PROGRAM_H_ +#define __RADEON_PROGRAM_H_ + +#include <stdint.h> +#include <string.h> + +#include "radeon_opcodes.h" +#include "radeon_code.h" +#include "radeon_program_constants.h" +#include "radeon_program_pair.h" + +struct radeon_compiler; + +struct rc_src_register { + unsigned int File:4; + + /** Negative values may be used for relative addressing. */ + signed int Index:(RC_REGISTER_INDEX_BITS+1); + unsigned int RelAddr:1; + + unsigned int Swizzle:12; + + /** Take the component-wise absolute value */ + unsigned int Abs:1; + + /** Post-Abs negation. */ + unsigned int Negate:4; +}; + +struct rc_dst_register { + unsigned int File:3; + unsigned int Index:RC_REGISTER_INDEX_BITS; + unsigned int WriteMask:4; +}; + +struct rc_presub_instruction { + rc_presubtract_op Opcode; + struct rc_src_register SrcReg[2]; +}; + +/** + * Instructions are maintained by the compiler in a doubly linked list + * of these structures. + * + * This instruction format is intended to be expanded for hardware-specific + * trickery. At different stages of compilation, a different set of + * instruction types may be valid. + */ +struct rc_sub_instruction { + struct rc_src_register SrcReg[3]; + struct rc_dst_register DstReg; + + /** + * Opcode of this instruction, according to \ref rc_opcode enums. + */ + unsigned int Opcode:8; + + /** + * Saturate each value of the result to the range [0,1] or [-1,1], + * according to \ref rc_saturate_mode enums. + */ + unsigned int SaturateMode:2; + + /** + * Writing to the special register RC_SPECIAL_ALU_RESULT + */ + /*@{*/ + unsigned int WriteALUResult:2; + unsigned int ALUResultCompare:3; + /*@}*/ + + /** + * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions. + */ + /*@{*/ + /** Source texture unit. */ + unsigned int TexSrcUnit:5; + + /** Source texture target, one of the \ref rc_texture_target enums */ + unsigned int TexSrcTarget:3; + + /** True if tex instruction should do shadow comparison */ + unsigned int TexShadow:1; + + /**R500 Only. How to swizzle the result of a TEX lookup*/ + unsigned int TexSwizzle:12; + /*@}*/ + + /** This holds information about the presubtract operation used by + * this instruction. */ + struct rc_presub_instruction PreSub; +}; + +typedef enum { + RC_INSTRUCTION_NORMAL = 0, + RC_INSTRUCTION_PAIR +} rc_instruction_type; + +struct rc_instruction { + struct rc_instruction * Prev; + struct rc_instruction * Next; + + rc_instruction_type Type; + union { + struct rc_sub_instruction I; + struct rc_pair_instruction P; + } U; + + /** + * Warning: IPs are not stable. If you want to use them, + * you need to recompute them at the beginning of each pass + * using \ref rc_recompute_ips + */ + unsigned int IP; +}; + +struct rc_program { + /** + * Instructions.Next points to the first instruction, + * Instructions.Prev points to the last instruction. + */ + struct rc_instruction Instructions; + + /* Long term, we should probably remove InputsRead & OutputsWritten, + * since updating dependent state can be fragile, and they aren't + * actually used very often. */ + uint32_t InputsRead; + uint32_t OutputsWritten; + uint32_t ShadowSamplers; /**< Texture units used for shadow sampling. */ + + struct rc_constant_list Constants; +}; + +/** + * A transformation that can be passed to \ref rc_local_transform. + * + * The function will be called once for each instruction. + * It has to either emit the appropriate transformed code for the instruction + * and return true, or return false if it doesn't understand the + * instruction. + * + * The function gets passed the userData as last parameter. + */ +struct radeon_program_transformation { + int (*function)( + struct radeon_compiler*, + struct rc_instruction*, + void*); + void *userData; +}; + +void rc_local_transform( + struct radeon_compiler *c, + void *user); + +void rc_get_used_temporaries( + struct radeon_compiler * c, + unsigned char * used, + unsigned int used_length); + +int rc_find_free_temporary_list( + struct radeon_compiler * c, + unsigned char * used, + unsigned int used_length, + unsigned int mask); + +unsigned int rc_find_free_temporary(struct radeon_compiler * c); + +struct rc_instruction *rc_alloc_instruction(struct radeon_compiler * c); +struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, struct rc_instruction * after); +void rc_insert_instruction(struct rc_instruction * after, struct rc_instruction * inst); +void rc_remove_instruction(struct rc_instruction * inst); + +unsigned int rc_recompute_ips(struct radeon_compiler * c); + +void rc_print_program(const struct rc_program *prog); + +rc_swizzle rc_mask_to_swizzle(unsigned int mask); +#endif diff --git a/src/gallium/drivers/r300/compiler/radeon_program_alu.c b/src/gallium/drivers/r300/compiler/radeon_program_alu.c new file mode 100644 index 00000000000..9fc991166a3 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_alu.c @@ -0,0 +1,1154 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * @file + * + * Shareable transformations that transform "special" ALU instructions + * into ALU instructions that are supported by hardware. + * + */ + +#include "radeon_program_alu.h" + +#include "radeon_compiler.h" +#include "radeon_compiler_util.h" + + +static struct rc_instruction *emit1( + struct radeon_compiler * c, struct rc_instruction * after, + rc_opcode Opcode, rc_saturate_mode Saturate, struct rc_dst_register DstReg, + struct rc_src_register SrcReg) +{ + struct rc_instruction *fpi = rc_insert_new_instruction(c, after); + + fpi->U.I.Opcode = Opcode; + fpi->U.I.SaturateMode = Saturate; + fpi->U.I.DstReg = DstReg; + fpi->U.I.SrcReg[0] = SrcReg; + return fpi; +} + +static struct rc_instruction *emit2( + struct radeon_compiler * c, struct rc_instruction * after, + rc_opcode Opcode, rc_saturate_mode Saturate, struct rc_dst_register DstReg, + struct rc_src_register SrcReg0, struct rc_src_register SrcReg1) +{ + struct rc_instruction *fpi = rc_insert_new_instruction(c, after); + + fpi->U.I.Opcode = Opcode; + fpi->U.I.SaturateMode = Saturate; + fpi->U.I.DstReg = DstReg; + fpi->U.I.SrcReg[0] = SrcReg0; + fpi->U.I.SrcReg[1] = SrcReg1; + return fpi; +} + +static struct rc_instruction *emit3( + struct radeon_compiler * c, struct rc_instruction * after, + rc_opcode Opcode, rc_saturate_mode Saturate, struct rc_dst_register DstReg, + struct rc_src_register SrcReg0, struct rc_src_register SrcReg1, + struct rc_src_register SrcReg2) +{ + struct rc_instruction *fpi = rc_insert_new_instruction(c, after); + + fpi->U.I.Opcode = Opcode; + fpi->U.I.SaturateMode = Saturate; + fpi->U.I.DstReg = DstReg; + fpi->U.I.SrcReg[0] = SrcReg0; + fpi->U.I.SrcReg[1] = SrcReg1; + fpi->U.I.SrcReg[2] = SrcReg2; + return fpi; +} + +static struct rc_dst_register dstregtmpmask(int index, int mask) +{ + struct rc_dst_register dst = {0}; + dst.File = RC_FILE_TEMPORARY; + dst.Index = index; + dst.WriteMask = mask; + return dst; +} + +static const struct rc_src_register builtin_zero = { + .File = RC_FILE_NONE, + .Index = 0, + .Swizzle = RC_SWIZZLE_0000 +}; +static const struct rc_src_register builtin_one = { + .File = RC_FILE_NONE, + .Index = 0, + .Swizzle = RC_SWIZZLE_1111 +}; +static const struct rc_src_register srcreg_undefined = { + .File = RC_FILE_NONE, + .Index = 0, + .Swizzle = RC_SWIZZLE_XYZW +}; + +static struct rc_src_register srcreg(int file, int index) +{ + struct rc_src_register src = srcreg_undefined; + src.File = file; + src.Index = index; + return src; +} + +static struct rc_src_register srcregswz(int file, int index, int swz) +{ + struct rc_src_register src = srcreg_undefined; + src.File = file; + src.Index = index; + src.Swizzle = swz; + return src; +} + +static struct rc_src_register absolute(struct rc_src_register reg) +{ + struct rc_src_register newreg = reg; + newreg.Abs = 1; + newreg.Negate = RC_MASK_NONE; + return newreg; +} + +static struct rc_src_register negate(struct rc_src_register reg) +{ + struct rc_src_register newreg = reg; + newreg.Negate = newreg.Negate ^ RC_MASK_XYZW; + return newreg; +} + +static struct rc_src_register swizzle(struct rc_src_register reg, + rc_swizzle x, rc_swizzle y, rc_swizzle z, rc_swizzle w) +{ + struct rc_src_register swizzled = reg; + swizzled.Swizzle = combine_swizzles4(reg.Swizzle, x, y, z, w); + return swizzled; +} + +static struct rc_src_register swizzle_smear(struct rc_src_register reg, + rc_swizzle x) +{ + return swizzle(reg, x, x, x, x); +} + +static struct rc_src_register swizzle_xxxx(struct rc_src_register reg) +{ + return swizzle_smear(reg, RC_SWIZZLE_X); +} + +static struct rc_src_register swizzle_yyyy(struct rc_src_register reg) +{ + return swizzle_smear(reg, RC_SWIZZLE_Y); +} + +static struct rc_src_register swizzle_zzzz(struct rc_src_register reg) +{ + return swizzle_smear(reg, RC_SWIZZLE_Z); +} + +static struct rc_src_register swizzle_wwww(struct rc_src_register reg) +{ + return swizzle_smear(reg, RC_SWIZZLE_W); +} + +static int is_dst_safe_to_reuse(struct rc_instruction *inst) +{ + const struct rc_opcode_info *info = rc_get_opcode_info(inst->U.I.Opcode); + unsigned i; + + assert(info->HasDstReg); + + if (inst->U.I.DstReg.File != RC_FILE_TEMPORARY) + return 0; + + for (i = 0; i < info->NumSrcRegs; i++) { + if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY && + inst->U.I.SrcReg[i].Index == inst->U.I.DstReg.Index) + return 0; + } + + return 1; +} + +static struct rc_dst_register try_to_reuse_dst(struct radeon_compiler *c, + struct rc_instruction *inst) +{ + unsigned tmp; + + if (is_dst_safe_to_reuse(inst)) + tmp = inst->U.I.DstReg.Index; + else + tmp = rc_find_free_temporary(c); + + return dstregtmpmask(tmp, inst->U.I.DstReg.WriteMask); +} + +static void transform_ABS(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_src_register src = inst->U.I.SrcReg[0]; + src.Abs = 1; + src.Negate = RC_MASK_NONE; + emit1(c, inst->Prev, RC_OPCODE_MOV, inst->U.I.SaturateMode, inst->U.I.DstReg, src); + rc_remove_instruction(inst); +} + +static void transform_CEIL(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* Assuming: + * ceil(x) = -floor(-x) + * + * After inlining floor: + * ceil(x) = -(-x-frac(-x)) + * + * After simplification: + * ceil(x) = x+frac(-x) + */ + + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dst, negate(inst->U.I.SrcReg[0])); + emit2(c, inst->Prev, RC_OPCODE_ADD, inst->U.I.SaturateMode, inst->U.I.DstReg, + inst->U.I.SrcReg[0], srcreg(RC_FILE_TEMPORARY, dst.Index)); + rc_remove_instruction(inst); +} + +static void transform_CLAMP(struct radeon_compiler *c, + struct rc_instruction *inst) +{ + /* CLAMP dst, src, min, max + * into: + * MIN tmp, src, max + * MAX dst, tmp, min + */ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + emit2(c, inst->Prev, RC_OPCODE_MIN, 0, dst, + inst->U.I.SrcReg[0], inst->U.I.SrcReg[2]); + emit2(c, inst->Prev, RC_OPCODE_MAX, inst->U.I.SaturateMode, inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst.Index), inst->U.I.SrcReg[1]); + rc_remove_instruction(inst); +} + +static void transform_DP2(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_src_register src0 = inst->U.I.SrcReg[0]; + struct rc_src_register src1 = inst->U.I.SrcReg[1]; + src0.Negate &= ~(RC_MASK_Z | RC_MASK_W); + src0.Swizzle &= ~(63 << (3 * 2)); + src0.Swizzle |= (RC_SWIZZLE_ZERO << (3 * 2)) | (RC_SWIZZLE_ZERO << (3 * 3)); + src1.Negate &= ~(RC_MASK_Z | RC_MASK_W); + src1.Swizzle &= ~(63 << (3 * 2)); + src1.Swizzle |= (RC_SWIZZLE_ZERO << (3 * 2)) | (RC_SWIZZLE_ZERO << (3 * 3)); + emit2(c, inst->Prev, RC_OPCODE_DP3, inst->U.I.SaturateMode, inst->U.I.DstReg, src0, src1); + rc_remove_instruction(inst); +} + +static void transform_DPH(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_src_register src0 = inst->U.I.SrcReg[0]; + src0.Negate &= ~RC_MASK_W; + src0.Swizzle &= ~(7 << (3 * 3)); + src0.Swizzle |= RC_SWIZZLE_ONE << (3 * 3); + emit2(c, inst->Prev, RC_OPCODE_DP4, inst->U.I.SaturateMode, inst->U.I.DstReg, src0, inst->U.I.SrcReg[1]); + rc_remove_instruction(inst); +} + +/** + * [1, src0.y*src1.y, src0.z, src1.w] + * So basically MUL with lotsa swizzling. + */ +static void transform_DST(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + emit2(c, inst->Prev, RC_OPCODE_MUL, inst->U.I.SaturateMode, inst->U.I.DstReg, + swizzle(inst->U.I.SrcReg[0], RC_SWIZZLE_ONE, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_ONE), + swizzle(inst->U.I.SrcReg[1], RC_SWIZZLE_ONE, RC_SWIZZLE_Y, RC_SWIZZLE_ONE, RC_SWIZZLE_W)); + rc_remove_instruction(inst); +} + +static void transform_FLR(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dst, inst->U.I.SrcReg[0]); + emit2(c, inst->Prev, RC_OPCODE_ADD, inst->U.I.SaturateMode, inst->U.I.DstReg, + inst->U.I.SrcReg[0], negate(srcreg(RC_FILE_TEMPORARY, dst.Index))); + rc_remove_instruction(inst); +} + +/** + * Definition of LIT (from ARB_fragment_program): + * + * tmp = VectorLoad(op0); + * if (tmp.x < 0) tmp.x = 0; + * if (tmp.y < 0) tmp.y = 0; + * if (tmp.w < -(128.0-epsilon)) tmp.w = -(128.0-epsilon); + * else if (tmp.w > 128-epsilon) tmp.w = 128-epsilon; + * result.x = 1.0; + * result.y = tmp.x; + * result.z = (tmp.x > 0) ? RoughApproxPower(tmp.y, tmp.w) : 0.0; + * result.w = 1.0; + * + * The longest path of computation is the one leading to result.z, + * consisting of 5 operations. This implementation of LIT takes + * 5 slots, if the subsequent optimization passes are clever enough + * to pair instructions correctly. + */ +static void transform_LIT(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + unsigned int constant; + unsigned int constant_swizzle; + unsigned int temp; + struct rc_src_register srctemp; + + constant = rc_constants_add_immediate_scalar(&c->Program.Constants, -127.999999, &constant_swizzle); + + if (inst->U.I.DstReg.WriteMask != RC_MASK_XYZW || inst->U.I.DstReg.File != RC_FILE_TEMPORARY) { + struct rc_instruction * inst_mov; + + inst_mov = emit1(c, inst, + RC_OPCODE_MOV, 0, inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, rc_find_free_temporary(c))); + + inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst->U.I.DstReg.Index = inst_mov->U.I.SrcReg[0].Index; + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + } + + temp = inst->U.I.DstReg.Index; + srctemp = srcreg(RC_FILE_TEMPORARY, temp); + + /* tmp.x = max(0.0, Src.x); */ + /* tmp.y = max(0.0, Src.y); */ + /* tmp.w = clamp(Src.z, -128+eps, 128-eps); */ + emit2(c, inst->Prev, RC_OPCODE_MAX, 0, + dstregtmpmask(temp, RC_MASK_XYW), + inst->U.I.SrcReg[0], + swizzle(srcreg(RC_FILE_CONSTANT, constant), + RC_SWIZZLE_ZERO, RC_SWIZZLE_ZERO, RC_SWIZZLE_ZERO, constant_swizzle&3)); + emit2(c, inst->Prev, RC_OPCODE_MIN, 0, + dstregtmpmask(temp, RC_MASK_Z), + swizzle_wwww(srctemp), + negate(srcregswz(RC_FILE_CONSTANT, constant, constant_swizzle))); + + /* tmp.w = Pow(tmp.y, tmp.w) */ + emit1(c, inst->Prev, RC_OPCODE_LG2, 0, + dstregtmpmask(temp, RC_MASK_W), + swizzle_yyyy(srctemp)); + emit2(c, inst->Prev, RC_OPCODE_MUL, 0, + dstregtmpmask(temp, RC_MASK_W), + swizzle_wwww(srctemp), + swizzle_zzzz(srctemp)); + emit1(c, inst->Prev, RC_OPCODE_EX2, 0, + dstregtmpmask(temp, RC_MASK_W), + swizzle_wwww(srctemp)); + + /* tmp.z = (tmp.x > 0) ? tmp.w : 0.0 */ + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, + dstregtmpmask(temp, RC_MASK_Z), + negate(swizzle_xxxx(srctemp)), + swizzle_wwww(srctemp), + builtin_zero); + + /* tmp.x, tmp.y, tmp.w = 1.0, tmp.x, 1.0 */ + emit1(c, inst->Prev, RC_OPCODE_MOV, inst->U.I.SaturateMode, + dstregtmpmask(temp, RC_MASK_XYW), + swizzle(srctemp, RC_SWIZZLE_ONE, RC_SWIZZLE_X, RC_SWIZZLE_ONE, RC_SWIZZLE_ONE)); + + rc_remove_instruction(inst); +} + +static void transform_LRP(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, + dst, + inst->U.I.SrcReg[1], negate(inst->U.I.SrcReg[2])); + emit3(c, inst->Prev, RC_OPCODE_MAD, inst->U.I.SaturateMode, + inst->U.I.DstReg, + inst->U.I.SrcReg[0], srcreg(RC_FILE_TEMPORARY, dst.Index), inst->U.I.SrcReg[2]); + + rc_remove_instruction(inst); +} + +static void transform_POW(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register tempdst = try_to_reuse_dst(c, inst); + struct rc_src_register tempsrc = srcreg(RC_FILE_TEMPORARY, tempdst.Index); + tempdst.WriteMask = RC_MASK_W; + tempsrc.Swizzle = RC_SWIZZLE_WWWW; + + emit1(c, inst->Prev, RC_OPCODE_LG2, 0, tempdst, swizzle_xxxx(inst->U.I.SrcReg[0])); + emit2(c, inst->Prev, RC_OPCODE_MUL, 0, tempdst, tempsrc, swizzle_xxxx(inst->U.I.SrcReg[1])); + emit1(c, inst->Prev, RC_OPCODE_EX2, inst->U.I.SaturateMode, inst->U.I.DstReg, tempsrc); + + rc_remove_instruction(inst); +} + +static void transform_RSQ(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + inst->U.I.SrcReg[0] = absolute(inst->U.I.SrcReg[0]); +} + +static void transform_SEQ(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, dst, inst->U.I.SrcReg[0], negate(inst->U.I.SrcReg[1])); + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, inst->U.I.DstReg, + negate(absolute(srcreg(RC_FILE_TEMPORARY, dst.Index))), builtin_zero, builtin_one); + + rc_remove_instruction(inst); +} + +static void transform_SFL(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + emit1(c, inst->Prev, RC_OPCODE_MOV, inst->U.I.SaturateMode, inst->U.I.DstReg, builtin_zero); + rc_remove_instruction(inst); +} + +static void transform_SGE(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, dst, inst->U.I.SrcReg[0], negate(inst->U.I.SrcReg[1])); + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst.Index), builtin_zero, builtin_one); + + rc_remove_instruction(inst); +} + +static void transform_SGT(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, dst, negate(inst->U.I.SrcReg[0]), inst->U.I.SrcReg[1]); + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst.Index), builtin_one, builtin_zero); + + rc_remove_instruction(inst); +} + +static void transform_SLE(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, dst, negate(inst->U.I.SrcReg[0]), inst->U.I.SrcReg[1]); + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst.Index), builtin_zero, builtin_one); + + rc_remove_instruction(inst); +} + +static void transform_SLT(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, dst, inst->U.I.SrcReg[0], negate(inst->U.I.SrcReg[1])); + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst.Index), builtin_one, builtin_zero); + + rc_remove_instruction(inst); +} + +static void transform_SNE(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, dst, inst->U.I.SrcReg[0], negate(inst->U.I.SrcReg[1])); + emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, inst->U.I.DstReg, + negate(absolute(srcreg(RC_FILE_TEMPORARY, dst.Index))), builtin_one, builtin_zero); + + rc_remove_instruction(inst); +} + +static void transform_SSG(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* result = sign(x) + * + * CMP tmp0, -x, 1, 0 + * CMP tmp1, x, 1, 0 + * ADD result, tmp0, -tmp1; + */ + struct rc_dst_register dst0; + unsigned tmp1; + + /* 0 < x */ + dst0 = try_to_reuse_dst(c, inst); + emit3(c, inst->Prev, RC_OPCODE_CMP, 0, + dst0, + negate(inst->U.I.SrcReg[0]), + builtin_one, + builtin_zero); + + /* x < 0 */ + tmp1 = rc_find_free_temporary(c); + emit3(c, inst->Prev, RC_OPCODE_CMP, 0, + dstregtmpmask(tmp1, inst->U.I.DstReg.WriteMask), + inst->U.I.SrcReg[0], + builtin_one, + builtin_zero); + + /* Either both are zero, or one of them is one and the other is zero. */ + /* result = tmp0 - tmp1 */ + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst0.Index), + negate(srcreg(RC_FILE_TEMPORARY, tmp1))); + + rc_remove_instruction(inst); +} + +static void transform_SUB(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + inst->U.I.Opcode = RC_OPCODE_ADD; + inst->U.I.SrcReg[1] = negate(inst->U.I.SrcReg[1]); +} + +static void transform_SWZ(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + inst->U.I.Opcode = RC_OPCODE_MOV; +} + +static void transform_XPD(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + emit2(c, inst->Prev, RC_OPCODE_MUL, 0, dst, + swizzle(inst->U.I.SrcReg[0], RC_SWIZZLE_Z, RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_W), + swizzle(inst->U.I.SrcReg[1], RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_X, RC_SWIZZLE_W)); + emit3(c, inst->Prev, RC_OPCODE_MAD, inst->U.I.SaturateMode, inst->U.I.DstReg, + swizzle(inst->U.I.SrcReg[0], RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_X, RC_SWIZZLE_W), + swizzle(inst->U.I.SrcReg[1], RC_SWIZZLE_Z, RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_W), + negate(srcreg(RC_FILE_TEMPORARY, dst.Index))); + + rc_remove_instruction(inst); +} + + +/** + * Can be used as a transformation for @ref radeonClauseLocalTransform, + * no userData necessary. + * + * Eliminates the following ALU instructions: + * ABS, CEIL, DPH, DST, FLR, LIT, LRP, POW, SEQ, SFL, SGE, SGT, SLE, SLT, SNE, SUB, SWZ, XPD + * using: + * MOV, ADD, MUL, MAD, FRC, DP3, LG2, EX2, CMP + * + * Transforms RSQ to Radeon's native RSQ by explicitly setting + * absolute value. + * + * @note should be applicable to R300 and R500 fragment programs. + */ +int radeonTransformALU( + struct radeon_compiler * c, + struct rc_instruction* inst, + void* unused) +{ + switch(inst->U.I.Opcode) { + case RC_OPCODE_ABS: transform_ABS(c, inst); return 1; + case RC_OPCODE_CEIL: transform_CEIL(c, inst); return 1; + case RC_OPCODE_CLAMP: transform_CLAMP(c, inst); return 1; + case RC_OPCODE_DP2: transform_DP2(c, inst); return 1; + case RC_OPCODE_DPH: transform_DPH(c, inst); return 1; + case RC_OPCODE_DST: transform_DST(c, inst); return 1; + case RC_OPCODE_FLR: transform_FLR(c, inst); return 1; + case RC_OPCODE_LIT: transform_LIT(c, inst); return 1; + case RC_OPCODE_LRP: transform_LRP(c, inst); return 1; + case RC_OPCODE_POW: transform_POW(c, inst); return 1; + case RC_OPCODE_RSQ: transform_RSQ(c, inst); return 1; + case RC_OPCODE_SEQ: transform_SEQ(c, inst); return 1; + case RC_OPCODE_SFL: transform_SFL(c, inst); return 1; + case RC_OPCODE_SGE: transform_SGE(c, inst); return 1; + case RC_OPCODE_SGT: transform_SGT(c, inst); return 1; + case RC_OPCODE_SLE: transform_SLE(c, inst); return 1; + case RC_OPCODE_SLT: transform_SLT(c, inst); return 1; + case RC_OPCODE_SNE: transform_SNE(c, inst); return 1; + case RC_OPCODE_SSG: transform_SSG(c, inst); return 1; + case RC_OPCODE_SUB: transform_SUB(c, inst); return 1; + case RC_OPCODE_SWZ: transform_SWZ(c, inst); return 1; + case RC_OPCODE_XPD: transform_XPD(c, inst); return 1; + default: + return 0; + } +} + + +static void transform_r300_vertex_ABS(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* Note: r500 can take absolute values, but r300 cannot. */ + inst->U.I.Opcode = RC_OPCODE_MAX; + inst->U.I.SrcReg[1] = inst->U.I.SrcReg[0]; + inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; +} + +static void transform_r300_vertex_CMP(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* There is no decent CMP available, so let's rig one up. + * CMP is defined as dst = src0 < 0.0 ? src1 : src2 + * The following sequence consumes zero to two temps and two extra slots + * (the second temp and the second slot is consumed by transform_LRP), + * but should be equivalent: + * + * SLT tmp0, src0, 0.0 + * LRP dst, tmp0, src1, src2 + * + * Yes, I know, I'm a mad scientist. ~ C. & M. */ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + + /* SLT tmp0, src0, 0.0 */ + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + dst, + inst->U.I.SrcReg[0], builtin_zero); + + /* LRP dst, tmp0, src1, src2 */ + transform_LRP(c, + emit3(c, inst->Prev, RC_OPCODE_LRP, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst.Index), inst->U.I.SrcReg[1], inst->U.I.SrcReg[2])); + + rc_remove_instruction(inst); +} + +static void transform_r300_vertex_DP2(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_instruction *next_inst = inst->Next; + transform_DP2(c, inst); + next_inst->Prev->U.I.Opcode = RC_OPCODE_DP4; +} + +static void transform_r300_vertex_DP3(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_src_register src0 = inst->U.I.SrcReg[0]; + struct rc_src_register src1 = inst->U.I.SrcReg[1]; + src0.Negate &= ~RC_MASK_W; + src0.Swizzle &= ~(7 << (3 * 3)); + src0.Swizzle |= RC_SWIZZLE_ZERO << (3 * 3); + src1.Negate &= ~RC_MASK_W; + src1.Swizzle &= ~(7 << (3 * 3)); + src1.Swizzle |= RC_SWIZZLE_ZERO << (3 * 3); + emit2(c, inst->Prev, RC_OPCODE_DP4, inst->U.I.SaturateMode, inst->U.I.DstReg, src0, src1); + rc_remove_instruction(inst); +} + +static void transform_r300_vertex_fix_LIT(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + struct rc_dst_register dst = try_to_reuse_dst(c, inst); + unsigned constant_swizzle; + int constant = rc_constants_add_immediate_scalar(&c->Program.Constants, + 0.0000000000000000001, + &constant_swizzle); + + /* MOV dst, src */ + dst.WriteMask = RC_MASK_XYZW; + emit1(c, inst->Prev, RC_OPCODE_MOV, 0, + dst, + inst->U.I.SrcReg[0]); + + /* MAX dst.y, src, 0.00...001 */ + emit2(c, inst->Prev, RC_OPCODE_MAX, 0, + dstregtmpmask(dst.Index, RC_MASK_Y), + srcreg(RC_FILE_TEMPORARY, dst.Index), + srcregswz(RC_FILE_CONSTANT, constant, constant_swizzle)); + + inst->U.I.SrcReg[0] = srcreg(RC_FILE_TEMPORARY, dst.Index); +} + +static void transform_r300_vertex_SEQ(struct radeon_compiler *c, + struct rc_instruction *inst) +{ + /* x = y <==> x >= y && y >= x */ + int tmp = rc_find_free_temporary(c); + + /* x <= y */ + emit2(c, inst->Prev, RC_OPCODE_SGE, 0, + dstregtmpmask(tmp, inst->U.I.DstReg.WriteMask), + inst->U.I.SrcReg[0], + inst->U.I.SrcReg[1]); + + /* y <= x */ + emit2(c, inst->Prev, RC_OPCODE_SGE, 0, + inst->U.I.DstReg, + inst->U.I.SrcReg[1], + inst->U.I.SrcReg[0]); + + /* x && y = x * y */ + emit2(c, inst->Prev, RC_OPCODE_MUL, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, tmp), + srcreg(inst->U.I.DstReg.File, inst->U.I.DstReg.Index)); + + rc_remove_instruction(inst); +} + +static void transform_r300_vertex_SNE(struct radeon_compiler *c, + struct rc_instruction *inst) +{ + /* x != y <==> x < y || y < x */ + int tmp = rc_find_free_temporary(c); + + /* x < y */ + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + dstregtmpmask(tmp, inst->U.I.DstReg.WriteMask), + inst->U.I.SrcReg[0], + inst->U.I.SrcReg[1]); + + /* y < x */ + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + inst->U.I.DstReg, + inst->U.I.SrcReg[1], + inst->U.I.SrcReg[0]); + + /* x || y = max(x, y) */ + emit2(c, inst->Prev, RC_OPCODE_MAX, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, tmp), + srcreg(inst->U.I.DstReg.File, inst->U.I.DstReg.Index)); + + rc_remove_instruction(inst); +} + +static void transform_r300_vertex_SGT(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* x > y <==> -x < -y */ + inst->U.I.Opcode = RC_OPCODE_SLT; + inst->U.I.SrcReg[0].Negate ^= RC_MASK_XYZW; + inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; +} + +static void transform_r300_vertex_SLE(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* x <= y <==> -x >= -y */ + inst->U.I.Opcode = RC_OPCODE_SGE; + inst->U.I.SrcReg[0].Negate ^= RC_MASK_XYZW; + inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW; +} + +static void transform_r300_vertex_SSG(struct radeon_compiler* c, + struct rc_instruction* inst) +{ + /* result = sign(x) + * + * SLT tmp0, 0, x; + * SLT tmp1, x, 0; + * ADD result, tmp0, -tmp1; + */ + struct rc_dst_register dst0 = try_to_reuse_dst(c, inst); + unsigned tmp1; + + /* 0 < x */ + dst0 = try_to_reuse_dst(c, inst); + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + dst0, + builtin_zero, + inst->U.I.SrcReg[0]); + + /* x < 0 */ + tmp1 = rc_find_free_temporary(c); + emit2(c, inst->Prev, RC_OPCODE_SLT, 0, + dstregtmpmask(tmp1, inst->U.I.DstReg.WriteMask), + inst->U.I.SrcReg[0], + builtin_zero); + + /* Either both are zero, or one of them is one and the other is zero. */ + /* result = tmp0 - tmp1 */ + emit2(c, inst->Prev, RC_OPCODE_ADD, 0, + inst->U.I.DstReg, + srcreg(RC_FILE_TEMPORARY, dst0.Index), + negate(srcreg(RC_FILE_TEMPORARY, tmp1))); + + rc_remove_instruction(inst); +} + +/** + * For use with rc_local_transform, this transforms non-native ALU + * instructions of the r300 up to r500 vertex engine. + */ +int r300_transform_vertex_alu( + struct radeon_compiler * c, + struct rc_instruction* inst, + void* unused) +{ + switch(inst->U.I.Opcode) { + case RC_OPCODE_ABS: transform_r300_vertex_ABS(c, inst); return 1; + case RC_OPCODE_CEIL: transform_CEIL(c, inst); return 1; + case RC_OPCODE_CLAMP: transform_CLAMP(c, inst); return 1; + case RC_OPCODE_CMP: transform_r300_vertex_CMP(c, inst); return 1; + case RC_OPCODE_DP2: transform_r300_vertex_DP2(c, inst); return 1; + case RC_OPCODE_DP3: transform_r300_vertex_DP3(c, inst); return 1; + case RC_OPCODE_DPH: transform_DPH(c, inst); return 1; + case RC_OPCODE_FLR: transform_FLR(c, inst); return 1; + case RC_OPCODE_LIT: transform_r300_vertex_fix_LIT(c, inst); return 1; + case RC_OPCODE_LRP: transform_LRP(c, inst); return 1; + case RC_OPCODE_SEQ: + if (!c->is_r500) { + transform_r300_vertex_SEQ(c, inst); + return 1; + } + return 0; + case RC_OPCODE_SFL: transform_SFL(c, inst); return 1; + case RC_OPCODE_SGT: transform_r300_vertex_SGT(c, inst); return 1; + case RC_OPCODE_SLE: transform_r300_vertex_SLE(c, inst); return 1; + case RC_OPCODE_SNE: + if (!c->is_r500) { + transform_r300_vertex_SNE(c, inst); + return 1; + } + return 0; + case RC_OPCODE_SSG: transform_r300_vertex_SSG(c, inst); return 1; + case RC_OPCODE_SUB: transform_SUB(c, inst); return 1; + case RC_OPCODE_SWZ: transform_SWZ(c, inst); return 1; + case RC_OPCODE_XPD: transform_XPD(c, inst); return 1; + default: + return 0; + } +} + +static void sincos_constants(struct radeon_compiler* c, unsigned int *constants) +{ + static const float SinCosConsts[2][4] = { + { + 1.273239545, /* 4/PI */ + -0.405284735, /* -4/(PI*PI) */ + 3.141592654, /* PI */ + 0.2225 /* weight */ + }, + { + 0.75, + 0.5, + 0.159154943, /* 1/(2*PI) */ + 6.283185307 /* 2*PI */ + } + }; + int i; + + for(i = 0; i < 2; ++i) + constants[i] = rc_constants_add_immediate_vec4(&c->Program.Constants, SinCosConsts[i]); +} + +/** + * Approximate sin(x), where x is clamped to (-pi/2, pi/2). + * + * MUL tmp.xy, src, { 4/PI, -4/(PI^2) } + * MAD tmp.x, tmp.y, |src|, tmp.x + * MAD tmp.y, tmp.x, |tmp.x|, -tmp.x + * MAD dest, tmp.y, weight, tmp.x + */ +static void sin_approx( + struct radeon_compiler* c, struct rc_instruction * inst, + struct rc_dst_register dst, struct rc_src_register src, const unsigned int* constants) +{ + unsigned int tempreg = rc_find_free_temporary(c); + + emit2(c, inst->Prev, RC_OPCODE_MUL, 0, dstregtmpmask(tempreg, RC_MASK_XY), + swizzle_xxxx(src), + srcreg(RC_FILE_CONSTANT, constants[0])); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_X), + swizzle_yyyy(srcreg(RC_FILE_TEMPORARY, tempreg)), + absolute(swizzle_xxxx(src)), + swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg))); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_Y), + swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg)), + absolute(swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg))), + negate(swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg)))); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dst, + swizzle_yyyy(srcreg(RC_FILE_TEMPORARY, tempreg)), + swizzle_wwww(srcreg(RC_FILE_CONSTANT, constants[0])), + swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg))); +} + +/** + * Translate the trigonometric functions COS, SIN, and SCS + * using only the basic instructions + * MOV, ADD, MUL, MAD, FRC + */ +int r300_transform_trig_simple(struct radeon_compiler* c, + struct rc_instruction* inst, + void* unused) +{ + unsigned int constants[2]; + unsigned int tempreg; + + if (inst->U.I.Opcode != RC_OPCODE_COS && + inst->U.I.Opcode != RC_OPCODE_SIN && + inst->U.I.Opcode != RC_OPCODE_SCS) + return 0; + + tempreg = rc_find_free_temporary(c); + + sincos_constants(c, constants); + + if (inst->U.I.Opcode == RC_OPCODE_COS) { + /* MAD tmp.x, src, 1/(2*PI), 0.75 */ + /* FRC tmp.x, tmp.x */ + /* MAD tmp.z, tmp.x, 2*PI, -PI */ + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_W), + swizzle_xxxx(inst->U.I.SrcReg[0]), + swizzle_zzzz(srcreg(RC_FILE_CONSTANT, constants[1])), + swizzle_xxxx(srcreg(RC_FILE_CONSTANT, constants[1]))); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dstregtmpmask(tempreg, RC_MASK_W), + swizzle_wwww(srcreg(RC_FILE_TEMPORARY, tempreg))); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_W), + swizzle_wwww(srcreg(RC_FILE_TEMPORARY, tempreg)), + swizzle_wwww(srcreg(RC_FILE_CONSTANT, constants[1])), + negate(swizzle_zzzz(srcreg(RC_FILE_CONSTANT, constants[0])))); + + sin_approx(c, inst, inst->U.I.DstReg, + swizzle_wwww(srcreg(RC_FILE_TEMPORARY, tempreg)), + constants); + } else if (inst->U.I.Opcode == RC_OPCODE_SIN) { + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_W), + swizzle_xxxx(inst->U.I.SrcReg[0]), + swizzle_zzzz(srcreg(RC_FILE_CONSTANT, constants[1])), + swizzle_yyyy(srcreg(RC_FILE_CONSTANT, constants[1]))); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dstregtmpmask(tempreg, RC_MASK_W), + swizzle_wwww(srcreg(RC_FILE_TEMPORARY, tempreg))); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_W), + swizzle_wwww(srcreg(RC_FILE_TEMPORARY, tempreg)), + swizzle_wwww(srcreg(RC_FILE_CONSTANT, constants[1])), + negate(swizzle_zzzz(srcreg(RC_FILE_CONSTANT, constants[0])))); + + sin_approx(c, inst, inst->U.I.DstReg, + swizzle_wwww(srcreg(RC_FILE_TEMPORARY, tempreg)), + constants); + } else { + struct rc_dst_register dst; + + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_XY), + swizzle_xxxx(inst->U.I.SrcReg[0]), + swizzle_zzzz(srcreg(RC_FILE_CONSTANT, constants[1])), + swizzle(srcreg(RC_FILE_CONSTANT, constants[1]), RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_W)); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dstregtmpmask(tempreg, RC_MASK_XY), + srcreg(RC_FILE_TEMPORARY, tempreg)); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_XY), + srcreg(RC_FILE_TEMPORARY, tempreg), + swizzle_wwww(srcreg(RC_FILE_CONSTANT, constants[1])), + negate(swizzle_zzzz(srcreg(RC_FILE_CONSTANT, constants[0])))); + + dst = inst->U.I.DstReg; + + dst.WriteMask = inst->U.I.DstReg.WriteMask & RC_MASK_X; + sin_approx(c, inst, dst, + swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg)), + constants); + + dst.WriteMask = inst->U.I.DstReg.WriteMask & RC_MASK_Y; + sin_approx(c, inst, dst, + swizzle_yyyy(srcreg(RC_FILE_TEMPORARY, tempreg)), + constants); + } + + rc_remove_instruction(inst); + + return 1; +} + +static void r300_transform_SIN_COS_SCS(struct radeon_compiler *c, + struct rc_instruction *inst, + unsigned srctmp) +{ + if (inst->U.I.Opcode == RC_OPCODE_COS) { + emit1(c, inst->Prev, RC_OPCODE_COS, inst->U.I.SaturateMode, inst->U.I.DstReg, + srcregswz(RC_FILE_TEMPORARY, srctmp, RC_SWIZZLE_WWWW)); + } else if (inst->U.I.Opcode == RC_OPCODE_SIN) { + emit1(c, inst->Prev, RC_OPCODE_SIN, inst->U.I.SaturateMode, + inst->U.I.DstReg, srcregswz(RC_FILE_TEMPORARY, srctmp, RC_SWIZZLE_WWWW)); + } else if (inst->U.I.Opcode == RC_OPCODE_SCS) { + struct rc_dst_register moddst = inst->U.I.DstReg; + + if (inst->U.I.DstReg.WriteMask & RC_MASK_X) { + moddst.WriteMask = RC_MASK_X; + emit1(c, inst->Prev, RC_OPCODE_COS, inst->U.I.SaturateMode, moddst, + srcregswz(RC_FILE_TEMPORARY, srctmp, RC_SWIZZLE_WWWW)); + } + if (inst->U.I.DstReg.WriteMask & RC_MASK_Y) { + moddst.WriteMask = RC_MASK_Y; + emit1(c, inst->Prev, RC_OPCODE_SIN, inst->U.I.SaturateMode, moddst, + srcregswz(RC_FILE_TEMPORARY, srctmp, RC_SWIZZLE_WWWW)); + } + } + + rc_remove_instruction(inst); +} + + +/** + * Transform the trigonometric functions COS, SIN, and SCS + * to include pre-scaling by 1/(2*PI) and taking the fractional + * part, so that the input to COS and SIN is always in the range [0,1). + * SCS is replaced by one COS and one SIN instruction. + * + * @warning This transformation implicitly changes the semantics of SIN and COS! + */ +int radeonTransformTrigScale(struct radeon_compiler* c, + struct rc_instruction* inst, + void* unused) +{ + static const float RCP_2PI = 0.15915494309189535; + unsigned int temp; + unsigned int constant; + unsigned int constant_swizzle; + + if (inst->U.I.Opcode != RC_OPCODE_COS && + inst->U.I.Opcode != RC_OPCODE_SIN && + inst->U.I.Opcode != RC_OPCODE_SCS) + return 0; + + temp = rc_find_free_temporary(c); + constant = rc_constants_add_immediate_scalar(&c->Program.Constants, RCP_2PI, &constant_swizzle); + + emit2(c, inst->Prev, RC_OPCODE_MUL, 0, dstregtmpmask(temp, RC_MASK_W), + swizzle_xxxx(inst->U.I.SrcReg[0]), + srcregswz(RC_FILE_CONSTANT, constant, constant_swizzle)); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dstregtmpmask(temp, RC_MASK_W), + srcreg(RC_FILE_TEMPORARY, temp)); + + r300_transform_SIN_COS_SCS(c, inst, temp); + return 1; +} + +/** + * Transform the trigonometric functions COS, SIN, and SCS + * so that the input to COS and SIN is always in the range [-PI, PI]. + * SCS is replaced by one COS and one SIN instruction. + */ +int r300_transform_trig_scale_vertex(struct radeon_compiler *c, + struct rc_instruction *inst, + void *unused) +{ + static const float cons[4] = {0.15915494309189535, 0.5, 6.28318530717959, -3.14159265358979}; + unsigned int temp; + unsigned int constant; + + if (inst->U.I.Opcode != RC_OPCODE_COS && + inst->U.I.Opcode != RC_OPCODE_SIN && + inst->U.I.Opcode != RC_OPCODE_SCS) + return 0; + + /* Repeat x in the range [-PI, PI]: + * + * repeat(x) = frac(x / 2PI + 0.5) * 2PI - PI + */ + + temp = rc_find_free_temporary(c); + constant = rc_constants_add_immediate_vec4(&c->Program.Constants, cons); + + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(temp, RC_MASK_W), + swizzle_xxxx(inst->U.I.SrcReg[0]), + srcregswz(RC_FILE_CONSTANT, constant, RC_SWIZZLE_XXXX), + srcregswz(RC_FILE_CONSTANT, constant, RC_SWIZZLE_YYYY)); + emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dstregtmpmask(temp, RC_MASK_W), + srcreg(RC_FILE_TEMPORARY, temp)); + emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(temp, RC_MASK_W), + srcreg(RC_FILE_TEMPORARY, temp), + srcregswz(RC_FILE_CONSTANT, constant, RC_SWIZZLE_ZZZZ), + srcregswz(RC_FILE_CONSTANT, constant, RC_SWIZZLE_WWWW)); + + r300_transform_SIN_COS_SCS(c, inst, temp); + return 1; +} + +/** + * Rewrite DDX/DDY instructions to properly work with r5xx shaders. + * The r5xx MDH/MDV instruction provides per-quad partial derivatives. + * It takes the form A*B+C. A and C are set by setting src0. B should be -1. + * + * @warning This explicitly changes the form of DDX and DDY! + */ + +int radeonTransformDeriv(struct radeon_compiler* c, + struct rc_instruction* inst, + void* unused) +{ + if (inst->U.I.Opcode != RC_OPCODE_DDX && inst->U.I.Opcode != RC_OPCODE_DDY) + return 0; + + inst->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_1111; + inst->U.I.SrcReg[1].Negate = RC_MASK_XYZW; + + return 1; +} + +/** + * IF Temp[0].x -\ + * KILP - > KIL -abs(Temp[0].x) + * ENDIF -/ + * + * This needs to be done in its own pass, because it modifies the instructions + * before and after KILP. + */ +void rc_transform_KILP(struct radeon_compiler * c, void *user) +{ + struct rc_instruction * inst; + for (inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + + if (inst->U.I.Opcode != RC_OPCODE_KILP) + continue; + + inst->U.I.Opcode = RC_OPCODE_KIL; + + if (inst->Prev->U.I.Opcode != RC_OPCODE_IF + || inst->Next->U.I.Opcode != RC_OPCODE_ENDIF) { + inst->U.I.SrcReg[0] = negate(builtin_one); + } else { + + inst->U.I.SrcReg[0] = + negate(absolute(inst->Prev->U.I.SrcReg[0])); + /* Remove IF */ + rc_remove_instruction(inst->Prev); + /* Remove ENDIF */ + rc_remove_instruction(inst->Next); + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_program_alu.h b/src/gallium/drivers/r300/compiler/radeon_program_alu.h new file mode 100644 index 00000000000..b5f361e624f --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_alu.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __RADEON_PROGRAM_ALU_H_ +#define __RADEON_PROGRAM_ALU_H_ + +#include "radeon_program.h" + +int radeonTransformALU( + struct radeon_compiler * c, + struct rc_instruction * inst, + void*); + +int r300_transform_vertex_alu( + struct radeon_compiler * c, + struct rc_instruction * inst, + void*); + +int r300_transform_trig_simple( + struct radeon_compiler * c, + struct rc_instruction * inst, + void*); + +int radeonTransformTrigScale( + struct radeon_compiler * c, + struct rc_instruction * inst, + void*); + +int r300_transform_trig_scale_vertex( + struct radeon_compiler *c, + struct rc_instruction *inst, + void*); + +int radeonTransformDeriv( + struct radeon_compiler * c, + struct rc_instruction * inst, + void*); + +void rc_transform_KILP(struct radeon_compiler * c, + void *user); + +#endif /* __RADEON_PROGRAM_ALU_H_ */ diff --git a/src/gallium/drivers/r300/compiler/radeon_program_constants.h b/src/gallium/drivers/r300/compiler/radeon_program_constants.h new file mode 100644 index 00000000000..24577333450 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_constants.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_PROGRAM_CONSTANTS_H +#define RADEON_PROGRAM_CONSTANTS_H + +typedef enum { + RC_SATURATE_NONE = 0, + RC_SATURATE_ZERO_ONE, + RC_SATURATE_MINUS_PLUS_ONE +} rc_saturate_mode; + +typedef enum { + RC_TEXTURE_2D_ARRAY, + RC_TEXTURE_1D_ARRAY, + RC_TEXTURE_CUBE, + RC_TEXTURE_3D, + RC_TEXTURE_RECT, + RC_TEXTURE_2D, + RC_TEXTURE_1D +} rc_texture_target; + +typedef enum { + /** + * Used to indicate unused register descriptions and + * source register that use a constant swizzle. + */ + RC_FILE_NONE = 0, + RC_FILE_TEMPORARY, + + /** + * Input register. + * + * \note The compiler attaches no implicit semantics to input registers. + * Fragment/vertex program specific semantics must be defined explicitly + * using the appropriate compiler interfaces. + */ + RC_FILE_INPUT, + + /** + * Output register. + * + * \note The compiler attaches no implicit semantics to input registers. + * Fragment/vertex program specific semantics must be defined explicitly + * using the appropriate compiler interfaces. + */ + RC_FILE_OUTPUT, + RC_FILE_ADDRESS, + + /** + * Indicates a constant from the \ref rc_constant_list . + */ + RC_FILE_CONSTANT, + + /** + * Indicates a special register, see RC_SPECIAL_xxx. + */ + RC_FILE_SPECIAL, + + /** + * Indicates this register should use the result of the presubtract + * operation. + */ + RC_FILE_PRESUB +} rc_register_file; + +enum { + /** R500 fragment program ALU result "register" */ + RC_SPECIAL_ALU_RESULT = 0, + + /** Must be last */ + RC_NUM_SPECIAL_REGISTERS +}; + +#define RC_REGISTER_INDEX_BITS 10 +#define RC_REGISTER_MAX_INDEX (1 << RC_REGISTER_INDEX_BITS) + +typedef enum { + RC_SWIZZLE_X = 0, + RC_SWIZZLE_Y, + RC_SWIZZLE_Z, + RC_SWIZZLE_W, + RC_SWIZZLE_ZERO, + RC_SWIZZLE_ONE, + RC_SWIZZLE_HALF, + RC_SWIZZLE_UNUSED +} rc_swizzle; + +#define RC_MAKE_SWIZZLE(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9)) +#define RC_MAKE_SWIZZLE_SMEAR(a) RC_MAKE_SWIZZLE((a),(a),(a),(a)) +#define GET_SWZ(swz, idx) (((swz) >> ((idx)*3)) & 0x7) +#define GET_BIT(msk, idx) (((msk) >> (idx)) & 0x1) +#define SET_SWZ(swz, idx, newv) \ + do { \ + (swz) = ((swz) & ~(7 << ((idx)*3))) | ((newv) << ((idx)*3)); \ + } while(0) + +#define RC_SWIZZLE_XYZW RC_MAKE_SWIZZLE(RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_W) +#define RC_SWIZZLE_XYZ0 RC_MAKE_SWIZZLE(RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_ZERO) +#define RC_SWIZZLE_XYZZ RC_MAKE_SWIZZLE(RC_SWIZZLE_X, RC_SWIZZLE_Y, RC_SWIZZLE_Z, RC_SWIZZLE_Z) +#define RC_SWIZZLE_XXXX RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_X) +#define RC_SWIZZLE_YYYY RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_Y) +#define RC_SWIZZLE_ZZZZ RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_Z) +#define RC_SWIZZLE_WWWW RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_W) +#define RC_SWIZZLE_0000 RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_ZERO) +#define RC_SWIZZLE_1111 RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_ONE) +#define RC_SWIZZLE_HHHH RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_HALF) +#define RC_SWIZZLE_UUUU RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_UNUSED) + +/** + * \name Bitmasks for components of vectors. + * + * Used for write masks, negation masks, etc. + */ +/*@{*/ +#define RC_MASK_NONE 0 +#define RC_MASK_X 1 +#define RC_MASK_Y 2 +#define RC_MASK_Z 4 +#define RC_MASK_W 8 +#define RC_MASK_XY (RC_MASK_X|RC_MASK_Y) +#define RC_MASK_XYZ (RC_MASK_X|RC_MASK_Y|RC_MASK_Z) +#define RC_MASK_XYW (RC_MASK_X|RC_MASK_Y|RC_MASK_W) +#define RC_MASK_XYZW (RC_MASK_X|RC_MASK_Y|RC_MASK_Z|RC_MASK_W) +/*@}*/ + +typedef enum { + RC_ALURESULT_NONE = 0, + RC_ALURESULT_X, + RC_ALURESULT_W +} rc_write_aluresult; + +typedef enum { + RC_PRESUB_NONE = 0, + + /** 1 - 2 * src0 */ + RC_PRESUB_BIAS, + + /** src1 - src0 */ + RC_PRESUB_SUB, + + /** src1 + src0 */ + RC_PRESUB_ADD, + + /** 1 - src0 */ + RC_PRESUB_INV +} rc_presubtract_op; + +static inline int rc_presubtract_src_reg_count(rc_presubtract_op op){ + switch(op){ + case RC_PRESUB_BIAS: + case RC_PRESUB_INV: + return 1; + case RC_PRESUB_ADD: + case RC_PRESUB_SUB: + return 2; + default: + return 0; + } +} + +#define RC_SOURCE_NONE 0x0 +#define RC_SOURCE_RGB 0x1 +#define RC_SOURCE_ALPHA 0x2 + +#endif /* RADEON_PROGRAM_CONSTANTS_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_program_pair.c b/src/gallium/drivers/r300/compiler/radeon_program_pair.c new file mode 100644 index 00000000000..52315957520 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_pair.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2008-2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_program_pair.h" + +#include "radeon_compiler_util.h" + +#include <stdlib.h> + +/** + * Return the source slot where we installed the given register access, + * or -1 if no slot was free anymore. + */ +int rc_pair_alloc_source(struct rc_pair_instruction *pair, + unsigned int rgb, unsigned int alpha, + rc_register_file file, unsigned int index) +{ + int candidate = -1; + int candidate_quality = -1; + unsigned int alpha_used = 0; + unsigned int rgb_used = 0; + int i; + + if ((!rgb && !alpha) || file == RC_FILE_NONE) + return 0; + + /* Make sure only one presubtract operation is used per instruction. */ + if (file == RC_FILE_PRESUB) { + if (rgb && pair->RGB.Src[RC_PAIR_PRESUB_SRC].Used + && index != pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index) { + return -1; + } + + if (alpha && pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Used + && index != pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) { + return -1; + } + } + + for(i = 0; i < 3; ++i) { + int q = 0; + if (rgb) { + if (pair->RGB.Src[i].Used) { + if (pair->RGB.Src[i].File != file || + pair->RGB.Src[i].Index != index) { + rgb_used++; + continue; + } + q++; + } + } + if (alpha) { + if (pair->Alpha.Src[i].Used) { + if (pair->Alpha.Src[i].File != file || + pair->Alpha.Src[i].Index != index) { + alpha_used++; + continue; + } + q++; + } + } + if (q > candidate_quality) { + candidate_quality = q; + candidate = i; + } + } + + if (file == RC_FILE_PRESUB) { + candidate = RC_PAIR_PRESUB_SRC; + } else if (candidate < 0 || (rgb && rgb_used > 2) + || (alpha && alpha_used > 2)) { + return -1; + } + + /* candidate >= 0 */ + + if (rgb) { + pair->RGB.Src[candidate].Used = 1; + pair->RGB.Src[candidate].File = file; + pair->RGB.Src[candidate].Index = index; + if (candidate == RC_PAIR_PRESUB_SRC) { + /* For registers with the RC_FILE_PRESUB file, + * the index stores the presubtract op. */ + int src_regs = rc_presubtract_src_reg_count(index); + for(i = 0; i < src_regs; i++) { + pair->RGB.Src[i].Used = 1; + } + } + } + if (alpha) { + pair->Alpha.Src[candidate].Used = 1; + pair->Alpha.Src[candidate].File = file; + pair->Alpha.Src[candidate].Index = index; + if (candidate == RC_PAIR_PRESUB_SRC) { + /* For registers with the RC_FILE_PRESUB file, + * the index stores the presubtract op. */ + int src_regs = rc_presubtract_src_reg_count(index); + for(i=0; i < src_regs; i++) { + pair->Alpha.Src[i].Used = 1; + } + } + } + + return candidate; +} + +static void pair_foreach_source_callback( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb, + unsigned int swz, + unsigned int src) +{ + /* swz > 3 means that the swizzle is either not used, or a constant + * swizzle (e.g. 0, 1, 0.5). */ + if(swz > 3) + return; + + if(swz == RC_SWIZZLE_W) { + if (src == RC_PAIR_PRESUB_SRC) { + unsigned int i; + unsigned int src_count = rc_presubtract_src_reg_count( + pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index); + for(i = 0; i < src_count; i++) { + cb(data, &pair->Alpha.Src[i]); + } + } else { + cb(data, &pair->Alpha.Src[src]); + } + } else { + if (src == RC_PAIR_PRESUB_SRC) { + unsigned int i; + unsigned int src_count = rc_presubtract_src_reg_count( + pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index); + for(i = 0; i < src_count; i++) { + cb(data, &pair->RGB.Src[i]); + } + } + else { + cb(data, &pair->RGB.Src[src]); + } + } +} + +void rc_pair_foreach_source_that_alpha_reads( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb) +{ + unsigned int i; + const struct rc_opcode_info * info = + rc_get_opcode_info(pair->Alpha.Opcode); + for(i = 0; i < info->NumSrcRegs; i++) { + pair_foreach_source_callback(pair, data, cb, + GET_SWZ(pair->Alpha.Arg[i].Swizzle, 0), + pair->Alpha.Arg[i].Source); + } +} + +void rc_pair_foreach_source_that_rgb_reads( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb) +{ + unsigned int i; + const struct rc_opcode_info * info = + rc_get_opcode_info(pair->RGB.Opcode); + for(i = 0; i < info->NumSrcRegs; i++) { + unsigned int chan; + unsigned int swz = RC_SWIZZLE_UNUSED; + /* Find a swizzle that is either X,Y,Z,or W. We assume here + * that if one channel swizzles X,Y, or Z, then none of the + * other channels swizzle W, and vice-versa. */ + for(chan = 0; chan < 4; chan++) { + swz = GET_SWZ(pair->RGB.Arg[i].Swizzle, chan); + if(swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y + || swz == RC_SWIZZLE_Z || swz == RC_SWIZZLE_W) + continue; + } + pair_foreach_source_callback(pair, data, cb, + swz, + pair->RGB.Arg[i].Source); + } +} + +struct rc_pair_instruction_source * rc_pair_get_src( + struct rc_pair_instruction * pair_inst, + struct rc_pair_instruction_arg * arg) +{ + unsigned int type; + + type = rc_source_type_swz(arg->Swizzle); + + if (type & RC_SOURCE_RGB) { + return &pair_inst->RGB.Src[arg->Source]; + } else if (type & RC_SOURCE_ALPHA) { + return &pair_inst->Alpha.Src[arg->Source]; + } else { + return NULL; + } +} + +int rc_pair_get_src_index( + struct rc_pair_instruction * pair_inst, + struct rc_pair_instruction_source * src) +{ + int i; + for (i = 0; i < 3; i++) { + if (&pair_inst->RGB.Src[i] == src + || &pair_inst->Alpha.Src[i] == src) { + return i; + } + } + return -1; +} diff --git a/src/gallium/drivers/r300/compiler/radeon_program_pair.h b/src/gallium/drivers/r300/compiler/radeon_program_pair.h new file mode 100644 index 00000000000..a957ea9f7a0 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_pair.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2008 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __RADEON_PROGRAM_PAIR_H_ +#define __RADEON_PROGRAM_PAIR_H_ + +#include "radeon_code.h" +#include "radeon_opcodes.h" +#include "radeon_program_constants.h" + +struct radeon_compiler; + + +/** + * \file + * Represents a paired ALU instruction, as found in R300 and R500 + * fragment programs. + * + * Note that this representation is taking some liberties as far + * as register files are concerned, to allow separate register + * allocation. + * + * Also note that there are some subtleties in that the semantics + * of certain opcodes are implicitly changed in this representation; + * see \ref rc_pair_translate + */ + +/* For rgb and alpha instructions when arg[n].Source = RC_PAIR_PRESUB_SRC, then + * the presubtract value will be used, and + * {RGB,Alpha}.Src[RC_PAIR_PRESUB_SRC].File will be set to RC_FILE_PRESUB. + */ +#define RC_PAIR_PRESUB_SRC 3 + +struct rc_pair_instruction_source { + unsigned int Used:1; + unsigned int File:3; + unsigned int Index:RC_REGISTER_INDEX_BITS; +}; + +struct rc_pair_instruction_arg { + unsigned int Source:2; + unsigned int Swizzle:12; + unsigned int Abs:1; + unsigned int Negate:1; +}; + +struct rc_pair_sub_instruction { + unsigned int Opcode:8; + unsigned int DestIndex:RC_REGISTER_INDEX_BITS; + unsigned int WriteMask:4; + unsigned int Target:2; + unsigned int OutputWriteMask:3; + unsigned int DepthWriteMask:1; + unsigned int Saturate:1; + + struct rc_pair_instruction_source Src[4]; + struct rc_pair_instruction_arg Arg[3]; +}; + +struct rc_pair_instruction { + struct rc_pair_sub_instruction RGB; + struct rc_pair_sub_instruction Alpha; + + unsigned int WriteALUResult:2; + unsigned int ALUResultCompare:3; + unsigned int Nop:1; +}; + +typedef void (*rc_pair_foreach_src_fn) + (void *, struct rc_pair_instruction_source *); + +/** + * General helper functions for dealing with the paired instruction format. + */ +/*@{*/ +int rc_pair_alloc_source(struct rc_pair_instruction *pair, + unsigned int rgb, unsigned int alpha, + rc_register_file file, unsigned int index); + +void rc_pair_foreach_source_that_alpha_reads( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb); + +void rc_pair_foreach_source_that_rgb_reads( + struct rc_pair_instruction * pair, + void * data, + rc_pair_foreach_src_fn cb); + +struct rc_pair_instruction_source * rc_pair_get_src( + struct rc_pair_instruction * pair_inst, + struct rc_pair_instruction_arg * arg); + +int rc_pair_get_src_index( + struct rc_pair_instruction * pair_inst, + struct rc_pair_instruction_source * src); +/*@}*/ + + +/** + * Compiler passes that operate with the paired format. + */ +/*@{*/ +struct radeon_pair_handler; + +void rc_pair_translate(struct radeon_compiler *cc, void *user); +void rc_pair_schedule(struct radeon_compiler *cc, void *user); +void rc_pair_regalloc(struct radeon_compiler *cc, void *user); +void rc_pair_regalloc_inputs_only(struct radeon_compiler *cc, void *user); +void rc_pair_remove_dead_sources(struct radeon_compiler *c, void *user); +/*@}*/ + +#endif /* __RADEON_PROGRAM_PAIR_H_ */ diff --git a/src/gallium/drivers/r300/compiler/radeon_program_print.c b/src/gallium/drivers/r300/compiler/radeon_program_print.c new file mode 100644 index 00000000000..390d1319460 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_print.c @@ -0,0 +1,418 @@ +/* + * Copyright 2009 Nicolai Hähnle <[email protected]> + * + * 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 + * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */ + +#include "radeon_program.h" + +#include <stdio.h> + +static const char * textarget_to_string(rc_texture_target target) +{ + switch(target) { + case RC_TEXTURE_2D_ARRAY: return "2D_ARRAY"; + case RC_TEXTURE_1D_ARRAY: return "1D_ARRAY"; + case RC_TEXTURE_CUBE: return "CUBE"; + case RC_TEXTURE_3D: return "3D"; + case RC_TEXTURE_RECT: return "RECT"; + case RC_TEXTURE_2D: return "2D"; + case RC_TEXTURE_1D: return "1D"; + default: return "BAD_TEXTURE_TARGET"; + } +} + +static const char * presubtract_op_to_string(rc_presubtract_op op) +{ + switch(op) { + case RC_PRESUB_NONE: + return "NONE"; + case RC_PRESUB_BIAS: + return "(1 - 2 * src0)"; + case RC_PRESUB_SUB: + return "(src1 - src0)"; + case RC_PRESUB_ADD: + return "(src1 + src0)"; + case RC_PRESUB_INV: + return "(1 - src0)"; + default: + return "BAD_PRESUBTRACT_OP"; + } +} + +static void rc_print_comparefunc(FILE * f, const char * lhs, rc_compare_func func, const char * rhs) +{ + if (func == RC_COMPARE_FUNC_NEVER) { + fprintf(f, "false"); + } else if (func == RC_COMPARE_FUNC_ALWAYS) { + fprintf(f, "true"); + } else { + const char * op; + switch(func) { + case RC_COMPARE_FUNC_LESS: op = "<"; break; + case RC_COMPARE_FUNC_EQUAL: op = "=="; break; + case RC_COMPARE_FUNC_LEQUAL: op = "<="; break; + case RC_COMPARE_FUNC_GREATER: op = ">"; break; + case RC_COMPARE_FUNC_NOTEQUAL: op = "!="; break; + case RC_COMPARE_FUNC_GEQUAL: op = ">="; break; + default: op = "???"; break; + } + fprintf(f, "%s %s %s", lhs, op, rhs); + } +} + +static void rc_print_register(FILE * f, rc_register_file file, int index, unsigned int reladdr) +{ + if (file == RC_FILE_NONE) { + fprintf(f, "none"); + } else if (file == RC_FILE_SPECIAL) { + switch(index) { + case RC_SPECIAL_ALU_RESULT: fprintf(f, "aluresult"); break; + default: fprintf(f, "special[%i]", index); break; + } + } else { + const char * filename; + switch(file) { + case RC_FILE_TEMPORARY: filename = "temp"; break; + case RC_FILE_INPUT: filename = "input"; break; + case RC_FILE_OUTPUT: filename = "output"; break; + case RC_FILE_ADDRESS: filename = "addr"; break; + case RC_FILE_CONSTANT: filename = "const"; break; + default: filename = "BAD FILE"; break; + } + fprintf(f, "%s[%i%s]", filename, index, reladdr ? " + addr[0]" : ""); + } +} + +static void rc_print_mask(FILE * f, unsigned int mask) +{ + if (mask & RC_MASK_X) fprintf(f, "x"); + if (mask & RC_MASK_Y) fprintf(f, "y"); + if (mask & RC_MASK_Z) fprintf(f, "z"); + if (mask & RC_MASK_W) fprintf(f, "w"); +} + +static void rc_print_dst_register(FILE * f, struct rc_dst_register dst) +{ + rc_print_register(f, dst.File, dst.Index, 0); + if (dst.WriteMask != RC_MASK_XYZW) { + fprintf(f, "."); + rc_print_mask(f, dst.WriteMask); + } +} + +static char rc_swizzle_char(unsigned int swz) +{ + switch(swz) { + case RC_SWIZZLE_X: return 'x'; + case RC_SWIZZLE_Y: return 'y'; + case RC_SWIZZLE_Z: return 'z'; + case RC_SWIZZLE_W: return 'w'; + case RC_SWIZZLE_ZERO: return '0'; + case RC_SWIZZLE_ONE: return '1'; + case RC_SWIZZLE_HALF: return 'H'; + case RC_SWIZZLE_UNUSED: return '_'; + } + fprintf(stderr, "bad swz: %u\n", swz); + return '?'; +} + +static void rc_print_swizzle(FILE * f, unsigned int swizzle, unsigned int negate) +{ + unsigned int comp; + for(comp = 0; comp < 4; ++comp) { + rc_swizzle swz = GET_SWZ(swizzle, comp); + if (GET_BIT(negate, comp)) + fprintf(f, "-"); + fprintf(f, "%c", rc_swizzle_char(swz)); + } +} + +static void rc_print_presub_instruction(FILE * f, + struct rc_presub_instruction inst) +{ + fprintf(f,"("); + switch(inst.Opcode){ + case RC_PRESUB_BIAS: + fprintf(f, "1 - 2 * "); + rc_print_register(f, inst.SrcReg[0].File, + inst.SrcReg[0].Index,inst.SrcReg[0].RelAddr); + break; + case RC_PRESUB_SUB: + rc_print_register(f, inst.SrcReg[1].File, + inst.SrcReg[1].Index,inst.SrcReg[1].RelAddr); + fprintf(f, " - "); + rc_print_register(f, inst.SrcReg[0].File, + inst.SrcReg[0].Index,inst.SrcReg[0].RelAddr); + break; + case RC_PRESUB_ADD: + rc_print_register(f, inst.SrcReg[1].File, + inst.SrcReg[1].Index,inst.SrcReg[1].RelAddr); + fprintf(f, " + "); + rc_print_register(f, inst.SrcReg[0].File, + inst.SrcReg[0].Index,inst.SrcReg[0].RelAddr); + break; + case RC_PRESUB_INV: + fprintf(f, "1 - "); + rc_print_register(f, inst.SrcReg[0].File, + inst.SrcReg[0].Index,inst.SrcReg[0].RelAddr); + break; + default: + break; + } + fprintf(f, ")"); +} + +static void rc_print_src_register(FILE * f, struct rc_instruction * inst, + struct rc_src_register src) +{ + int trivial_negate = (src.Negate == RC_MASK_NONE || src.Negate == RC_MASK_XYZW); + + if (src.Negate == RC_MASK_XYZW) + fprintf(f, "-"); + if (src.Abs) + fprintf(f, "|"); + + if(src.File == RC_FILE_PRESUB) + rc_print_presub_instruction(f, inst->U.I.PreSub); + else + rc_print_register(f, src.File, src.Index, src.RelAddr); + + if (src.Abs && !trivial_negate) + fprintf(f, "|"); + + if (src.Swizzle != RC_SWIZZLE_XYZW || !trivial_negate) { + fprintf(f, "."); + rc_print_swizzle(f, src.Swizzle, trivial_negate ? 0 : src.Negate); + } + + if (src.Abs && trivial_negate) + fprintf(f, "|"); +} + +static unsigned update_branch_depth(rc_opcode opcode, unsigned *branch_depth) +{ + switch (opcode) { + case RC_OPCODE_IF: + case RC_OPCODE_BGNLOOP: + return (*branch_depth)++ * 2; + + case RC_OPCODE_ENDIF: + case RC_OPCODE_ENDLOOP: + assert(*branch_depth > 0); + return --(*branch_depth) * 2; + + case RC_OPCODE_ELSE: + assert(*branch_depth > 0); + return (*branch_depth - 1) * 2; + + default: + return *branch_depth * 2; + } +} + +static void rc_print_normal_instruction(FILE * f, struct rc_instruction * inst, unsigned *branch_depth) +{ + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode); + unsigned int reg; + unsigned spaces = update_branch_depth(inst->U.I.Opcode, branch_depth); + + for (unsigned i = 0; i < spaces; i++) + fprintf(f, " "); + + fprintf(f, "%s", opcode->Name); + + switch(inst->U.I.SaturateMode) { + case RC_SATURATE_NONE: break; + case RC_SATURATE_ZERO_ONE: fprintf(f, "_SAT"); break; + case RC_SATURATE_MINUS_PLUS_ONE: fprintf(f, "_SAT2"); break; + default: fprintf(f, "_BAD_SAT"); break; + } + + if (opcode->HasDstReg) { + fprintf(f, " "); + rc_print_dst_register(f, inst->U.I.DstReg); + if (opcode->NumSrcRegs) + fprintf(f, ","); + } + + for(reg = 0; reg < opcode->NumSrcRegs; ++reg) { + if (reg > 0) + fprintf(f, ","); + fprintf(f, " "); + rc_print_src_register(f, inst, inst->U.I.SrcReg[reg]); + } + + if (opcode->HasTexture) { + fprintf(f, ", %s%s[%u]", + textarget_to_string(inst->U.I.TexSrcTarget), + inst->U.I.TexShadow ? "SHADOW" : "", + inst->U.I.TexSrcUnit); + } + + fprintf(f, ";"); + + if (inst->U.I.WriteALUResult) { + fprintf(f, " [aluresult = ("); + rc_print_comparefunc(f, + (inst->U.I.WriteALUResult == RC_ALURESULT_X) ? "x" : "w", + inst->U.I.ALUResultCompare, "0"); + fprintf(f, ")]"); + } + + fprintf(f, "\n"); +} + +static void rc_print_pair_instruction(FILE * f, struct rc_instruction * fullinst, unsigned *branch_depth) +{ + struct rc_pair_instruction * inst = &fullinst->U.P; + int printedsrc = 0; + unsigned spaces = update_branch_depth(inst->RGB.Opcode != RC_OPCODE_NOP ? + inst->RGB.Opcode : inst->Alpha.Opcode, branch_depth); + + for (unsigned i = 0; i < spaces; i++) + fprintf(f, " "); + + for(unsigned int src = 0; src < 3; ++src) { + if (inst->RGB.Src[src].Used) { + if (printedsrc) + fprintf(f, ", "); + fprintf(f, "src%i.xyz = ", src); + rc_print_register(f, inst->RGB.Src[src].File, inst->RGB.Src[src].Index, 0); + printedsrc = 1; + } + if (inst->Alpha.Src[src].Used) { + if (printedsrc) + fprintf(f, ", "); + fprintf(f, "src%i.w = ", src); + rc_print_register(f, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, 0); + printedsrc = 1; + } + } + if(inst->RGB.Src[RC_PAIR_PRESUB_SRC].Used) { + fprintf(f, ", srcp.xyz = %s", + presubtract_op_to_string( + inst->RGB.Src[RC_PAIR_PRESUB_SRC].Index)); + } + if(inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) { + fprintf(f, ", srcp.w = %s", + presubtract_op_to_string( + inst->Alpha.Src[RC_PAIR_PRESUB_SRC].Index)); + } + fprintf(f, "\n"); + + if (inst->RGB.Opcode != RC_OPCODE_NOP) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->RGB.Opcode); + + for (unsigned i = 0; i < spaces; i++) + fprintf(f, " "); + + fprintf(f, " %s%s", opcode->Name, inst->RGB.Saturate ? "_SAT" : ""); + if (inst->RGB.WriteMask) + fprintf(f, " temp[%i].%s%s%s", inst->RGB.DestIndex, + (inst->RGB.WriteMask & 1) ? "x" : "", + (inst->RGB.WriteMask & 2) ? "y" : "", + (inst->RGB.WriteMask & 4) ? "z" : ""); + if (inst->RGB.OutputWriteMask) + fprintf(f, " color[%i].%s%s%s", inst->RGB.Target, + (inst->RGB.OutputWriteMask & 1) ? "x" : "", + (inst->RGB.OutputWriteMask & 2) ? "y" : "", + (inst->RGB.OutputWriteMask & 4) ? "z" : ""); + if (inst->WriteALUResult == RC_ALURESULT_X) + fprintf(f, " aluresult"); + + for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) { + const char* abs = inst->RGB.Arg[arg].Abs ? "|" : ""; + const char* neg = inst->RGB.Arg[arg].Negate ? "-" : ""; + fprintf(f, ", %s%ssrc", neg, abs); + if(inst->RGB.Arg[arg].Source == RC_PAIR_PRESUB_SRC) + fprintf(f,"p"); + else + fprintf(f,"%d", inst->RGB.Arg[arg].Source); + fprintf(f,".%c%c%c%s", + rc_swizzle_char(GET_SWZ(inst->RGB.Arg[arg].Swizzle, 0)), + rc_swizzle_char(GET_SWZ(inst->RGB.Arg[arg].Swizzle, 1)), + rc_swizzle_char(GET_SWZ(inst->RGB.Arg[arg].Swizzle, 2)), + abs); + } + fprintf(f, "\n"); + } + + if (inst->Alpha.Opcode != RC_OPCODE_NOP) { + const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Alpha.Opcode); + + for (unsigned i = 0; i < spaces; i++) + fprintf(f, " "); + + fprintf(f, " %s%s", opcode->Name, inst->Alpha.Saturate ? "_SAT" : ""); + if (inst->Alpha.WriteMask) + fprintf(f, " temp[%i].w", inst->Alpha.DestIndex); + if (inst->Alpha.OutputWriteMask) + fprintf(f, " color[%i].w", inst->Alpha.Target); + if (inst->Alpha.DepthWriteMask) + fprintf(f, " depth.w"); + if (inst->WriteALUResult == RC_ALURESULT_W) + fprintf(f, " aluresult"); + + for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) { + const char* abs = inst->Alpha.Arg[arg].Abs ? "|" : ""; + const char* neg = inst->Alpha.Arg[arg].Negate ? "-" : ""; + fprintf(f, ", %s%ssrc", neg, abs); + if(inst->Alpha.Arg[arg].Source == RC_PAIR_PRESUB_SRC) + fprintf(f,"p"); + else + fprintf(f,"%d", inst->Alpha.Arg[arg].Source); + fprintf(f,".%c%s", + rc_swizzle_char(GET_SWZ(inst->Alpha.Arg[arg].Swizzle, 0)), abs); + } + fprintf(f, "\n"); + } + + if (inst->WriteALUResult) { + for (unsigned i = 0; i < spaces; i++) + fprintf(f, " "); + + fprintf(f, " [aluresult = ("); + rc_print_comparefunc(f, "result", inst->ALUResultCompare, "0"); + fprintf(f, ")]\n"); + } +} + +/** + * Print program to stderr, default options. + */ +void rc_print_program(const struct rc_program *prog) +{ + unsigned int linenum = 0; + unsigned branch_depth = 0; + struct rc_instruction *inst; + + fprintf(stderr, "# Radeon Compiler Program\n"); + + for(inst = prog->Instructions.Next; inst != &prog->Instructions; inst = inst->Next) { + fprintf(stderr, "%3d: ", linenum); + + if (inst->Type == RC_INSTRUCTION_PAIR) + rc_print_pair_instruction(stderr, inst, &branch_depth); + else + rc_print_normal_instruction(stderr, inst, &branch_depth); + + linenum++; + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_program_tex.c b/src/gallium/drivers/r300/compiler/radeon_program_tex.c new file mode 100644 index 00000000000..8d16b2cf9ec --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_tex.c @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2010 Corbin Simpson + * Copyright (C) 2010 Marek Olšák <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_program_tex.h" + +#include "radeon_compiler_util.h" + +/* Series of transformations to be done on textures. */ + +static struct rc_src_register shadow_fail_value(struct r300_fragment_program_compiler *compiler, + int tmu) +{ + struct rc_src_register reg = { 0, }; + + if (compiler->enable_shadow_ambient) { + reg.File = RC_FILE_CONSTANT; + reg.Index = rc_constants_add_state(&compiler->Base.Program.Constants, + RC_STATE_SHADOW_AMBIENT, tmu); + reg.Swizzle = RC_SWIZZLE_WWWW; + } else { + reg.File = RC_FILE_NONE; + reg.Swizzle = RC_SWIZZLE_0000; + } + + reg.Swizzle = combine_swizzles(reg.Swizzle, + compiler->state.unit[tmu].texture_swizzle); + return reg; +} + +static struct rc_src_register shadow_pass_value(struct r300_fragment_program_compiler *compiler, + int tmu) +{ + struct rc_src_register reg = { 0, }; + + reg.File = RC_FILE_NONE; + reg.Swizzle = combine_swizzles(RC_SWIZZLE_1111, + compiler->state.unit[tmu].texture_swizzle); + return reg; +} + +static void scale_texcoords(struct r300_fragment_program_compiler *compiler, + struct rc_instruction *inst, + unsigned state_constant) +{ + struct rc_instruction *inst_mov; + + unsigned temp = rc_find_free_temporary(&compiler->Base); + + inst_mov = rc_insert_new_instruction(&compiler->Base, inst->Prev); + + inst_mov->U.I.Opcode = RC_OPCODE_MUL; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = temp; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_mov->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + inst_mov->U.I.SrcReg[1].Index = + rc_constants_add_state(&compiler->Base.Program.Constants, + state_constant, inst->U.I.TexSrcUnit); + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = temp; +} + +static void projective_divide(struct r300_fragment_program_compiler *compiler, + struct rc_instruction *inst) +{ + struct rc_instruction *inst_mul, *inst_rcp; + + unsigned temp = rc_find_free_temporary(&compiler->Base); + + inst_rcp = rc_insert_new_instruction(&compiler->Base, inst->Prev); + inst_rcp->U.I.Opcode = RC_OPCODE_RCP; + inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rcp->U.I.DstReg.Index = temp; + inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W; + inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + /* Because the input can be arbitrarily swizzled, + * read the component mapped to W. */ + inst_rcp->U.I.SrcReg[0].Swizzle = + RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3)); + + inst_mul = rc_insert_new_instruction(&compiler->Base, inst->Prev); + inst_mul->U.I.Opcode = RC_OPCODE_MUL; + inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mul->U.I.DstReg.Index = temp; + inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_mul->U.I.SrcReg[1].Index = temp; + inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW; + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.Opcode = RC_OPCODE_TEX; + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = temp; +} + +/** + * Transform TEX, TXP, TXB, and KIL instructions in the following ways: + * - implement texture compare (shadow extensions) + * - extract non-native source / destination operands + * - premultiply texture coordinates for RECT + * - extract operand swizzles + * - introduce a temporary register when write masks are needed + */ +int radeonTransformTEX( + struct radeon_compiler * c, + struct rc_instruction * inst, + void* data) +{ + struct r300_fragment_program_compiler *compiler = + (struct r300_fragment_program_compiler*)data; + rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode; + int is_rect = inst->U.I.TexSrcTarget == RC_TEXTURE_RECT || + compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords; + + if (inst->U.I.Opcode != RC_OPCODE_TEX && + inst->U.I.Opcode != RC_OPCODE_TXB && + inst->U.I.Opcode != RC_OPCODE_TXP && + inst->U.I.Opcode != RC_OPCODE_TXD && + inst->U.I.Opcode != RC_OPCODE_TXL && + inst->U.I.Opcode != RC_OPCODE_KIL) + return 0; + + /* ARB_shadow & EXT_shadow_funcs */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + ((c->Program.ShadowSamplers & (1 << inst->U.I.TexSrcUnit)) || + (compiler->state.unit[inst->U.I.TexSrcUnit].compare_mode_enabled))) { + rc_compare_func comparefunc = compiler->state.unit[inst->U.I.TexSrcUnit].texture_compare_func; + + if (comparefunc == RC_COMPARE_FUNC_NEVER || comparefunc == RC_COMPARE_FUNC_ALWAYS) { + inst->U.I.Opcode = RC_OPCODE_MOV; + + if (comparefunc == RC_COMPARE_FUNC_ALWAYS) { + inst->U.I.SrcReg[0] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit); + } else { + inst->U.I.SrcReg[0] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit); + } + + return 1; + } else { + struct rc_instruction * inst_rcp = NULL; + struct rc_instruction *inst_mul, *inst_add, *inst_cmp; + unsigned tmp_texsample; + unsigned tmp_sum; + int pass, fail; + + /* Save the output register. */ + struct rc_dst_register output_reg = inst->U.I.DstReg; + unsigned saturate_mode = inst->U.I.SaturateMode; + + /* Redirect TEX to a new temp. */ + tmp_texsample = rc_find_free_temporary(c); + inst->U.I.SaturateMode = 0; + inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst->U.I.DstReg.Index = tmp_texsample; + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + + tmp_sum = rc_find_free_temporary(c); + + if (inst->U.I.Opcode == RC_OPCODE_TXP) { + /* Compute 1/W. */ + inst_rcp = rc_insert_new_instruction(c, inst); + inst_rcp->U.I.Opcode = RC_OPCODE_RCP; + inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_rcp->U.I.DstReg.Index = tmp_sum; + inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W; + inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_rcp->U.I.SrcReg[0].Swizzle = + RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3)); + } + + /* Divide Z by W (if it's TXP) and saturate. */ + inst_mul = rc_insert_new_instruction(c, inst_rcp ? inst_rcp : inst); + inst_mul->U.I.Opcode = inst->U.I.Opcode == RC_OPCODE_TXP ? RC_OPCODE_MUL : RC_OPCODE_MOV; + inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mul->U.I.DstReg.Index = tmp_sum; + inst_mul->U.I.DstReg.WriteMask = RC_MASK_W; + inst_mul->U.I.SaturateMode = RC_SATURATE_ZERO_ONE; + inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_mul->U.I.SrcReg[0].Swizzle = + RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 2)); + if (inst->U.I.Opcode == RC_OPCODE_TXP) { + inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_mul->U.I.SrcReg[1].Index = tmp_sum; + inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW; + } + + /* Add the depth texture value. */ + inst_add = rc_insert_new_instruction(c, inst_mul); + inst_add->U.I.Opcode = RC_OPCODE_ADD; + inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_add->U.I.DstReg.Index = tmp_sum; + inst_add->U.I.DstReg.WriteMask = RC_MASK_W; + inst_add->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_add->U.I.SrcReg[0].Index = tmp_sum; + inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW; + inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_add->U.I.SrcReg[1].Index = tmp_texsample; + inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX; + + /* Note that SrcReg[0] is r, SrcReg[1] is tex and: + * LESS: r < tex <=> -tex+r < 0 + * GEQUAL: r >= tex <=> not (-tex+r < 0) + * GREATER: r > tex <=> tex-r < 0 + * LEQUAL: r <= tex <=> not ( tex-r < 0) + * EQUAL: GEQUAL + * NOTEQUAL:LESS + */ + + /* This negates either r or tex: */ + if (comparefunc == RC_COMPARE_FUNC_LESS || comparefunc == RC_COMPARE_FUNC_GEQUAL || + comparefunc == RC_COMPARE_FUNC_EQUAL || comparefunc == RC_COMPARE_FUNC_NOTEQUAL) + inst_add->U.I.SrcReg[1].Negate = inst_add->U.I.SrcReg[1].Negate ^ RC_MASK_XYZW; + else + inst_add->U.I.SrcReg[0].Negate = inst_add->U.I.SrcReg[0].Negate ^ RC_MASK_XYZW; + + /* This negates the whole expresion: */ + if (comparefunc == RC_COMPARE_FUNC_LESS || comparefunc == RC_COMPARE_FUNC_GREATER || + comparefunc == RC_COMPARE_FUNC_NOTEQUAL) { + pass = 1; + fail = 2; + } else { + pass = 2; + fail = 1; + } + + inst_cmp = rc_insert_new_instruction(c, inst_add); + inst_cmp->U.I.Opcode = RC_OPCODE_CMP; + inst_cmp->U.I.SaturateMode = saturate_mode; + inst_cmp->U.I.DstReg = output_reg; + inst_cmp->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_cmp->U.I.SrcReg[0].Index = tmp_sum; + inst_cmp->U.I.SrcReg[0].Swizzle = + combine_swizzles(RC_SWIZZLE_WWWW, + compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle); + inst_cmp->U.I.SrcReg[pass] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit); + inst_cmp->U.I.SrcReg[fail] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit); + + assert(tmp_texsample != tmp_sum); + } + } + + /* R300 cannot sample from rectangles and the wrap mode fallback needs + * normalized coordinates anyway. */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + is_rect && (!c->is_r500 || wrapmode != RC_WRAP_NONE)) { + scale_texcoords(compiler, inst, RC_STATE_R300_TEXRECT_FACTOR); + inst->U.I.TexSrcTarget = RC_TEXTURE_2D; + } + + /* Divide by W if needed. */ + if (inst->U.I.Opcode == RC_OPCODE_TXP && + (wrapmode == RC_WRAP_REPEAT || wrapmode == RC_WRAP_MIRRORED_REPEAT || + compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch)) { + projective_divide(compiler, inst); + } + + /* Texture wrap modes don't work on NPOT textures. + * + * Non-wrapped/clamped texcoords with NPOT are free in HW. Repeat and + * mirroring are not. If we need to repeat, we do: + * + * MUL temp, texcoord, <scaling factor constant> + * FRC temp, temp ; Discard integer portion of coords + * + * This gives us coords in [0, 1]. + * + * Mirroring is trickier. We're going to start out like repeat: + * + * MUL temp, texcoord, <scaling factor constant> ; De-mirror across axes + * MUL temp, temp, 0.5 ; Pattern repeats in [0, 2] + * ; so scale to [0, 1] + * FRC temp, temp ; Make the pattern repeat + * MAD temp, temp, 2, -1 ; Move the pattern to [-1, 1] + * ADD temp, 1, -abs(temp) ; Now comes a neat trick: use abs to mirror the pattern. + * ; The pattern is backwards, so reverse it (1-x). + * + * This gives us coords in [0, 1]. + * + * ~ C & M. ;) + */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + wrapmode != RC_WRAP_NONE) { + struct rc_instruction *inst_mov; + unsigned temp = rc_find_free_temporary(c); + + if (wrapmode == RC_WRAP_REPEAT) { + /* Both instructions will be paired up. */ + struct rc_instruction *inst_frc = rc_insert_new_instruction(c, inst->Prev); + + inst_frc->U.I.Opcode = RC_OPCODE_FRC; + inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_frc->U.I.DstReg.Index = temp; + inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_frc->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + } else if (wrapmode == RC_WRAP_MIRRORED_REPEAT) { + /* + * Function: + * f(v) = 1 - abs(frac(v * 0.5) * 2 - 1) + * + * Code: + * MUL temp, src0, 0.5 + * FRC temp, temp + * MAD temp, temp, 2, -1 + * ADD temp, 1, -abs(temp) + */ + + struct rc_instruction *inst_mul, *inst_frc, *inst_mad, *inst_add; + unsigned two, two_swizzle; + + inst_mul = rc_insert_new_instruction(c, inst->Prev); + + inst_mul->U.I.Opcode = RC_OPCODE_MUL; + inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mul->U.I.DstReg.Index = temp; + inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_HHHH; + + inst_frc = rc_insert_new_instruction(c, inst->Prev); + + inst_frc->U.I.Opcode = RC_OPCODE_FRC; + inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_frc->U.I.DstReg.Index = temp; + inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_frc->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_frc->U.I.SrcReg[0].Index = temp; + inst_frc->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0; + + two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2, &two_swizzle); + inst_mad = rc_insert_new_instruction(c, inst->Prev); + + inst_mad->U.I.Opcode = RC_OPCODE_MAD; + inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mad->U.I.DstReg.Index = temp; + inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_mad->U.I.SrcReg[0].Index = temp; + inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0; + inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT; + inst_mad->U.I.SrcReg[1].Index = two; + inst_mad->U.I.SrcReg[1].Swizzle = two_swizzle; + inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_1111; + inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZ; + + inst_add = rc_insert_new_instruction(c, inst->Prev); + + inst_add->U.I.Opcode = RC_OPCODE_ADD; + inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_add->U.I.DstReg.Index = temp; + inst_add->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111; + inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_add->U.I.SrcReg[1].Index = temp; + inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0; + inst_add->U.I.SrcReg[1].Abs = 1; + inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZ; + } else if (wrapmode == RC_WRAP_MIRRORED_CLAMP) { + /* + * Mirrored clamp modes are bloody simple, we just use abs + * to mirror [0, 1] into [-1, 0]. This works for + * all modes i.e. CLAMP, CLAMP_TO_EDGE, and CLAMP_TO_BORDER. + */ + struct rc_instruction *inst_mov; + + inst_mov = rc_insert_new_instruction(c, inst->Prev); + + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = temp; + inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + inst_mov->U.I.SrcReg[0].Abs = 1; + } + + /* Preserve W for TXP/TXB. */ + inst_mov = rc_insert_new_instruction(c, inst->Prev); + + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = temp; + inst_mov->U.I.DstReg.WriteMask = RC_MASK_W; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = temp; + } + + /* NPOT -> POT conversion for 3D textures. */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch) { + struct rc_instruction *inst_mov; + unsigned temp = rc_find_free_temporary(c); + + /* Saturate XYZ. */ + inst_mov = rc_insert_new_instruction(c, inst->Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.SaturateMode = RC_SATURATE_ZERO_ONE; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = temp; + inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + /* Copy W. */ + inst_mov = rc_insert_new_instruction(c, inst->Prev); + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = temp; + inst_mov->U.I.DstReg.WriteMask = RC_MASK_W; + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = temp; + + scale_texcoords(compiler, inst, RC_STATE_R300_TEXSCALE_FACTOR); + } + + /* Convert SNORM-encoded ATI1N sampled as UNORM to SNORM. + * Formula: dst = tex > 0.5 ? tex*2-2 : tex*2 + */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + compiler->state.unit[inst->U.I.TexSrcUnit].convert_unorm_to_snorm) { + unsigned two, two_swizzle; + struct rc_instruction *inst_mul, *inst_mad, *inst_cnd; + + two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2.35, &two_swizzle); + + inst_mul = rc_insert_new_instruction(c, inst); + inst_mul->U.I.Opcode = RC_OPCODE_MUL; + inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mul->U.I.DstReg.Index = rc_find_free_temporary(c); + inst_mul->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_mul->U.I.SrcReg[0].Index = rc_find_free_temporary(c); /* redirected TEX output */ + inst_mul->U.I.SrcReg[1].File = RC_FILE_CONSTANT; /* 2 */ + inst_mul->U.I.SrcReg[1].Index = two; + inst_mul->U.I.SrcReg[1].Swizzle = two_swizzle; + + inst_mad = rc_insert_new_instruction(c, inst_mul); + inst_mad->U.I.Opcode = RC_OPCODE_MAD; + inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mad->U.I.DstReg.Index = rc_find_free_temporary(c); + inst_mad->U.I.SrcReg[0] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */ + inst_mad->U.I.SrcReg[1] = inst_mul->U.I.SrcReg[1]; /* 2 */ + inst_mad->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[1]; /* 2 */ + inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZW; + + inst_cnd = rc_insert_new_instruction(c, inst_mad); + inst_cnd->U.I.Opcode = RC_OPCODE_CND; + inst_cnd->U.I.SaturateMode = inst->U.I.SaturateMode; + inst_cnd->U.I.DstReg = inst->U.I.DstReg; + inst_cnd->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_cnd->U.I.SrcReg[0].Index = inst_mad->U.I.DstReg.Index; + inst_cnd->U.I.SrcReg[0].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle; + inst_cnd->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; + inst_cnd->U.I.SrcReg[1].Index = inst_mul->U.I.DstReg.Index; + inst_cnd->U.I.SrcReg[1].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle; + inst_cnd->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */ + + inst->U.I.SaturateMode = 0; + inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst->U.I.DstReg.Index = inst_mul->U.I.SrcReg[0].Index; + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + } + + /* Cannot write texture to output registers or with saturate (all chips), + * or with masks (non-r500). */ + if (inst->U.I.Opcode != RC_OPCODE_KIL && + (inst->U.I.DstReg.File != RC_FILE_TEMPORARY || + inst->U.I.SaturateMode || + (!c->is_r500 && inst->U.I.DstReg.WriteMask != RC_MASK_XYZW))) { + struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst); + + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.SaturateMode = inst->U.I.SaturateMode; + inst_mov->U.I.DstReg = inst->U.I.DstReg; + inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst_mov->U.I.SrcReg[0].Index = rc_find_free_temporary(c); + + inst->U.I.SaturateMode = 0; + inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst->U.I.DstReg.Index = inst_mov->U.I.SrcReg[0].Index; + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + } + + /* Cannot read texture coordinate from constants file */ + if (inst->U.I.SrcReg[0].File != RC_FILE_TEMPORARY && inst->U.I.SrcReg[0].File != RC_FILE_INPUT) { + struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev); + + inst_mov->U.I.Opcode = RC_OPCODE_MOV; + inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; + inst_mov->U.I.DstReg.Index = rc_find_free_temporary(c); + inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; + + reset_srcreg(&inst->U.I.SrcReg[0]); + inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; + inst->U.I.SrcReg[0].Index = inst_mov->U.I.DstReg.Index; + } + + return 1; +} diff --git a/src/gallium/drivers/r300/compiler/radeon_program_tex.h b/src/gallium/drivers/r300/compiler/radeon_program_tex.h new file mode 100644 index 00000000000..a0105051ac4 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_program_tex.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 Corbin Simpson + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __RADEON_PROGRAM_TEX_H_ +#define __RADEON_PROGRAM_TEX_H_ + +#include "radeon_compiler.h" +#include "radeon_program.h" + +int radeonTransformTEX( + struct radeon_compiler * c, + struct rc_instruction * inst, + void* data); + +#endif /* __RADEON_PROGRAM_TEX_H_ */ diff --git a/src/gallium/drivers/r300/compiler/radeon_remove_constants.c b/src/gallium/drivers/r300/compiler/radeon_remove_constants.c new file mode 100644 index 00000000000..7d76585a593 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_remove_constants.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010 Marek Olšák <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_remove_constants.h" +#include "radeon_dataflow.h" + +struct mark_used_data { + unsigned char * const_used; + unsigned * has_rel_addr; +}; + +static void remap_regs(void * userdata, struct rc_instruction * inst, + rc_register_file * pfile, unsigned int * pindex) +{ + unsigned *inv_remap_table = userdata; + + if (*pfile == RC_FILE_CONSTANT) { + *pindex = inv_remap_table[*pindex]; + } +} + +static void mark_used(void * userdata, struct rc_instruction * inst, + struct rc_src_register * src) +{ + struct mark_used_data * d = userdata; + + if (src->File == RC_FILE_CONSTANT) { + if (src->RelAddr) { + *d->has_rel_addr = 1; + } else { + d->const_used[src->Index] = 1; + } + } +} + +void rc_remove_unused_constants(struct radeon_compiler *c, void *user) +{ + unsigned **out_remap_table = (unsigned**)user; + unsigned char *const_used; + unsigned *remap_table; + unsigned *inv_remap_table; + unsigned has_rel_addr = 0; + unsigned is_identity = 1; + unsigned are_externals_remapped = 0; + struct rc_constant *constants = c->Program.Constants.Constants; + struct mark_used_data d; + unsigned new_count; + + if (!c->Program.Constants.Count) { + *out_remap_table = NULL; + return; + } + + const_used = malloc(c->Program.Constants.Count); + memset(const_used, 0, c->Program.Constants.Count); + + d.const_used = const_used; + d.has_rel_addr = &has_rel_addr; + + /* Pass 1: Mark used constants. */ + for (struct rc_instruction *inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + rc_for_all_reads_src(inst, mark_used, &d); + } + + /* Pass 2: If there is relative addressing or dead constant elimination + * is disabled, mark all externals as used. */ + if (has_rel_addr || !c->remove_unused_constants) { + for (unsigned i = 0; i < c->Program.Constants.Count; i++) + if (constants[i].Type == RC_CONSTANT_EXTERNAL) + const_used[i] = 1; + } + + /* Pass 3: Make the remapping table and remap constants. + * This pass removes unused constants simply by overwriting them by other constants. */ + remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); + inv_remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); + new_count = 0; + + for (unsigned i = 0; i < c->Program.Constants.Count; i++) { + if (const_used[i]) { + remap_table[new_count] = i; + inv_remap_table[i] = new_count; + + if (i != new_count) { + if (constants[i].Type == RC_CONSTANT_EXTERNAL) + are_externals_remapped = 1; + + constants[new_count] = constants[i]; + is_identity = 0; + } + new_count++; + } + } + + /* is_identity ==> new_count == old_count + * !is_identity ==> new_count < old_count */ + assert( is_identity || new_count < c->Program.Constants.Count); + assert(!((has_rel_addr || !c->remove_unused_constants) && are_externals_remapped)); + + /* Pass 4: Redirect reads of all constants to their new locations. */ + if (!is_identity) { + for (struct rc_instruction *inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; inst = inst->Next) { + rc_remap_registers(inst, remap_regs, inv_remap_table); + } + } + + /* Set the new constant count. Note that new_count may be less than + * Count even though the remapping function is identity. In that case, + * the constants have been removed at the end of the array. */ + c->Program.Constants.Count = new_count; + + if (are_externals_remapped) { + *out_remap_table = remap_table; + } else { + *out_remap_table = NULL; + free(remap_table); + } + + free(const_used); + free(inv_remap_table); + + if (c->Debug & RC_DBG_LOG) + rc_constants_print(&c->Program.Constants); +} diff --git a/src/gallium/drivers/r300/compiler/radeon_remove_constants.h b/src/gallium/drivers/r300/compiler/radeon_remove_constants.h new file mode 100644 index 00000000000..f29113b922b --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_remove_constants.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 Marek Olšák <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_REMOVE_CONSTANTS_H +#define RADEON_REMOVE_CONSTANTS_H + +#include "radeon_compiler.h" + +void rc_remove_unused_constants(struct radeon_compiler *c, void *user); + +#endif diff --git a/src/gallium/drivers/r300/compiler/radeon_rename_regs.c b/src/gallium/drivers/r300/compiler/radeon_rename_regs.c new file mode 100644 index 00000000000..cafa0579734 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_rename_regs.c @@ -0,0 +1,92 @@ +/* + * Copyright 2010 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/** + * \file + */ + +#include "radeon_rename_regs.h" + +#include "radeon_compiler.h" +#include "radeon_dataflow.h" +#include "radeon_program.h" + +/** + * This function renames registers in an attempt to get the code close to + * SSA form. After this function has completed, most of the register are only + * written to one time, with a few exceptions. + * + * This function assumes all the instructions are still of type + * RC_INSTRUCTION_NORMAL. + */ +void rc_rename_regs(struct radeon_compiler *c, void *user) +{ + unsigned int i, used_length; + int new_index; + struct rc_instruction * inst; + struct rc_reader_data reader_data; + unsigned char * used; + + /* XXX Remove this once the register allocation works with flow control. */ + for(inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next) { + if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP) + return; + } + + used_length = 2 * rc_recompute_ips(c); + used = memory_pool_malloc(&c->Pool, sizeof(unsigned char) * used_length); + memset(used, 0, sizeof(unsigned char) * used_length); + + rc_get_used_temporaries(c, used, used_length); + for(inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next) { + + if (inst->U.I.DstReg.File != RC_FILE_TEMPORARY) + continue; + + reader_data.ExitOnAbort = 1; + rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL); + + if (reader_data.Abort || reader_data.ReaderCount == 0) + continue; + + new_index = rc_find_free_temporary_list(c, used, used_length, + RC_MASK_XYZW); + if (new_index < 0) { + rc_error(c, "Ran out of temporary registers\n"); + return; + } + + reader_data.Writer->U.I.DstReg.Index = new_index; + for(i = 0; i < reader_data.ReaderCount; i++) { + reader_data.Readers[i].U.I.Src->Index = new_index; + } + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_rename_regs.h b/src/gallium/drivers/r300/compiler/radeon_rename_regs.h new file mode 100644 index 00000000000..3baf29f6120 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_rename_regs.h @@ -0,0 +1,9 @@ + +#ifndef RADEON_RENAME_REGS_H +#define RADEON_RENAME_REGS_H + +struct radeon_compiler; + +void rc_rename_regs(struct radeon_compiler *c, void *user); + +#endif /* RADEON_RENAME_REGS_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_swizzle.h b/src/gallium/drivers/r300/compiler/radeon_swizzle.h new file mode 100644 index 00000000000..c81d5f7a5e9 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_swizzle.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_SWIZZLE_H +#define RADEON_SWIZZLE_H + +#include "radeon_program.h" + +struct rc_swizzle_split { + unsigned char NumPhases; + unsigned char Phase[4]; +}; + +/** + * Describe the swizzling capability of target hardware. + */ +struct rc_swizzle_caps { + /** + * Check whether the given swizzle, absolute and negate combination + * can be implemented natively by the hardware for this opcode. + * + * \return 1 if the swizzle is native for the given opcode + */ + int (*IsNative)(rc_opcode opcode, struct rc_src_register reg); + + /** + * Determine how to split access to the masked channels of the + * given source register to obtain ALU-native swizzles. + */ + void (*Split)(struct rc_src_register reg, unsigned int mask, struct rc_swizzle_split * split); +}; + +#endif /* RADEON_SWIZZLE_H */ diff --git a/src/gallium/drivers/r300/compiler/radeon_variable.c b/src/gallium/drivers/r300/compiler/radeon_variable.c new file mode 100644 index 00000000000..938fb8421f2 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_variable.c @@ -0,0 +1,517 @@ +/* + * Copyright 2011 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_variable.h" + +#include "memory_pool.h" +#include "radeon_compiler_util.h" +#include "radeon_dataflow.h" +#include "radeon_list.h" +#include "radeon_opcodes.h" +#include "radeon_program.h" + +/** + * Rewrite the index and writemask for the destination register of var + * and its friends to new_index and new_writemask. This function also takes + * care of rewriting the swizzles for the sources of var. + */ +void rc_variable_change_dst( + struct rc_variable * var, + unsigned int new_index, + unsigned int new_writemask) +{ + struct rc_variable * var_ptr; + struct rc_list * readers; + unsigned int old_mask = rc_variable_writemask_sum(var); + unsigned int conversion_swizzle = + rc_make_conversion_swizzle(old_mask, new_writemask); + + for (var_ptr = var; var_ptr; var_ptr = var_ptr->Friend) { + if (var_ptr->Inst->Type == RC_INSTRUCTION_NORMAL) { + rc_normal_rewrite_writemask(var_ptr->Inst, + conversion_swizzle); + var_ptr->Inst->U.I.DstReg.Index = new_index; + } else { + struct rc_pair_sub_instruction * sub; + if (var_ptr->Dst.WriteMask == RC_MASK_W) { + assert(new_writemask & RC_MASK_W); + sub = &var_ptr->Inst->U.P.Alpha; + } else { + sub = &var_ptr->Inst->U.P.RGB; + rc_pair_rewrite_writemask(sub, + conversion_swizzle); + } + sub->DestIndex = new_index; + } + } + + readers = rc_variable_readers_union(var); + + for ( ; readers; readers = readers->Next) { + struct rc_reader * reader = readers->Item; + if (reader->Inst->Type == RC_INSTRUCTION_NORMAL) { + reader->U.I.Src->Index = new_index; + reader->U.I.Src->Swizzle = rc_rewrite_swizzle( + reader->U.I.Src->Swizzle, conversion_swizzle); + } else { + struct rc_pair_instruction * pair_inst = + &reader->Inst->U.P; + unsigned int src_type = rc_source_type_swz( + reader->U.P.Arg->Swizzle); + + int src_index = reader->U.P.Arg->Source; + if (src_index == RC_PAIR_PRESUB_SRC) { + src_index = rc_pair_get_src_index( + pair_inst, reader->U.P.Src); + } + /* Try to delete the old src, it is OK if this fails, + * because rc_pair_alloc_source might be able to + * find a source the ca be reused. + */ + if (rc_pair_remove_src(reader->Inst, src_type, + src_index, old_mask)) { + /* Reuse the source index of the source that + * was just deleted and set its register + * index. We can't use rc_pair_alloc_source + * for this becuase it might return a source + * index that is already being used. */ + if (src_type & RC_SOURCE_RGB) { + pair_inst->RGB.Src[src_index] + .Used = 1; + pair_inst->RGB.Src[src_index] + .Index = new_index; + pair_inst->RGB.Src[src_index] + .File = RC_FILE_TEMPORARY; + } + if (src_type & RC_SOURCE_ALPHA) { + pair_inst->Alpha.Src[src_index] + .Used = 1; + pair_inst->Alpha.Src[src_index] + .Index = new_index; + pair_inst->Alpha.Src[src_index] + .File = RC_FILE_TEMPORARY; + } + } else { + src_index = rc_pair_alloc_source( + &reader->Inst->U.P, + src_type & RC_SOURCE_RGB, + src_type & RC_SOURCE_ALPHA, + RC_FILE_TEMPORARY, + new_index); + if (src_index < 0) { + rc_error(var->C, "Rewrite of inst %u failed " + "Can't allocate source for " + "Inst %u src_type=%x " + "new_index=%u new_mask=%u\n", + var->Inst->IP, reader->Inst->IP, src_type, new_index, new_writemask); + continue; + } + } + reader->U.P.Arg->Swizzle = rc_rewrite_swizzle( + reader->U.P.Arg->Swizzle, conversion_swizzle); + if (reader->U.P.Arg->Source != RC_PAIR_PRESUB_SRC) { + reader->U.P.Arg->Source = src_index; + } + } + } +} + +/** + * Compute the live intervals for var and its friends. + */ +void rc_variable_compute_live_intervals(struct rc_variable * var) +{ + while(var) { + unsigned int i; + unsigned int start = var->Inst->IP; + + for (i = 0; i < var->ReaderCount; i++) { + unsigned int chan; + unsigned int chan_start = start; + unsigned int chan_end = var->Readers[i].Inst->IP; + unsigned int mask = var->Readers[i].WriteMask; + struct rc_instruction * inst; + + /* Extend the live interval of T0 to the start of the + * loop for sequences like: + * BGNLOOP + * read T0 + * ... + * write T0 + * ENDLOOP + */ + if (var->Readers[i].Inst->IP < start) { + struct rc_instruction * bgnloop = + rc_match_endloop(var->Readers[i].Inst); + chan_start = bgnloop->IP; + } + + /* Extend the live interval of T0 to the start of the + * loop in case there is a BRK instruction in the loop + * (we don't actually check for a BRK instruction we + * assume there is one somewhere in the loop, which + * there usually is) for sequences like: + * BGNLOOP + * ... + * conditional BRK + * ... + * write T0 + * ENDLOOP + * read T0 + *************************************************** + * Extend the live interval of T0 to the end of the + * loop for sequences like: + * write T0 + * BGNLOOP + * ... + * read T0 + * ENDLOOP + */ + for (inst = var->Inst; inst != var->Readers[i].Inst; + inst = inst->Next) { + rc_opcode op = rc_get_flow_control_inst(inst); + if (op == RC_OPCODE_ENDLOOP) { + struct rc_instruction * bgnloop = + rc_match_endloop(inst); + if (bgnloop->IP < chan_start) { + chan_start = bgnloop->IP; + } + } else if (op == RC_OPCODE_BGNLOOP) { + struct rc_instruction * endloop = + rc_match_bgnloop(inst); + if (endloop->IP > chan_end) { + chan_end = endloop->IP; + } + } + } + + for (chan = 0; chan < 4; chan++) { + if ((mask >> chan) & 0x1) { + if (!var->Live[chan].Used + || chan_start < var->Live[chan].Start) { + var->Live[chan].Start = + chan_start; + } + if (!var->Live[chan].Used + || chan_end > var->Live[chan].End) { + var->Live[chan].End = chan_end; + } + var->Live[chan].Used = 1; + } + } + } + var = var->Friend; + } +} + +/** + * @return 1 if a and b share a reader + * @return 0 if they do not + */ +static unsigned int readers_intersect( + struct rc_variable * a, + struct rc_variable * b) +{ + unsigned int a_index, b_index; + for (a_index = 0; a_index < a->ReaderCount; a_index++) { + struct rc_reader reader_a = a->Readers[a_index]; + for (b_index = 0; b_index < b->ReaderCount; b_index++) { + struct rc_reader reader_b = b->Readers[b_index]; + if (reader_a.Inst->Type == RC_INSTRUCTION_NORMAL + && reader_b.Inst->Type == RC_INSTRUCTION_NORMAL + && reader_a.U.I.Src == reader_b.U.I.Src) { + + return 1; + } + if (reader_a.Inst->Type == RC_INSTRUCTION_PAIR + && reader_b.Inst->Type == RC_INSTRUCTION_PAIR + && reader_a.U.P.Src == reader_b.U.P.Src) { + + return 1; + } + } + } + return 0; +} + +void rc_variable_add_friend( + struct rc_variable * var, + struct rc_variable * friend) +{ + assert(var->Dst.Index == friend->Dst.Index); + while(var->Friend) { + var = var->Friend; + } + var->Friend = friend; +} + +struct rc_variable * rc_variable( + struct radeon_compiler * c, + unsigned int DstFile, + unsigned int DstIndex, + unsigned int DstWriteMask, + struct rc_reader_data * reader_data) +{ + struct rc_variable * new = + memory_pool_malloc(&c->Pool, sizeof(struct rc_variable)); + memset(new, 0, sizeof(struct rc_variable)); + new->C = c; + new->Dst.File = DstFile; + new->Dst.Index = DstIndex; + new->Dst.WriteMask = DstWriteMask; + if (reader_data) { + new->Inst = reader_data->Writer; + new->ReaderCount = reader_data->ReaderCount; + new->Readers = reader_data->Readers; + } + return new; +} + +static void get_variable_helper( + struct rc_list ** variable_list, + struct rc_variable * variable) +{ + struct rc_list * list_ptr; + for (list_ptr = *variable_list; list_ptr; list_ptr = list_ptr->Next) { + if (readers_intersect(variable, list_ptr->Item)) { + rc_variable_add_friend(list_ptr->Item, variable); + return; + } + } + rc_list_add(variable_list, rc_list(&variable->C->Pool, variable)); +} + +static void get_variable_pair_helper( + struct rc_list ** variable_list, + struct radeon_compiler * c, + struct rc_instruction * inst, + struct rc_pair_sub_instruction * sub_inst) +{ + struct rc_reader_data reader_data; + struct rc_variable * new_var; + rc_register_file file; + unsigned int writemask; + + if (sub_inst->Opcode == RC_OPCODE_NOP) { + return; + } + memset(&reader_data, 0, sizeof(struct rc_reader_data)); + rc_get_readers_sub(c, inst, sub_inst, &reader_data, NULL, NULL, NULL); + + if (reader_data.ReaderCount == 0) { + return; + } + + if (sub_inst->WriteMask) { + file = RC_FILE_TEMPORARY; + writemask = sub_inst->WriteMask; + } else if (sub_inst->OutputWriteMask) { + file = RC_FILE_OUTPUT; + writemask = sub_inst->OutputWriteMask; + } else { + writemask = 0; + file = RC_FILE_NONE; + } + new_var = rc_variable(c, file, sub_inst->DestIndex, writemask, + &reader_data); + get_variable_helper(variable_list, new_var); +} + +/** + * Generate a list of variables used by the shader program. Each instruction + * that writes to a register is considered a variable. The struct rc_variable + * data structure includes a list of readers and is essentially a + * definition-use chain. Any two variables that share a reader are considered + * "friends" and they are linked together via the Friend attribute. + */ +struct rc_list * rc_get_variables(struct radeon_compiler * c) +{ + struct rc_instruction * inst; + struct rc_list * variable_list = NULL; + + for (inst = c->Program.Instructions.Next; + inst != &c->Program.Instructions; + inst = inst->Next) { + struct rc_reader_data reader_data; + struct rc_variable * new_var; + memset(&reader_data, 0, sizeof(reader_data)); + + if (inst->Type == RC_INSTRUCTION_NORMAL) { + rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL); + if (reader_data.ReaderCount == 0) { + continue; + } + new_var = rc_variable(c, inst->U.I.DstReg.File, + inst->U.I.DstReg.Index, + inst->U.I.DstReg.WriteMask, &reader_data); + get_variable_helper(&variable_list, new_var); + } else { + get_variable_pair_helper(&variable_list, c, inst, + &inst->U.P.RGB); + get_variable_pair_helper(&variable_list, c, inst, + &inst->U.P.Alpha); + } + } + + return variable_list; +} + +/** + * @return The bitwise or of the writemasks of a variable and all of its + * friends. + */ +unsigned int rc_variable_writemask_sum(struct rc_variable * var) +{ + unsigned int writemask = 0; + while(var) { + writemask |= var->Dst.WriteMask; + var = var->Friend; + } + return writemask; +} + +/* + * @return A list of readers for a variable and its friends. Readers + * that read from two different variable friends are only included once in + * this list. + */ +struct rc_list * rc_variable_readers_union(struct rc_variable * var) +{ + struct rc_list * list = NULL; + while (var) { + unsigned int i; + for (i = 0; i < var->ReaderCount; i++) { + struct rc_list * temp; + struct rc_reader * a = &var->Readers[i]; + unsigned int match = 0; + for (temp = list; temp; temp = temp->Next) { + struct rc_reader * b = temp->Item; + if (a->Inst->Type != b->Inst->Type) { + continue; + } + if (a->Inst->Type == RC_INSTRUCTION_NORMAL) { + if (a->U.I.Src == b->U.I.Src) { + match = 1; + break; + } + } + if (a->Inst->Type == RC_INSTRUCTION_PAIR) { + if (a->U.P.Arg == b->U.P.Arg + && a->U.P.Src == b->U.P.Src) { + match = 1; + break; + } + } + } + if (match) { + continue; + } + rc_list_add(&list, rc_list(&var->C->Pool, a)); + } + var = var->Friend; + } + return list; +} + +static unsigned int reader_equals_src( + struct rc_reader reader, + unsigned int src_type, + void * src) +{ + if (reader.Inst->Type != src_type) { + return 0; + } + if (src_type == RC_INSTRUCTION_NORMAL) { + return reader.U.I.Src == src; + } else { + return reader.U.P.Src == src; + } +} + +static unsigned int variable_writes_src( + struct rc_variable * var, + unsigned int src_type, + void * src) +{ + unsigned int i; + for (i = 0; i < var->ReaderCount; i++) { + if (reader_equals_src(var->Readers[i], src_type, src)) { + return 1; + } + } + return 0; +} + + +struct rc_list * rc_variable_list_get_writers( + struct rc_list * var_list, + unsigned int src_type, + void * src) +{ + struct rc_list * list_ptr; + struct rc_list * writer_list = NULL; + for (list_ptr = var_list; list_ptr; list_ptr = list_ptr->Next) { + struct rc_variable * var = list_ptr->Item; + if (variable_writes_src(var, src_type, src)) { + struct rc_variable * friend; + rc_list_add(&writer_list, rc_list(&var->C->Pool, var)); + for (friend = var->Friend; friend; + friend = friend->Friend) { + if (variable_writes_src(friend, src_type, src)) { + rc_list_add(&writer_list, + rc_list(&var->C->Pool, friend)); + } + } + /* Once we have indentifed the variable and its + * friends that write this source, we can stop + * stop searching, because we know know of the + * other variables in the list will write this source. + * If they did they would be friends of var. + */ + break; + } + } + return writer_list; +} + +void rc_variable_print(struct rc_variable * var) +{ + unsigned int i; + while (var) { + fprintf(stderr, "%u: TEMP[%u].%u: ", + var->Inst->IP, var->Dst.Index, var->Dst.WriteMask); + for (i = 0; i < 4; i++) { + fprintf(stderr, "chan %u: start=%u end=%u ", i, + var->Live[i].Start, var->Live[i].End); + } + fprintf(stderr, "%u readers\n", var->ReaderCount); + if (var->Friend) { + fprintf(stderr, "Friend: \n\t"); + } + var = var->Friend; + } +} diff --git a/src/gallium/drivers/r300/compiler/radeon_variable.h b/src/gallium/drivers/r300/compiler/radeon_variable.h new file mode 100644 index 00000000000..9427bee18a7 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_variable.h @@ -0,0 +1,89 @@ +/* + * Copyright 2011 Tom Stellard <[email protected]> + * + * 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, 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 (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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef RADEON_VARIABLE_H +#define RADEON_VARIABLE_H + +#include "radeon_compiler.h" + +struct radeon_compiler; +struct rc_list; +struct rc_reader_data; +struct rc_readers; + +struct live_intervals { + int Start; + int End; + int Used; +}; + +struct rc_variable { + struct radeon_compiler * C; + struct rc_dst_register Dst; + + struct rc_instruction * Inst; + unsigned int ReaderCount; + struct rc_reader * Readers; + struct live_intervals Live[4]; + + /* A friend is a variable that shares a reader with another variable. + */ + struct rc_variable * Friend; +}; + +void rc_variable_change_dst( + struct rc_variable * var, + unsigned int new_index, + unsigned int new_writemask); + +void rc_variable_compute_live_intervals(struct rc_variable * var); + +void rc_variable_add_friend( + struct rc_variable * var, + struct rc_variable * friend); + +struct rc_variable * rc_variable( + struct radeon_compiler * c, + unsigned int DstFile, + unsigned int DstIndex, + unsigned int DstWriteMask, + struct rc_reader_data * reader_data); + +struct rc_list * rc_get_variables(struct radeon_compiler * c); + +unsigned int rc_variable_writemask_sum(struct rc_variable * var); + +struct rc_list * rc_variable_readers_union(struct rc_variable * var); + +struct rc_list * rc_variable_list_get_writers( + struct rc_list * var_list, + unsigned int src_type, + void * src); + +void rc_variable_print(struct rc_variable * var); + +#endif /* RADEON_VARIABLE_H */ diff --git a/src/gallium/drivers/r300/compiler/tests/.gitignore b/src/gallium/drivers/r300/compiler/tests/.gitignore new file mode 100644 index 00000000000..85672fed777 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/.gitignore @@ -0,0 +1 @@ +radeon_compiler_util_tests diff --git a/src/gallium/drivers/r300/compiler/tests/Makefile b/src/gallium/drivers/r300/compiler/tests/Makefile new file mode 100644 index 00000000000..6eda34a2c00 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/Makefile @@ -0,0 +1,53 @@ +TOP = ../../../../../.. +include $(TOP)/configs/current + +CFLAGS += -Wall -Werror + +### Basic defines ### +TESTS = radeon_compiler_util_tests + +TEST_SOURCES := $(TESTS:=.c) + +SHARED_SOURCES = \ + rc_test_helpers.c \ + unit_test.c + +C_SOURCES = $(SHARED_SOURCES) $(TEST_SOURCES) + +INCLUDES = \ + -I. \ + -I.. + +COMPILER_LIB = ../../libr300.a + +##### TARGETS ##### + +default: depend run_tests + +depend: $(C_SOURCES) + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(INCLUDES) $^ 2> /dev/null + +# Remove .o and backup files +clean: + rm -f $(TESTS) depend depend.bak + +$(TESTS): $(TESTS:=.o) $(SHARED_SOURCES:.c=.o) $(COMPILER_LIB) + $(APP_CC) -o $@ $^ + +run_tests: $(TESTS) + @echo "RUNNING TESTS:" + @echo "" + $(foreach test, $^, @./$(test)) + +.PHONY: $(COMPILER_LIB) +$(COMPILER_LIB): + $(MAKE) -C ../.. + +##### RULES ##### +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(LIBRARY_DEFINES) $< -o $@ + + +sinclude depend diff --git a/src/gallium/drivers/r300/compiler/tests/radeon_compiler_util_tests.c b/src/gallium/drivers/r300/compiler/tests/radeon_compiler_util_tests.c new file mode 100644 index 00000000000..a2e3f2ab2e5 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/radeon_compiler_util_tests.c @@ -0,0 +1,76 @@ +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "radeon_compiler_util.h" +#include "radeon_program.h" + +#include "rc_test_helpers.h" +#include "unit_test.h" + +static void test_rc_inst_can_use_presub( + struct test_result * result, + int expected, + const char * add_str, + const char * replace_str) +{ + struct rc_instruction add_inst, replace_inst; + int ret; + + test_begin(result); + init_rc_normal_instruction(&add_inst, add_str); + init_rc_normal_instruction(&replace_inst, replace_str); + + ret = rc_inst_can_use_presub(&replace_inst, RC_PRESUB_ADD, 0, + &replace_inst.U.I.SrcReg[0], + &add_inst.U.I.SrcReg[0], &add_inst.U.I.SrcReg[1]); + + test_check(result, ret == expected); +} + +static void test_runner_rc_inst_can_use_presub(struct test_result * result) +{ + + /* This tests the case where the source being replace has the same + * register file and register index as another source register in the + * CMP instruction. A previous version of this function was ignoring + * all registers that shared the same file and index as the replacement + * register when counting the number of source selects. + * + * https://bugs.freedesktop.org/show_bug.cgi?id=36527 + */ + test_rc_inst_can_use_presub(result, 0, + "ADD temp[0].z, temp[6].__x_, const[1].__x_;", + "CMP temp[0].y, temp[0]._z__, const[0]._z__, temp[0]._y__;"); + + + /* Testing a random case that should fail + * + * https://bugs.freedesktop.org/show_bug.cgi?id=36527 + */ + test_rc_inst_can_use_presub(result, 0, + "ADD temp[3], temp[1], temp[2];", + "MAD temp[1], temp[0], const[0].xxxx, -temp[3];"); + + /* This tests the case where the arguments of the ADD + * instruction share the same register file and index. Normally, we + * would need only one source select for these two arguments, but since + * they will be part of a presubtract operation we need to use the two + * source selects that the presubtract instruction expects + * (src0 and src1). + * + * https://bugs.freedesktop.org/show_bug.cgi?id=36527 + */ + test_rc_inst_can_use_presub(result, 0, + "ADD temp[3].x, temp[0].x___, temp[0].x___;", + "MAD temp[0].xyz, temp[2].xyz_, -temp[3].xxx_, input[5].xyz_;"); +} + +int main(int argc, char ** argv) +{ + struct test tests[] = { + {"rc_inst_can_use_presub()", test_runner_rc_inst_can_use_presub}, + {NULL, NULL} + }; + run_tests(tests); +} diff --git a/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c new file mode 100644 index 00000000000..ca4738af54d --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c @@ -0,0 +1,380 @@ +#include <errno.h> +#include <regex.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "../radeon_compiler_util.h" +#include "../radeon_opcodes.h" +#include "../radeon_program.h" + +#include "rc_test_helpers.h" + +/* This file contains some helper functions for filling out the rc_instruction + * data structures. These functions take a string as input based on the format + * output by rc_program_print(). + */ + +#define VERBOSE 0 + +#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) + +#define REGEX_ERR_BUF_SIZE 50 + +struct match_info { + const char * String; + int Length; +}; + +static int match_length(regmatch_t * matches, int index) +{ + return matches[index].rm_eo - matches[index].rm_so; +} + +static int regex_helper( + const char * regex_str, + const char * search_str, + regmatch_t * matches, + int num_matches) +{ + char err_buf[REGEX_ERR_BUF_SIZE]; + regex_t regex; + int err_code; + unsigned int i; + + err_code = regcomp(®ex, regex_str, REG_EXTENDED); + if (err_code) { + regerror(err_code, ®ex, err_buf, REGEX_ERR_BUF_SIZE); + fprintf(stderr, "Failed to compile regex: %s\n", err_buf); + return 0; + } + + err_code = regexec(®ex, search_str, num_matches, matches, 0); + DBG("Search string: '%s'\n", search_str); + for (i = 0; i < num_matches; i++) { + DBG("Match %u start = %d end = %d\n", i, + matches[i].rm_so, matches[i].rm_eo); + } + if (err_code) { + regerror(err_code, ®ex, err_buf, REGEX_ERR_BUF_SIZE); + fprintf(stderr, "Failed to match regex: %s\n", err_buf); + return 0; + } + return 1; +} + +#define REGEX_SRC_MATCHES 6 + +struct src_tokens { + struct match_info Negate; + struct match_info Abs; + struct match_info File; + struct match_info Index; + struct match_info Swizzle; +}; + +/** + * Initialize the source register at index src_index for the instruction based + * on src_str. + * + * NOTE: Warning in init_rc_normal_instruction() applies to this function as + * well. + * + * @param src_str A string that represents the source register. The format for + * this string is the same that is output by rc_program_print. + * @return 1 On success, 0 on failure + */ +int init_rc_normal_src( + struct rc_instruction * inst, + unsigned int src_index, + const char * src_str) +{ + const char * regex_str = "(-*)(\\|*)([[:lower:]]*)\\[([[:digit:]])\\](\\.*[[:lower:]-]*)"; + regmatch_t matches[REGEX_SRC_MATCHES]; + struct src_tokens tokens; + struct rc_src_register * src_reg = &inst->U.I.SrcReg[src_index]; + unsigned int i; + + /* Execute the regex */ + if (!regex_helper(regex_str, src_str, matches, REGEX_SRC_MATCHES)) { + fprintf(stderr, "Failed to execute regex for src register.\n"); + return 0; + } + + /* Create Tokens */ + tokens.Negate.String = src_str + matches[1].rm_so; + tokens.Negate.Length = match_length(matches, 1); + tokens.Abs.String = src_str + matches[2].rm_so; + tokens.Abs.Length = match_length(matches, 2); + tokens.File.String = src_str + matches[3].rm_so; + tokens.File.Length = match_length(matches, 3); + tokens.Index.String = src_str + matches[4].rm_so; + tokens.Index.Length = match_length(matches, 4); + tokens.Swizzle.String = src_str + matches[5].rm_so; + tokens.Swizzle.Length = match_length(matches, 5); + + /* Negate */ + if (tokens.Negate.Length > 0) { + src_reg->Negate = RC_MASK_XYZW; + } + + /* Abs */ + if (tokens.Abs.Length > 0) { + src_reg->Abs = 1; + } + + /* File */ + if (!strncmp(tokens.File.String, "temp", tokens.File.Length)) { + src_reg->File = RC_FILE_TEMPORARY; + } else if (!strncmp(tokens.File.String, "input", tokens.File.Length)) { + src_reg->File = RC_FILE_INPUT; + } else if (!strncmp(tokens.File.String, "const", tokens.File.Length)) { + src_reg->File = RC_FILE_CONSTANT; + } else if (!strncmp(tokens.File.String, "none", tokens.File.Length)) { + src_reg->File = RC_FILE_NONE; + } + + /* Index */ + errno = 0; + src_reg->Index = strtol(tokens.Index.String, NULL, 10); + if (errno > 0) { + fprintf(stderr, "Could not convert src register index.\n"); + return 0; + } + + /* Swizzle */ + if (tokens.Swizzle.Length == 0) { + src_reg->Swizzle = RC_SWIZZLE_XYZW; + } else { + int str_index = 1; + src_reg->Swizzle = RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_UNUSED); + if (tokens.Swizzle.String[0] != '.') { + fprintf(stderr, "First char of swizzle is not valid.\n"); + return 0; + } + for (i = 0; i < 4; i++, str_index++) { + if (tokens.Swizzle.String[str_index] == '-') { + src_reg->Negate |= (1 << i); + str_index++; + } + switch(tokens.Swizzle.String[str_index]) { + case 'x': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_X); + break; + case 'y': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_Y); + break; + case 'z': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_Z); + break; + case 'w': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_W); + break; + case '1': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_ONE); + break; + case '0': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_ZERO); + break; + case 'H': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_HALF); + break; + case '_': + SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_UNUSED); + break; + default: + fprintf(stderr, "Unknown src register swizzle.\n"); + return 0; + } + } + } + DBG("File=%u index=%u swizzle=%x negate=%u abs=%u\n", + src_reg->File, src_reg->Index, src_reg->Swizzle, + src_reg->Negate, src_reg->Abs); + return 1; +} + +#define REGEX_DST_MATCHES 4 + +struct dst_tokens { + struct match_info File; + struct match_info Index; + struct match_info WriteMask; +}; + +/** + * Initialize the destination for the instruction based on dst_str. + * + * NOTE: Warning in init_rc_normal_instruction() applies to this function as + * well. + * + * @param dst_str A string that represents the destination register. The format + * for this string is the same that is output by rc_program_print. + * @return 1 On success, 0 on failure + */ +int init_rc_normal_dst( + struct rc_instruction * inst, + const char * dst_str) +{ + const char * regex_str = "([[:lower:]]*)\\[([[:digit:]]*)\\](\\.*[[:lower:]]*)"; + regmatch_t matches[REGEX_DST_MATCHES]; + struct dst_tokens tokens; + unsigned int i; + + /* Execute the regex */ + if (!regex_helper(regex_str, dst_str, matches, REGEX_DST_MATCHES)) { + fprintf(stderr, "Failed to execute regex for dst register.\n"); + return 0; + } + + /* Create Tokens */ + tokens.File.String = dst_str + matches[1].rm_so; + tokens.File.Length = match_length(matches, 1); + tokens.Index.String = dst_str + matches[2].rm_so; + tokens.Index.Length = match_length(matches, 2); + tokens.WriteMask.String = dst_str + matches[3].rm_so; + tokens.WriteMask.Length = match_length(matches, 3); + + /* File Type */ + if (!strncmp(tokens.File.String, "temp", tokens.File.Length)) { + inst->U.I.DstReg.File = RC_FILE_TEMPORARY; + } else if (!strncmp(tokens.File.String, "output", tokens.File.Length)) { + inst->U.I.DstReg.File = RC_FILE_OUTPUT; + } else { + fprintf(stderr, "Unknown dst register file type.\n"); + return 0; + } + + /* File Index */ + errno = 0; + inst->U.I.DstReg.Index = strtol(tokens.Index.String, NULL, 10); + + if (errno > 0) { + fprintf(stderr, "Could not convert dst register index\n"); + return 0; + } + + /* WriteMask */ + if (tokens.WriteMask.Length == 0) { + inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; + } else { + /* The first character should be '.' */ + if (tokens.WriteMask.String[0] != '.') { + fprintf(stderr, "1st char of writemask is not valid.\n"); + return 0; + } + for (i = 1; i < tokens.WriteMask.Length; i++) { + switch(tokens.WriteMask.String[i]) { + case 'x': + inst->U.I.DstReg.WriteMask |= RC_MASK_X; + break; + case 'y': + inst->U.I.DstReg.WriteMask |= RC_MASK_Y; + break; + case 'z': + inst->U.I.DstReg.WriteMask |= RC_MASK_Z; + break; + case 'w': + inst->U.I.DstReg.WriteMask |= RC_MASK_W; + break; + default: + fprintf(stderr, "Unknown swizzle in writemask.\n"); + return 0; + } + } + } + DBG("Dst Reg File=%u Index=%d Writemask=%d\n", + inst->U.I.DstReg.File, + inst->U.I.DstReg.Index, + inst->U.I.DstReg.WriteMask); + return 1; +} + +#define REGEX_INST_MATCHES 7 + +struct inst_tokens { + struct match_info Opcode; + struct match_info Sat; + struct match_info Dst; + struct match_info Srcs[3]; +}; + +/** + * Initialize a normal instruction based on inst_str. + * + * WARNING: This function might not be able to handle every kind of format that + * rc_program_print() can output. If you are having problems with a + * particular string, you may need to add support for it to this functions. + * + * @param inst_str A string that represents the source register. The format for + * this string is the same that is output by rc_program_print. + * @return 1 On success, 0 on failure + */ +int init_rc_normal_instruction( + struct rc_instruction * inst, + const char * inst_str) +{ + const char * regex_str = "([[:upper:]]+)(_SAT)* ([^,]*)[, ]*([^,]*)[, ]*([^,]*)[, ]*([^;]*)"; + int i; + regmatch_t matches[REGEX_INST_MATCHES]; + struct inst_tokens tokens; + + /* Initialize inst */ + memset(inst, 0, sizeof(struct rc_instruction)); + inst->Type = RC_INSTRUCTION_NORMAL; + + /* Execute the regex */ + if (!regex_helper(regex_str, inst_str, matches, REGEX_INST_MATCHES)) { + return 0; + } + memset(&tokens, 0, sizeof(tokens)); + + /* Create Tokens */ + tokens.Opcode.String = inst_str + matches[1].rm_so; + tokens.Opcode.Length = match_length(matches, 1); + if (matches[2].rm_so > -1) { + tokens.Sat.String = inst_str + matches[2].rm_so; + tokens.Sat.Length = match_length(matches, 2); + } + + + /* Fill out the rest of the instruction. */ + for (i = 0; i < MAX_RC_OPCODE; i++) { + const struct rc_opcode_info * info = rc_get_opcode_info(i); + unsigned int first_src = 3; + unsigned int j; + if (strncmp(tokens.Opcode.String, info->Name, tokens.Opcode.Length)) { + continue; + } + inst->U.I.Opcode = info->Opcode; + if (info->HasDstReg) { + char * dst_str; + tokens.Dst.String = inst_str + matches[3].rm_so; + tokens.Dst.Length = match_length(matches, 3); + first_src++; + + dst_str = malloc(sizeof(char) * (tokens.Dst.Length + 1)); + strncpy(dst_str, tokens.Dst.String, tokens.Dst.Length); + dst_str[tokens.Dst.Length] = '\0'; + init_rc_normal_dst(inst, dst_str); + free(dst_str); + } + for (j = 0; j < info->NumSrcRegs; j++) { + char * src_str; + tokens.Srcs[j].String = + inst_str + matches[first_src + j].rm_so; + tokens.Srcs[j].Length = + match_length(matches, first_src + j); + + src_str = malloc(sizeof(char) * + (tokens.Srcs[j].Length + 1)); + strncpy(src_str, tokens.Srcs[j].String, + tokens.Srcs[j].Length); + src_str[tokens.Srcs[j].Length] = '\0'; + init_rc_normal_src(inst, j, src_str); + } + break; + } + return 1; +} diff --git a/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h new file mode 100644 index 00000000000..1a6bf9699ba --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h @@ -0,0 +1,13 @@ + +int init_rc_normal_src( + struct rc_instruction * inst, + unsigned int src_index, + const char * src_str); + +int init_rc_normal_dst( + struct rc_instruction * inst, + const char * dst_str); + +int init_rc_normal_instruction( + struct rc_instruction * inst, + const char * inst_str); diff --git a/src/gallium/drivers/r300/compiler/tests/unit_test.c b/src/gallium/drivers/r300/compiler/tests/unit_test.c new file mode 100644 index 00000000000..266f3365c58 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/unit_test.c @@ -0,0 +1,35 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "unit_test.h" + +void run_tests(struct test tests[]) +{ + int i; + for (i = 0; tests[i].name; i++) { + printf("Test %s\n", tests[i].name); + memset(&tests[i].result, 0, sizeof(tests[i].result)); + tests[i].test_func(&tests[i].result); + printf("Test %s (%d/%d) pass\n", tests[i].name, + tests[i].result.pass, tests[i].result.test_count); + } +} + +void test_begin(struct test_result * result) +{ + result->test_count++; +} + +void test_check(struct test_result * result, int cond) +{ + printf("Subtest %u -> ", result->test_count); + if (cond) { + result->pass++; + printf("Pass"); + } else { + result->fail++; + printf("Fail"); + } + printf("\n"); +} diff --git a/src/gallium/drivers/r300/compiler/tests/unit_test.h b/src/gallium/drivers/r300/compiler/tests/unit_test.h new file mode 100644 index 00000000000..441e8b655a5 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/unit_test.h @@ -0,0 +1,17 @@ + +struct test_result { + unsigned int test_count; + unsigned int pass; + unsigned int fail; +}; + +struct test { + const char * name; + void (*test_func)(struct test_result * result); + struct test_result result; +}; + +void run_tests(struct test tests[]); + +void test_begin(struct test_result * result); +void test_check(struct test_result * result, int cond); diff --git a/src/gallium/drivers/r300/r300_blit.c b/src/gallium/drivers/r300/r300_blit.c index 388ebcdbf32..db97e496e19 100644 --- a/src/gallium/drivers/r300/r300_blit.c +++ b/src/gallium/drivers/r300/r300_blit.c @@ -247,7 +247,7 @@ static void r300_clear(struct pipe_context* pipe, if (!r300->hyperz_enabled) { r300->hyperz_enabled = r300->rws->cs_request_feature(r300->cs, - RADEON_FID_HYPERZ_RAM_ACCESS, + RADEON_FID_R300_HYPERZ_ACCESS, TRUE); if (r300->hyperz_enabled) { /* Need to emit HyperZ buffer regs for the first time. */ diff --git a/src/gallium/drivers/r300/r300_chipset.c b/src/gallium/drivers/r300/r300_chipset.c index 571986c3011..80148b80afb 100644 --- a/src/gallium/drivers/r300/r300_chipset.c +++ b/src/gallium/drivers/r300/r300_chipset.c @@ -31,9 +31,9 @@ * Radeons. */ /* Parse a PCI ID and fill an r300_capabilities struct with information. */ -void r300_parse_chipset(struct r300_capabilities* caps) +void r300_parse_chipset(uint32_t pci_id, struct r300_capabilities* caps) { - switch (caps->pci_id) { + switch (pci_id) { #define CHIPSET(pci_id, name, chipfamily) \ case pci_id: \ caps->family = CHIP_FAMILY_##chipfamily; \ @@ -43,7 +43,7 @@ void r300_parse_chipset(struct r300_capabilities* caps) default: fprintf(stderr, "r300: Warning: Unknown chipset 0x%x\nAborting...", - caps->pci_id); + pci_id); abort(); } diff --git a/src/gallium/drivers/r300/r300_chipset.h b/src/gallium/drivers/r300/r300_chipset.h index 4df6b5b6292..f96cdaf2580 100644 --- a/src/gallium/drivers/r300/r300_chipset.h +++ b/src/gallium/drivers/r300/r300_chipset.h @@ -43,16 +43,10 @@ enum r300_zmask_compression { /* Structure containing all the possible information about a specific Radeon * in the R3xx, R4xx, and R5xx families. */ struct r300_capabilities { - /* PCI ID */ - uint32_t pci_id; /* Chipset family */ int family; /* The number of vertex floating-point units */ unsigned num_vert_fpus; - /* The number of fragment pipes */ - unsigned num_frag_pipes; - /* The number of z pipes */ - unsigned num_z_pipes; /* The number of texture units. */ unsigned num_tex_units; /* Whether or not TCL is physically present */ @@ -121,6 +115,6 @@ enum { CHIP_FAMILY_RV570 }; -void r300_parse_chipset(struct r300_capabilities* caps); +void r300_parse_chipset(uint32_t pci_id, struct r300_capabilities* caps); #endif /* R300_CHIPSET_H */ diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index 0554c40eef0..5c222588e47 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -27,6 +27,8 @@ #include "util/u_simple_list.h" #include "util/u_upload_mgr.h" #include "os/os_time.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "r300_cb.h" #include "r300_context.h" @@ -97,7 +99,7 @@ static void r300_destroy_context(struct pipe_context* context) struct r300_context* r300 = r300_context(context); if (r300->cs && r300->hyperz_enabled) { - r300->rws->cs_request_feature(r300->cs, RADEON_FID_HYPERZ_RAM_ACCESS, FALSE); + r300->rws->cs_request_feature(r300->cs, RADEON_FID_R300_HYPERZ_ACCESS, FALSE); } if (r300->blitter) @@ -171,7 +173,7 @@ static boolean r300_setup_atoms(struct r300_context* r300) boolean is_rv350 = r300->screen->caps.is_rv350; boolean is_r500 = r300->screen->caps.is_r500; boolean has_tcl = r300->screen->caps.has_tcl; - boolean drm_2_6_0 = r300->rws->get_value(r300->rws, RADEON_VID_DRM_2_6_0); + boolean drm_2_6_0 = r300->screen->info.drm_minor >= 6; /* Create the actual atom list. * @@ -378,7 +380,7 @@ static void r300_init_states(struct pipe_context *pipe) if (r300->screen->caps.is_r500 || (r300->screen->caps.is_rv350 && - r300->rws->get_value(r300->rws, RADEON_VID_DRM_2_6_0))) { + r300->screen->info.drm_minor >= 6)) { OUT_CB_REG(R300_GB_Z_PEQ_CONFIG, 0); } END_CB; @@ -436,6 +438,9 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300_init_query_functions(r300); r300_init_state_functions(r300); r300_init_resource_functions(r300); + + r300->context.create_video_decoder = vl_create_decoder; + r300->context.create_video_buffer = vl_video_buffer_create; r300->vbuf_mgr = u_vbuf_mgr_create(&r300->context, 1024 * 1024, 16, PIPE_BIND_VERTEX_BUFFER | @@ -515,15 +520,15 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, "r300: DRM version: %d.%d.%d, Name: %s, ID: 0x%04x, GB: %d, Z: %d\n" "r300: GART size: %d MB, VRAM size: %d MB\n" "r300: AA compression RAM: %s, Z compression RAM: %s, HiZ RAM: %s\n", - rws->get_value(rws, RADEON_VID_DRM_MAJOR), - rws->get_value(rws, RADEON_VID_DRM_MINOR), - rws->get_value(rws, RADEON_VID_DRM_PATCHLEVEL), + r300->screen->info.drm_major, + r300->screen->info.drm_minor, + r300->screen->info.drm_patchlevel, screen->get_name(screen), - rws->get_value(rws, RADEON_VID_PCI_ID), - rws->get_value(rws, RADEON_VID_R300_GB_PIPES), - rws->get_value(rws, RADEON_VID_R300_Z_PIPES), - rws->get_value(rws, RADEON_VID_GART_SIZE) >> 20, - rws->get_value(rws, RADEON_VID_VRAM_SIZE) >> 20, + r300->screen->info.pci_id, + r300->screen->info.r300_num_gb_pipes, + r300->screen->info.r300_num_z_pipes, + r300->screen->info.gart_size >> 20, + r300->screen->info.vram_size >> 20, "YES", /* XXX really? */ r300->screen->caps.zmask_ram ? "YES" : "NO", r300->screen->caps.hiz_ram ? "YES" : "NO"); diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index d214af4cd5b..502aed3a20c 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -574,11 +574,12 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, struct r300_query *query) { struct r300_capabilities* caps = &r300->screen->caps; + uint32_t gb_pipes = r300->screen->info.r300_num_gb_pipes; CS_LOCALS(r300); - assert(caps->num_frag_pipes); + assert(gb_pipes); - BEGIN_CS(6 * caps->num_frag_pipes + 2); + BEGIN_CS(6 * gb_pipes + 2); /* I'm not so sure I like this switch, but it's hard to be elegant * when there's so many special cases... * @@ -587,7 +588,7 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, * 4-byte offset for each pipe. RV380 and older are special; they have * only two pipes, and the second pipe's enable is on bit 3, not bit 1, * so there's a chipset cap for that. */ - switch (caps->num_frag_pipes) { + switch (gb_pipes) { case 4: /* pipe 3 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 3); @@ -613,7 +614,7 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, break; default: fprintf(stderr, "r300: Implementation error: Chipset reports %d" - " pixel pipes!\n", caps->num_frag_pipes); + " pixel pipes!\n", gb_pipes); abort(); } @@ -663,7 +664,7 @@ void r300_emit_query_end(struct r300_context* r300) return; if (caps->family == CHIP_FAMILY_RV530) { - if (caps->num_z_pipes == 2) + if (r300->screen->info.r300_num_z_pipes == 2) rv530_emit_query_end_double_z(r300, query); else rv530_emit_query_end_single_z(r300, query); diff --git a/src/gallium/drivers/r300/r300_emit.h b/src/gallium/drivers/r300/r300_emit.h index 6c1c9d2fb13..234e043b071 100644 --- a/src/gallium/drivers/r300/r300_emit.h +++ b/src/gallium/drivers/r300/r300_emit.h @@ -24,7 +24,6 @@ #define R300_EMIT_H #include "r300_context.h" -#include "radeon_code.h" struct rX00_fragment_program_code; struct r300_vertex_program_code; diff --git a/src/gallium/drivers/r300/r300_flush.c b/src/gallium/drivers/r300/r300_flush.c index 34f5419a864..dc596c4122a 100644 --- a/src/gallium/drivers/r300/r300_flush.c +++ b/src/gallium/drivers/r300/r300_flush.c @@ -76,7 +76,6 @@ void r300_flush(struct pipe_context *pipe, /* Create a fence, which is a dummy BO. */ *rfence = r300->rws->buffer_create(r300->rws, 1, 1, PIPE_BIND_VERTEX_BUFFER, - PIPE_USAGE_STATIC, RADEON_DOMAIN_GTT); /* Add the fence as a dummy relocation. */ r300->rws->cs_add_reloc(r300->cs, @@ -121,7 +120,7 @@ void r300_flush(struct pipe_context *pipe, } /* Release HyperZ. */ - r300->rws->cs_request_feature(r300->cs, RADEON_FID_HYPERZ_RAM_ACCESS, + r300->rws->cs_request_feature(r300->cs, RADEON_FID_R300_HYPERZ_ACCESS, FALSE); } r300->num_z_clears = 0; diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c index e3a1bc4a0f4..6f21125f70a 100644 --- a/src/gallium/drivers/r300/r300_fs.c +++ b/src/gallium/drivers/r300/r300_fs.c @@ -38,8 +38,7 @@ #include "r300_texture.h" #include "r300_tgsi_to_rc.h" -#include "radeon_code.h" -#include "radeon_compiler.h" +#include "compiler/radeon_compiler.h" /* Convert info about FS input semantics to r300_shader_semantics. */ void r300_shader_read_fs_inputs(struct tgsi_shader_info* info, @@ -181,9 +180,10 @@ static void get_external_state( v->base.format == PIPE_FORMAT_LATC1_SNORM) { unsigned char swizzle[4]; - util_format_combine_swizzles(swizzle, + util_format_compose_swizzles( util_format_description(v->base.format)->swizzle, - v->swizzle); + v->swizzle, + swizzle); state->unit[i].texture_swizzle = RC_MAKE_SWIZZLE(swizzle[0], swizzle[1], diff --git a/src/gallium/drivers/r300/r300_fs.h b/src/gallium/drivers/r300/r300_fs.h index c86a90b85ae..45c9e8801c3 100644 --- a/src/gallium/drivers/r300/r300_fs.h +++ b/src/gallium/drivers/r300/r300_fs.h @@ -27,7 +27,7 @@ #include "pipe/p_state.h" #include "tgsi/tgsi_scan.h" -#include "radeon_code.h" +#include "compiler/radeon_code.h" #include "r300_shader_semantics.h" struct r300_fragment_shader_code { diff --git a/src/gallium/drivers/r300/r300_query.c b/src/gallium/drivers/r300/r300_query.c index 782f041e926..c0357f9d035 100644 --- a/src/gallium/drivers/r300/r300_query.c +++ b/src/gallium/drivers/r300/r300_query.c @@ -49,16 +49,15 @@ static struct pipe_query *r300_create_query(struct pipe_context *pipe, q->buffer_size = 4096; if (r300screen->caps.family == CHIP_FAMILY_RV530) - q->num_pipes = r300screen->caps.num_z_pipes; + q->num_pipes = r300screen->info.r300_num_z_pipes; else - q->num_pipes = r300screen->caps.num_frag_pipes; + q->num_pipes = r300screen->info.r300_num_gb_pipes; insert_at_tail(&r300->query_list, q); /* Open up the occlusion query buffer. */ q->buf = r300->rws->buffer_create(r300->rws, q->buffer_size, 4096, - PIPE_BIND_CUSTOM, PIPE_USAGE_STREAM, - q->domain); + PIPE_BIND_CUSTOM, q->domain); q->cs_buf = r300->rws->buffer_get_cs_handle(q->buf); return (struct pipe_query*)q; diff --git a/src/gallium/drivers/r300/r300_reg.h b/src/gallium/drivers/r300/r300_reg.h index bb30b1ab0be..5edbb22a743 100644 --- a/src/gallium/drivers/r300/r300_reg.h +++ b/src/gallium/drivers/r300/r300_reg.h @@ -2078,7 +2078,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_ALU_OUTC_D2A (3 << 23) # define R300_ALU_OUTC_MIN (4 << 23) # define R300_ALU_OUTC_MAX (5 << 23) -# define R300_ALU_OUTC_CMPH (7 << 23) +# define R300_ALU_OUTC_CND (7 << 23) # define R300_ALU_OUTC_CMP (8 << 23) # define R300_ALU_OUTC_FRC (9 << 23) # define R300_ALU_OUTC_REPL_ALPHA (10 << 23) @@ -2944,6 +2944,23 @@ enum { /*\}*/ +#define PVS_OP_DST_OPERAND(opcode, math_inst, macro_inst, reg_index, reg_writemask, reg_class) \ + (((opcode & PVS_DST_OPCODE_MASK) << PVS_DST_OPCODE_SHIFT) \ + | ((math_inst & PVS_DST_MATH_INST_MASK) << PVS_DST_MATH_INST_SHIFT) \ + | ((macro_inst & PVS_DST_MACRO_INST_MASK) << PVS_DST_MACRO_INST_SHIFT) \ + | ((reg_index & PVS_DST_OFFSET_MASK) << PVS_DST_OFFSET_SHIFT) \ + | ((reg_writemask & 0xf) << PVS_DST_WE_X_SHIFT) /* X Y Z W */ \ + | ((reg_class & PVS_DST_REG_TYPE_MASK) << PVS_DST_REG_TYPE_SHIFT)) + +#define PVS_SRC_OPERAND(in_reg_index, comp_x, comp_y, comp_z, comp_w, reg_class, negate) \ + (((in_reg_index & PVS_SRC_OFFSET_MASK) << PVS_SRC_OFFSET_SHIFT) \ + | ((comp_x & PVS_SRC_SWIZZLE_X_MASK) << PVS_SRC_SWIZZLE_X_SHIFT) \ + | ((comp_y & PVS_SRC_SWIZZLE_Y_MASK) << PVS_SRC_SWIZZLE_Y_SHIFT) \ + | ((comp_z & PVS_SRC_SWIZZLE_Z_MASK) << PVS_SRC_SWIZZLE_Z_SHIFT) \ + | ((comp_w & PVS_SRC_SWIZZLE_W_MASK) << PVS_SRC_SWIZZLE_W_SHIFT) \ + | ((negate & 0xf) << PVS_SRC_MODIFIER_X_SHIFT) /* X Y Z W */ \ + | ((reg_class & PVS_SRC_REG_TYPE_MASK) << PVS_SRC_REG_TYPE_SHIFT)) + /* BEGIN: Packet 3 commands */ /* A primitive emission dword. */ @@ -3249,6 +3266,8 @@ enum { # define R500_INST_RGB_CLAMP (1 << 19) # define R500_INST_ALPHA_CLAMP (1 << 20) # define R500_INST_ALU_RESULT_SEL (1 << 21) +# define R500_INST_ALU_RESULT_SEL_RED (0 << 21) +# define R500_INST_ALU_RESULT_SEL_ALPHA (1 << 21) # define R500_INST_ALPHA_PRED_INV (1 << 22) # define R500_INST_ALU_RESULT_OP_EQ (0 << 23) # define R500_INST_ALU_RESULT_OP_LT (1 << 23) diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c index d9399d78ef9..b31141a518e 100644 --- a/src/gallium/drivers/r300/r300_render.c +++ b/src/gallium/drivers/r300/r300_render.c @@ -175,8 +175,8 @@ static void r300_split_index_bias(struct r300_context *r300, int index_bias, enum r300_prepare_flags { PREP_EMIT_STATES = (1 << 0), /* call emit_dirty_state and friends? */ PREP_VALIDATE_VBOS = (1 << 1), /* validate VBOs? */ - PREP_EMIT_AOS = (1 << 2), /* call emit_vertex_arrays? */ - PREP_EMIT_AOS_SWTCL = (1 << 3), /* call emit_vertex_arrays_swtcl? */ + PREP_EMIT_VARRAYS = (1 << 2), /* call emit_vertex_arrays? */ + PREP_EMIT_VARRAYS_SWTCL = (1 << 3), /* call emit_vertex_arrays_swtcl? */ PREP_INDEXED = (1 << 4) /* is this draw_elements? */ }; @@ -193,23 +193,22 @@ static boolean r300_reserve_cs_dwords(struct r300_context *r300, unsigned cs_dwords) { boolean flushed = FALSE; - boolean first_draw = flags & PREP_EMIT_STATES; - boolean emit_vertex_arrays = flags & PREP_EMIT_AOS; - boolean emit_vertex_arrays_swtcl = flags & PREP_EMIT_AOS_SWTCL; + boolean emit_states = flags & PREP_EMIT_STATES; + boolean emit_vertex_arrays = flags & PREP_EMIT_VARRAYS; + boolean emit_vertex_arrays_swtcl = flags & PREP_EMIT_VARRAYS_SWTCL; /* Add dirty state, index offset, and AOS. */ - if (first_draw) { + if (emit_states) cs_dwords += r300_get_num_dirty_dwords(r300); - if (r300->screen->caps.is_r500) - cs_dwords += 2; /* emit_index_offset */ + if (r300->screen->caps.is_r500) + cs_dwords += 2; /* emit_index_offset */ - if (emit_vertex_arrays) - cs_dwords += 55; /* emit_vertex_arrays */ + if (emit_vertex_arrays) + cs_dwords += 55; /* emit_vertex_arrays */ - if (emit_vertex_arrays_swtcl) - cs_dwords += 7; /* emit_vertex_arrays_swtcl */ - } + if (emit_vertex_arrays_swtcl) + cs_dwords += 7; /* emit_vertex_arrays_swtcl */ cs_dwords += r300_get_num_cs_end_dwords(r300); @@ -238,46 +237,48 @@ static boolean r300_emit_states(struct r300_context *r300, int buffer_offset, int index_bias, int instance_id) { - boolean first_draw = flags & PREP_EMIT_STATES; - boolean emit_vertex_arrays = flags & PREP_EMIT_AOS; - boolean emit_vertex_arrays_swtcl = flags & PREP_EMIT_AOS_SWTCL; + boolean emit_states = flags & PREP_EMIT_STATES; + boolean emit_vertex_arrays = flags & PREP_EMIT_VARRAYS; + boolean emit_vertex_arrays_swtcl = flags & PREP_EMIT_VARRAYS_SWTCL; boolean indexed = flags & PREP_INDEXED; boolean validate_vbos = flags & PREP_VALIDATE_VBOS; /* Validate buffers and emit dirty state if needed. */ - if (first_draw) { + if (emit_states || (emit_vertex_arrays && validate_vbos)) { if (!r300_emit_buffer_validate(r300, validate_vbos, index_buffer)) { fprintf(stderr, "r300: CS space validation failed. " "(not enough memory?) Skipping rendering.\n"); return FALSE; } + } + if (emit_states) r300_emit_dirty_state(r300); - if (r300->screen->caps.is_r500) { - if (r300->screen->caps.has_tcl) - r500_emit_index_bias(r300, index_bias); - else - r500_emit_index_bias(r300, 0); - } - if (emit_vertex_arrays && - (r300->vertex_arrays_dirty || - r300->vertex_arrays_indexed != indexed || - r300->vertex_arrays_offset != buffer_offset || - r300->vertex_arrays_instance_id != instance_id)) { - r300_emit_vertex_arrays(r300, buffer_offset, indexed, instance_id); - - r300->vertex_arrays_dirty = FALSE; - r300->vertex_arrays_indexed = indexed; - r300->vertex_arrays_offset = buffer_offset; - r300->vertex_arrays_instance_id = instance_id; - } + if (r300->screen->caps.is_r500) { + if (r300->screen->caps.has_tcl) + r500_emit_index_bias(r300, index_bias); + else + r500_emit_index_bias(r300, 0); + } - if (emit_vertex_arrays_swtcl) - r300_emit_vertex_arrays_swtcl(r300, indexed); + if (emit_vertex_arrays && + (r300->vertex_arrays_dirty || + r300->vertex_arrays_indexed != indexed || + r300->vertex_arrays_offset != buffer_offset || + r300->vertex_arrays_instance_id != instance_id)) { + r300_emit_vertex_arrays(r300, buffer_offset, indexed, instance_id); + + r300->vertex_arrays_dirty = FALSE; + r300->vertex_arrays_indexed = indexed; + r300->vertex_arrays_offset = buffer_offset; + r300->vertex_arrays_instance_id = instance_id; } + if (emit_vertex_arrays_swtcl) + r300_emit_vertex_arrays_swtcl(r300, indexed); + return TRUE; } @@ -540,7 +541,7 @@ static void r300_draw_elements_immediate(struct r300_context *r300, /* 19 dwords for r300_draw_elements_immediate. Give up if the function fails. */ if (!r300_prepare_for_rendering(r300, - PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_AOS | + PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS | PREP_INDEXED, NULL, 2+count_dwords, 0, info->index_bias, -1)) return; @@ -662,7 +663,7 @@ static void r300_draw_elements(struct r300_context *r300, /* 19 dwords for emit_draw_elements. Give up if the function fails. */ if (!r300_prepare_for_rendering(r300, - PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_AOS | + PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS | PREP_INDEXED, indexBuffer, 19, buffer_offset, info->index_bias, instance_id)) goto done; @@ -689,7 +690,7 @@ static void r300_draw_elements(struct r300_context *r300, /* 15 dwords for emit_draw_elements */ if (count) { if (!r300_prepare_for_rendering(r300, - PREP_VALIDATE_VBOS | PREP_EMIT_AOS | PREP_INDEXED, + PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS | PREP_INDEXED, indexBuffer, 19, buffer_offset, info->index_bias, instance_id)) goto done; @@ -715,7 +716,7 @@ static void r300_draw_arrays(struct r300_context *r300, /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */ if (!r300_prepare_for_rendering(r300, - PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_AOS, + PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS, NULL, 9, start, 0, instance_id)) return; @@ -736,7 +737,7 @@ static void r300_draw_arrays(struct r300_context *r300, /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */ if (count) { if (!r300_prepare_for_rendering(r300, - PREP_VALIDATE_VBOS | PREP_EMIT_AOS, NULL, 9, + PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS, NULL, 9, start, 0, instance_id)) return; } @@ -767,7 +768,6 @@ static void r300_draw_vbo(struct pipe_context* pipe, { struct r300_context* r300 = r300_context(pipe); struct pipe_draw_info info = *dinfo; - boolean buffers_updated, uploader_flushed; info.indexed = info.indexed && r300->index_buffer.buffer; @@ -779,9 +779,7 @@ static void r300_draw_vbo(struct pipe_context* pipe, r300_update_derived_state(r300); /* Start the vbuf manager and update buffers if needed. */ - u_vbuf_mgr_draw_begin(r300->vbuf_mgr, &info, - &buffers_updated, &uploader_flushed); - if (buffers_updated) { + if (u_vbuf_mgr_draw_begin(r300->vbuf_mgr, &info) & U_VBUF_BUFFERS_UPDATED) { r300->vertex_arrays_dirty = TRUE; } @@ -843,7 +841,7 @@ static void r300_swtcl_draw_vbo(struct pipe_context* pipe, r300_update_derived_state(r300); r300_reserve_cs_dwords(r300, - PREP_EMIT_STATES | PREP_EMIT_AOS_SWTCL | + PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL | (indexed ? PREP_INDEXED : 0), indexed ? 256 : 6); @@ -1025,12 +1023,12 @@ static void r300_render_draw_arrays(struct vbuf_render* render, if (r300->draw_first_emitted) { if (!r300_prepare_for_rendering(r300, - PREP_EMIT_STATES | PREP_EMIT_AOS_SWTCL, + PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL, NULL, dwords, 0, 0, -1)) return; } else { if (!r300_emit_states(r300, - PREP_EMIT_STATES | PREP_EMIT_AOS_SWTCL, + PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL, NULL, 0, 0, -1)) return; } @@ -1065,12 +1063,12 @@ static void r300_render_draw_elements(struct vbuf_render* render, if (r300->draw_first_emitted) { if (!r300_prepare_for_rendering(r300, - PREP_EMIT_STATES | PREP_EMIT_AOS_SWTCL | PREP_INDEXED, + PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL | PREP_INDEXED, NULL, 256, 0, 0, -1)) return; } else { if (!r300_emit_states(r300, - PREP_EMIT_STATES | PREP_EMIT_AOS_SWTCL | PREP_INDEXED, + PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL | PREP_INDEXED, NULL, 0, 0, -1)) return; } @@ -1107,7 +1105,7 @@ static void r300_render_draw_elements(struct vbuf_render* render, if (count) { if (!r300_prepare_for_rendering(r300, - PREP_EMIT_AOS_SWTCL | PREP_INDEXED, + PREP_EMIT_VARRAYS_SWTCL | PREP_INDEXED, NULL, 256, 0, 0, -1)) return; diff --git a/src/gallium/drivers/r300/r300_screen.c b/src/gallium/drivers/r300/r300_screen.c index 93baba68150..47de4005c37 100644 --- a/src/gallium/drivers/r300/r300_screen.c +++ b/src/gallium/drivers/r300/r300_screen.c @@ -25,6 +25,8 @@ #include "util/u_format_s3tc.h" #include "util/u_memory.h" #include "os/os_time.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "r300_context.h" #include "r300_texture.h" @@ -304,15 +306,31 @@ static float r300_get_paramf(struct pipe_screen* pscreen, enum pipe_cap param) } } +static int r300_get_video_param(struct pipe_screen *screen, + enum pipe_video_profile profile, + enum pipe_video_cap param) +{ + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vl_profile_supported(screen, profile); + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 0; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vl_video_buffer_max_size(screen); + default: + return 0; + } +} + static boolean r300_is_format_supported(struct pipe_screen* screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned usage) { - struct radeon_winsys *rws = r300_screen(screen)->rws; uint32_t retval = 0; - boolean drm_2_8_0 = rws->get_value(rws, RADEON_VID_DRM_2_8_0); + boolean drm_2_8_0 = r300_screen(screen)->info.drm_minor >= 8; boolean is_r500 = r300_screen(screen)->caps.is_r500; boolean is_r400 = r300_screen(screen)->caps.is_r400; boolean is_color2101010 = format == PIPE_FORMAT_R10G10B10A2_UNORM || @@ -480,19 +498,17 @@ struct pipe_screen* r300_screen_create(struct radeon_winsys *rws) return NULL; } - r300screen->caps.pci_id = rws->get_value(rws, RADEON_VID_PCI_ID); - r300screen->caps.num_frag_pipes = rws->get_value(rws, RADEON_VID_R300_GB_PIPES); - r300screen->caps.num_z_pipes = rws->get_value(rws, RADEON_VID_R300_Z_PIPES); + rws->query_info(rws, &r300screen->info); r300_init_debug(r300screen); - r300_parse_chipset(&r300screen->caps); + r300_parse_chipset(r300screen->info.pci_id, &r300screen->caps); if (SCREEN_DBG_ON(r300screen, DBG_NO_ZMASK)) r300screen->caps.zmask_ram = 0; if (SCREEN_DBG_ON(r300screen, DBG_NO_HIZ)) r300screen->caps.hiz_ram = 0; - if (!rws->get_value(rws, RADEON_VID_DRM_2_8_0)) + if (r300screen->info.drm_minor < 8) r300screen->caps.has_us_format = FALSE; pipe_mutex_init(r300screen->num_contexts_mutex); @@ -509,9 +525,10 @@ struct pipe_screen* r300_screen_create(struct radeon_winsys *rws) r300screen->screen.get_param = r300_get_param; r300screen->screen.get_shader_param = r300_get_shader_param; r300screen->screen.get_paramf = r300_get_paramf; + r300screen->screen.get_video_param = r300_get_video_param; r300screen->screen.is_format_supported = r300_is_format_supported; + r300screen->screen.is_video_format_supported = vl_video_buffer_is_format_supported; r300screen->screen.context_create = r300_create_context; - r300screen->screen.fence_reference = r300_fence_reference; r300screen->screen.fence_signalled = r300_fence_signalled; r300screen->screen.fence_finish = r300_fence_finish; diff --git a/src/gallium/drivers/r300/r300_screen.h b/src/gallium/drivers/r300/r300_screen.h index e5c53bf3500..82b2068e7a0 100644 --- a/src/gallium/drivers/r300/r300_screen.h +++ b/src/gallium/drivers/r300/r300_screen.h @@ -24,23 +24,20 @@ #ifndef R300_SCREEN_H #define R300_SCREEN_H -#include "pipe/p_screen.h" - #include "r300_chipset.h" - +#include "../../winsys/radeon/drm/radeon_winsys.h" +#include "pipe/p_screen.h" #include "util/u_slab.h" - #include <stdio.h> -struct radeon_winsys; - struct r300_screen { /* Parent class */ struct pipe_screen screen; struct radeon_winsys *rws; - /* Chipset capabilities */ + /* Chipset info and capabilities. */ + struct radeon_info info; struct r300_capabilities caps; /* Memory pools. */ diff --git a/src/gallium/drivers/r300/r300_screen_buffer.c b/src/gallium/drivers/r300/r300_screen_buffer.c index 4154c81512e..c751a943b96 100644 --- a/src/gallium/drivers/r300/r300_screen_buffer.c +++ b/src/gallium/drivers/r300/r300_screen_buffer.c @@ -201,8 +201,7 @@ struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, rbuf->buf = r300screen->rws->buffer_create(r300screen->rws, rbuf->b.b.b.width0, alignment, - rbuf->b.b.b.bind, rbuf->b.b.b.usage, - rbuf->domain); + rbuf->b.b.b.bind, rbuf->domain); if (!rbuf->buf) { util_slab_free(&r300screen->pool_buffers, rbuf); return NULL; diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c index f63114e7eb7..45c11fce1fe 100644 --- a/src/gallium/drivers/r300/r300_state_derived.c +++ b/src/gallium/drivers/r300/r300_state_derived.c @@ -605,7 +605,6 @@ static uint32_t r300_get_border_color(enum pipe_format format, { const struct util_format_description *desc; float border_swizzled[4] = {0}; - unsigned i; union util_color uc = {0}; desc = util_format_description(format); @@ -629,22 +628,7 @@ static uint32_t r300_get_border_color(enum pipe_format format, } /* Apply inverse swizzle of the format. */ - for (i = 0; i < 4; i++) { - switch (desc->swizzle[i]) { - case UTIL_FORMAT_SWIZZLE_X: - border_swizzled[0] = border[i]; - break; - case UTIL_FORMAT_SWIZZLE_Y: - border_swizzled[1] = border[i]; - break; - case UTIL_FORMAT_SWIZZLE_Z: - border_swizzled[2] = border[i]; - break; - case UTIL_FORMAT_SWIZZLE_W: - border_swizzled[3] = border[i]; - break; - } - } + util_format_unswizzle_4f(border_swizzled, border, desc->swizzle); /* Compressed formats. */ if (util_format_is_compressed(format)) { diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c index 38ca9a24e45..fc84004fb97 100644 --- a/src/gallium/drivers/r300/r300_texture.c +++ b/src/gallium/drivers/r300/r300_texture.c @@ -38,18 +38,6 @@ #include "pipe/p_screen.h" -void util_format_combine_swizzles(unsigned char *dst, - const unsigned char *swz1, - const unsigned char *swz2) -{ - unsigned i; - - for (i = 0; i < 4; i++) { - dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ? - swz1[swz2[i]] : swz2[i]; - } -} - unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format, const unsigned char *swizzle_view, boolean dxtc_swizzle) @@ -72,7 +60,7 @@ unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format, if (swizzle_view) { /* Combine two sets of swizzles. */ - util_format_combine_swizzles(swizzle, swizzle_format, swizzle_view); + util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle); } else { memcpy(swizzle, swizzle_format, 4); } @@ -447,16 +435,8 @@ static uint32_t r300_translate_colorformat(enum pipe_format format) /*case PIPE_FORMAT_B8G8R8A8_SNORM:*/ case PIPE_FORMAT_B8G8R8X8_UNORM: /*case PIPE_FORMAT_B8G8R8X8_SNORM:*/ - case PIPE_FORMAT_A8R8G8B8_UNORM: - /*case PIPE_FORMAT_A8R8G8B8_SNORM:*/ - case PIPE_FORMAT_X8R8G8B8_UNORM: - /*case PIPE_FORMAT_X8R8G8B8_SNORM:*/ - case PIPE_FORMAT_A8B8G8R8_UNORM: - /*case PIPE_FORMAT_A8B8G8R8_SNORM:*/ case PIPE_FORMAT_R8G8B8A8_UNORM: case PIPE_FORMAT_R8G8B8A8_SNORM: - case PIPE_FORMAT_X8B8G8R8_UNORM: - /*case PIPE_FORMAT_X8B8G8R8_SNORM:*/ case PIPE_FORMAT_R8G8B8X8_UNORM: /*case PIPE_FORMAT_R8G8B8X8_SNORM:*/ /* These formats work fine with ARGB8888 if US_OUT_FMT is set @@ -662,10 +642,6 @@ static uint32_t r300_translate_out_fmt(enum pipe_format format) R300_C2_SEL_R | R300_C3_SEL_A; /* ARGB outputs. */ - case PIPE_FORMAT_A8R8G8B8_UNORM: - /*case PIPE_FORMAT_A8R8G8B8_SNORM:*/ - case PIPE_FORMAT_X8R8G8B8_UNORM: - /*case PIPE_FORMAT_X8R8G8B8_SNORM:*/ case PIPE_FORMAT_A16_UNORM: case PIPE_FORMAT_A16_SNORM: case PIPE_FORMAT_A16_FLOAT: @@ -674,15 +650,6 @@ static uint32_t r300_translate_out_fmt(enum pipe_format format) R300_C0_SEL_A | R300_C1_SEL_R | R300_C2_SEL_G | R300_C3_SEL_B; - /* ABGR outputs. */ - case PIPE_FORMAT_A8B8G8R8_UNORM: - /*case PIPE_FORMAT_A8B8G8R8_SNORM:*/ - case PIPE_FORMAT_X8B8G8R8_UNORM: - /*case PIPE_FORMAT_X8B8G8R8_SNORM:*/ - return modifier | - R300_C0_SEL_A | R300_C1_SEL_B | - R300_C2_SEL_G | R300_C3_SEL_R; - /* RGBA outputs. */ case PIPE_FORMAT_R8G8B8X8_UNORM: /*case PIPE_FORMAT_R8G8B8X8_SNORM:*/ @@ -947,7 +914,7 @@ r300_texture_create_object(struct r300_screen *rscreen, if (!buffer) { tex->buf_size = tex->tex.size_in_bytes; tex->buf = rws->buffer_create(rws, tex->tex.size_in_bytes, 2048, - base->bind, base->usage, tex->domain); + base->bind, tex->domain); if (!tex->buf) { FREE(tex); diff --git a/src/gallium/drivers/r300/r300_texture.h b/src/gallium/drivers/r300/r300_texture.h index 4586bb2e4dc..158a387478f 100644 --- a/src/gallium/drivers/r300/r300_texture.h +++ b/src/gallium/drivers/r300/r300_texture.h @@ -35,10 +35,6 @@ struct r300_texture_desc; struct r300_resource; struct r300_screen; -void util_format_combine_swizzles(unsigned char *dst, - const unsigned char *swz1, - const unsigned char *swz2); - unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format, const unsigned char *swizzle_view, boolean dxtc_swizzle); diff --git a/src/gallium/drivers/r300/r300_texture_desc.c b/src/gallium/drivers/r300/r300_texture_desc.c index da5778be65e..fe4f8dd5679 100644 --- a/src/gallium/drivers/r300/r300_texture_desc.c +++ b/src/gallium/drivers/r300/r300_texture_desc.c @@ -360,9 +360,9 @@ static void r300_setup_hyperz_properties(struct r300_screen *screen, unsigned i, pipes; if (screen->caps.family == CHIP_FAMILY_RV530) { - pipes = screen->caps.num_z_pipes; + pipes = screen->info.r300_num_z_pipes; } else { - pipes = screen->caps.num_frag_pipes; + pipes = screen->info.r300_num_gb_pipes; } for (i = 0; i <= tex->b.b.b.last_level; i++) { diff --git a/src/gallium/drivers/r300/r300_tgsi_to_rc.c b/src/gallium/drivers/r300/r300_tgsi_to_rc.c index 0561ab9bfa4..07a3f3caee7 100644 --- a/src/gallium/drivers/r300/r300_tgsi_to_rc.c +++ b/src/gallium/drivers/r300/r300_tgsi_to_rc.c @@ -22,8 +22,7 @@ #include "r300_tgsi_to_rc.h" -#include "radeon_compiler.h" -#include "radeon_program.h" +#include "compiler/radeon_compiler.h" #include "tgsi/tgsi_info.h" #include "tgsi/tgsi_parse.h" diff --git a/src/gallium/drivers/r300/r300_vs.c b/src/gallium/drivers/r300/r300_vs.c index b319890157f..a5e8fd680ff 100644 --- a/src/gallium/drivers/r300/r300_vs.c +++ b/src/gallium/drivers/r300/r300_vs.c @@ -32,7 +32,7 @@ #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_ureg.h" -#include "radeon_compiler.h" +#include "compiler/radeon_compiler.h" /* Convert info about VS output semantics into r300_shader_semantics. */ static void r300_shader_read_vs_outputs( diff --git a/src/gallium/drivers/r300/r300_vs.h b/src/gallium/drivers/r300/r300_vs.h index 170de6c79db..a482ddce9c9 100644 --- a/src/gallium/drivers/r300/r300_vs.h +++ b/src/gallium/drivers/r300/r300_vs.h @@ -26,7 +26,7 @@ #include "pipe/p_state.h" #include "tgsi/tgsi_scan.h" -#include "radeon_code.h" +#include "compiler/radeon_code.h" #include "r300_context.h" #include "r300_shader_semantics.h" diff --git a/src/gallium/drivers/r600/SConscript b/src/gallium/drivers/r600/SConscript index 0135808f10a..19f07b2bef8 100644 --- a/src/gallium/drivers/r600/SConscript +++ b/src/gallium/drivers/r600/SConscript @@ -2,11 +2,7 @@ Import('*') env = env.Clone() -try: - env.ParseConfig('pkg-config --cflags libdrm_radeon') -except OSError: - print 'warning: not building r600' - Return() +env.PkgUseModules('DRM_RADEON') env.Append(CPPPATH = [ '#/include', diff --git a/src/gallium/drivers/r600/eg_asm.c b/src/gallium/drivers/r600/eg_asm.c index fb0b0f104bf..c95872b0809 100644 --- a/src/gallium/drivers/r600/eg_asm.c +++ b/src/gallium/drivers/r600/eg_asm.c @@ -69,7 +69,7 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_W(cf->output.swizzle_w) | S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->output.barrier) | S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->output.inst); - if (bc->chiprev == CHIPREV_EVERGREEN) /* no EOP on cayman */ + if (bc->chip_class == EVERGREEN) /* no EOP on cayman */ bc->bytecode[id] |= S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(cf->output.end_of_program); id++; diff --git a/src/gallium/drivers/r600/eg_state_inlines.h b/src/gallium/drivers/r600/eg_state_inlines.h deleted file mode 100644 index f8891781be8..00000000000 --- a/src/gallium/drivers/r600/eg_state_inlines.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright 2010 Red Hat 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 - * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. - */ -#ifndef EG_STATE_INLINES_H -#define EG_STATE_INLINES_H - -#include "util/u_format.h" -#include "evergreend.h" -#include "r600_formats.h" - -static INLINE uint32_t r600_translate_blend_function(int blend_func) -{ - switch (blend_func) { - case PIPE_BLEND_ADD: - return V_028780_COMB_DST_PLUS_SRC; - case PIPE_BLEND_SUBTRACT: - return V_028780_COMB_SRC_MINUS_DST; - case PIPE_BLEND_REVERSE_SUBTRACT: - return V_028780_COMB_DST_MINUS_SRC; - case PIPE_BLEND_MIN: - return V_028780_COMB_MIN_DST_SRC; - case PIPE_BLEND_MAX: - return V_028780_COMB_MAX_DST_SRC; - default: - R600_ERR("Unknown blend function %d\n", blend_func); - assert(0); - break; - } - return 0; -} - -static INLINE uint32_t r600_translate_blend_factor(int blend_fact) -{ - switch (blend_fact) { - case PIPE_BLENDFACTOR_ONE: - return V_028780_BLEND_ONE; - case PIPE_BLENDFACTOR_SRC_COLOR: - return V_028780_BLEND_SRC_COLOR; - case PIPE_BLENDFACTOR_SRC_ALPHA: - return V_028780_BLEND_SRC_ALPHA; - case PIPE_BLENDFACTOR_DST_ALPHA: - return V_028780_BLEND_DST_ALPHA; - case PIPE_BLENDFACTOR_DST_COLOR: - return V_028780_BLEND_DST_COLOR; - case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - return V_028780_BLEND_SRC_ALPHA_SATURATE; - case PIPE_BLENDFACTOR_CONST_COLOR: - return V_028780_BLEND_CONST_COLOR; - case PIPE_BLENDFACTOR_CONST_ALPHA: - return V_028780_BLEND_CONST_ALPHA; - case PIPE_BLENDFACTOR_ZERO: - return V_028780_BLEND_ZERO; - case PIPE_BLENDFACTOR_INV_SRC_COLOR: - return V_028780_BLEND_ONE_MINUS_SRC_COLOR; - case PIPE_BLENDFACTOR_INV_SRC_ALPHA: - return V_028780_BLEND_ONE_MINUS_SRC_ALPHA; - case PIPE_BLENDFACTOR_INV_DST_ALPHA: - return V_028780_BLEND_ONE_MINUS_DST_ALPHA; - case PIPE_BLENDFACTOR_INV_DST_COLOR: - return V_028780_BLEND_ONE_MINUS_DST_COLOR; - case PIPE_BLENDFACTOR_INV_CONST_COLOR: - return V_028780_BLEND_ONE_MINUS_CONST_COLOR; - case PIPE_BLENDFACTOR_INV_CONST_ALPHA: - return V_028780_BLEND_ONE_MINUS_CONST_ALPHA; - case PIPE_BLENDFACTOR_SRC1_COLOR: - return V_028780_BLEND_SRC1_COLOR; - case PIPE_BLENDFACTOR_SRC1_ALPHA: - return V_028780_BLEND_SRC1_ALPHA; - case PIPE_BLENDFACTOR_INV_SRC1_COLOR: - return V_028780_BLEND_INV_SRC1_COLOR; - case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: - return V_028780_BLEND_INV_SRC1_ALPHA; - default: - R600_ERR("Bad blend factor %d not supported!\n", blend_fact); - assert(0); - break; - } - return 0; -} - -static INLINE uint32_t r600_translate_stencil_op(int s_op) -{ - switch (s_op) { - case PIPE_STENCIL_OP_KEEP: - return V_028800_STENCIL_KEEP; - case PIPE_STENCIL_OP_ZERO: - return V_028800_STENCIL_ZERO; - case PIPE_STENCIL_OP_REPLACE: - return V_028800_STENCIL_REPLACE; - case PIPE_STENCIL_OP_INCR: - return V_028800_STENCIL_INCR; - case PIPE_STENCIL_OP_DECR: - return V_028800_STENCIL_DECR; - case PIPE_STENCIL_OP_INCR_WRAP: - return V_028800_STENCIL_INCR_WRAP; - case PIPE_STENCIL_OP_DECR_WRAP: - return V_028800_STENCIL_DECR_WRAP; - case PIPE_STENCIL_OP_INVERT: - return V_028800_STENCIL_INVERT; - default: - R600_ERR("Unknown stencil op %d", s_op); - assert(0); - break; - } - return 0; -} - -static INLINE uint32_t r600_translate_fill(uint32_t func) -{ - switch(func) { - case PIPE_POLYGON_MODE_FILL: - return 2; - case PIPE_POLYGON_MODE_LINE: - return 1; - case PIPE_POLYGON_MODE_POINT: - return 0; - default: - assert(0); - return 0; - } -} - -/* translates straight */ -static INLINE uint32_t r600_translate_ds_func(int func) -{ - return func; -} - -static inline unsigned r600_tex_wrap(unsigned wrap) -{ - switch (wrap) { - default: - case PIPE_TEX_WRAP_REPEAT: - return V_03C000_SQ_TEX_WRAP; - case PIPE_TEX_WRAP_CLAMP: - return V_03C000_SQ_TEX_CLAMP_HALF_BORDER; - case PIPE_TEX_WRAP_CLAMP_TO_EDGE: - return V_03C000_SQ_TEX_CLAMP_LAST_TEXEL; - case PIPE_TEX_WRAP_CLAMP_TO_BORDER: - return V_03C000_SQ_TEX_CLAMP_BORDER; - case PIPE_TEX_WRAP_MIRROR_REPEAT: - return V_03C000_SQ_TEX_MIRROR; - case PIPE_TEX_WRAP_MIRROR_CLAMP: - return V_03C000_SQ_TEX_MIRROR_ONCE_HALF_BORDER; - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: - return V_03C000_SQ_TEX_MIRROR_ONCE_LAST_TEXEL; - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: - return V_03C000_SQ_TEX_MIRROR_ONCE_BORDER; - } -} - -static inline unsigned r600_tex_filter(unsigned filter) -{ - switch (filter) { - default: - case PIPE_TEX_FILTER_NEAREST: - return V_03C000_SQ_TEX_XY_FILTER_POINT; - case PIPE_TEX_FILTER_LINEAR: - return V_03C000_SQ_TEX_XY_FILTER_BILINEAR; - } -} - -static inline unsigned r600_tex_mipfilter(unsigned filter) -{ - switch (filter) { - case PIPE_TEX_MIPFILTER_NEAREST: - return V_03C000_SQ_TEX_Z_FILTER_POINT; - case PIPE_TEX_MIPFILTER_LINEAR: - return V_03C000_SQ_TEX_Z_FILTER_LINEAR; - default: - case PIPE_TEX_MIPFILTER_NONE: - return V_03C000_SQ_TEX_Z_FILTER_NONE; - } -} - -static inline unsigned r600_tex_compare(unsigned compare) -{ - switch (compare) { - default: - case PIPE_FUNC_NEVER: - return V_03C000_SQ_TEX_DEPTH_COMPARE_NEVER; - case PIPE_FUNC_LESS: - return V_03C000_SQ_TEX_DEPTH_COMPARE_LESS; - case PIPE_FUNC_EQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_EQUAL; - case PIPE_FUNC_LEQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_LESSEQUAL; - case PIPE_FUNC_GREATER: - return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATER; - case PIPE_FUNC_NOTEQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_NOTEQUAL; - case PIPE_FUNC_GEQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATEREQUAL; - case PIPE_FUNC_ALWAYS: - return V_03C000_SQ_TEX_DEPTH_COMPARE_ALWAYS; - } -} - -static inline unsigned r600_tex_swizzle(unsigned swizzle) -{ - switch (swizzle) { - case PIPE_SWIZZLE_RED: - return V_030010_SQ_SEL_X; - case PIPE_SWIZZLE_GREEN: - return V_030010_SQ_SEL_Y; - case PIPE_SWIZZLE_BLUE: - return V_030010_SQ_SEL_Z; - case PIPE_SWIZZLE_ALPHA: - return V_030010_SQ_SEL_W; - case PIPE_SWIZZLE_ZERO: - return V_030010_SQ_SEL_0; - default: - case PIPE_SWIZZLE_ONE: - return V_030010_SQ_SEL_1; - } -} - -static inline unsigned r600_format_type(unsigned format_type) -{ - switch (format_type) { - default: - case UTIL_FORMAT_TYPE_UNSIGNED: - return V_030010_SQ_FORMAT_COMP_UNSIGNED; - case UTIL_FORMAT_TYPE_SIGNED: - return V_030010_SQ_FORMAT_COMP_SIGNED; - case UTIL_FORMAT_TYPE_FIXED: - return V_030010_SQ_FORMAT_COMP_UNSIGNED_BIASED; - } -} - -static inline unsigned r600_tex_dim(unsigned dim) -{ - switch (dim) { - default: - case PIPE_TEXTURE_1D: - return V_030000_SQ_TEX_DIM_1D; - case PIPE_TEXTURE_1D_ARRAY: - return V_030000_SQ_TEX_DIM_1D_ARRAY; - case PIPE_TEXTURE_2D: - case PIPE_TEXTURE_RECT: - return V_030000_SQ_TEX_DIM_2D; - case PIPE_TEXTURE_2D_ARRAY: - return V_030000_SQ_TEX_DIM_2D_ARRAY; - case PIPE_TEXTURE_3D: - return V_030000_SQ_TEX_DIM_3D; - case PIPE_TEXTURE_CUBE: - return V_030000_SQ_TEX_DIM_CUBEMAP; - } -} - -static inline uint32_t r600_translate_dbformat(enum pipe_format format) -{ - switch (format) { - case PIPE_FORMAT_Z16_UNORM: - return V_028040_Z_16; - case PIPE_FORMAT_Z24X8_UNORM: - return V_028040_Z_24; - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_028040_Z_24; - default: - return ~0; - } -} - -static inline uint32_t r600_translate_stencilformat(enum pipe_format format) -{ - if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) - return 1; - else - return 0; -} - -static inline uint32_t r600_translate_colorswap(enum pipe_format format) -{ - switch (format) { - /* 8-bit buffers. */ - case PIPE_FORMAT_L4A4_UNORM: - return V_028C70_SWAP_ALT; - - case PIPE_FORMAT_A8_UNORM: - return V_028C70_SWAP_ALT_REV; - case PIPE_FORMAT_I8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_L8_SRGB: - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R8_SNORM: - return V_028C70_SWAP_STD; - - /* 16-bit buffers. */ - case PIPE_FORMAT_B5G6R5_UNORM: - return V_028C70_SWAP_STD_REV; - - case PIPE_FORMAT_B5G5R5A1_UNORM: - case PIPE_FORMAT_B5G5R5X1_UNORM: - return V_028C70_SWAP_ALT; - - case PIPE_FORMAT_B4G4R4A4_UNORM: - case PIPE_FORMAT_B4G4R4X4_UNORM: - return V_028C70_SWAP_ALT; - - case PIPE_FORMAT_Z16_UNORM: - return V_028C70_SWAP_STD; - - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_L8A8_SRGB: - return V_028C70_SWAP_ALT; - case PIPE_FORMAT_R8G8_UNORM: - return V_028C70_SWAP_STD; - - case PIPE_FORMAT_R16_UNORM: - return V_028C70_SWAP_STD; - - /* 32-bit buffers. */ - case PIPE_FORMAT_A8B8G8R8_SRGB: - return V_028C70_SWAP_STD_REV; - case PIPE_FORMAT_B8G8R8A8_SRGB: - return V_028C70_SWAP_ALT; - - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - return V_028C70_SWAP_ALT; - - case PIPE_FORMAT_A8R8G8B8_UNORM: - case PIPE_FORMAT_X8R8G8B8_UNORM: - return V_028C70_SWAP_ALT_REV; - case PIPE_FORMAT_R8G8B8A8_SNORM: - case PIPE_FORMAT_R8G8B8X8_UNORM: - return V_028C70_SWAP_STD; - - case PIPE_FORMAT_A8B8G8R8_UNORM: - case PIPE_FORMAT_X8B8G8R8_UNORM: - /* case PIPE_FORMAT_R8SG8SB8UX8U_NORM: */ - return V_028C70_SWAP_STD_REV; - - case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_028C70_SWAP_STD; - - case PIPE_FORMAT_X8Z24_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - return V_028C70_SWAP_STD; - - case PIPE_FORMAT_R10G10B10A2_UNORM: - case PIPE_FORMAT_R10G10B10X2_SNORM: - case PIPE_FORMAT_R10SG10SB10SA2U_NORM: - return V_028C70_SWAP_STD; - - case PIPE_FORMAT_B10G10R10A2_UNORM: - return V_028C70_SWAP_ALT; - - case PIPE_FORMAT_R11G11B10_FLOAT: - case PIPE_FORMAT_R32_FLOAT: - case PIPE_FORMAT_R16G16_FLOAT: - case PIPE_FORMAT_R16G16_UNORM: - return V_028C70_SWAP_STD; - - /* 64-bit buffers. */ - case PIPE_FORMAT_R32G32_FLOAT: - case PIPE_FORMAT_R16G16B16A16_UNORM: - case PIPE_FORMAT_R16G16B16A16_SNORM: - case PIPE_FORMAT_R16G16B16A16_FLOAT: - - /* 128-bit buffers. */ - case PIPE_FORMAT_R32G32B32A32_FLOAT: - case PIPE_FORMAT_R32G32B32A32_SNORM: - case PIPE_FORMAT_R32G32B32A32_UNORM: - return V_028C70_SWAP_STD; - default: - R600_ERR("unsupported colorswap format %d\n", format); - return ~0; - } - return ~0; -} - -static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) -{ - switch (format) { - /* 8-bit buffers. */ - case PIPE_FORMAT_L4A4_UNORM: - return V_028C70_COLOR_4_4; - - case PIPE_FORMAT_A8_UNORM: - case PIPE_FORMAT_I8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_L8_SRGB: - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R8_SNORM: - return V_028C70_COLOR_8; - - /* 16-bit buffers. */ - case PIPE_FORMAT_B5G6R5_UNORM: - return V_028C70_COLOR_5_6_5; - - case PIPE_FORMAT_B5G5R5A1_UNORM: - case PIPE_FORMAT_B5G5R5X1_UNORM: - return V_028C70_COLOR_1_5_5_5; - - case PIPE_FORMAT_B4G4R4A4_UNORM: - case PIPE_FORMAT_B4G4R4X4_UNORM: - return V_028C70_COLOR_4_4_4_4; - - case PIPE_FORMAT_Z16_UNORM: - return V_028C70_COLOR_16; - - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_L8A8_SRGB: - case PIPE_FORMAT_R8G8_UNORM: - return V_028C70_COLOR_8_8; - - case PIPE_FORMAT_R16_UNORM: - return V_028C70_COLOR_16; - - /* 32-bit buffers. */ - case PIPE_FORMAT_A8B8G8R8_SRGB: - case PIPE_FORMAT_A8B8G8R8_UNORM: - case PIPE_FORMAT_A8R8G8B8_UNORM: - case PIPE_FORMAT_B8G8R8A8_SRGB: - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_R8G8B8A8_SNORM: - case PIPE_FORMAT_R8G8B8A8_UNORM: - case PIPE_FORMAT_R8G8B8X8_UNORM: - case PIPE_FORMAT_R8SG8SB8UX8U_NORM: - case PIPE_FORMAT_X8B8G8R8_UNORM: - case PIPE_FORMAT_X8R8G8B8_UNORM: - case PIPE_FORMAT_R8G8B8_UNORM: - return V_028C70_COLOR_8_8_8_8; - - case PIPE_FORMAT_R10G10B10A2_UNORM: - case PIPE_FORMAT_R10G10B10X2_SNORM: - case PIPE_FORMAT_B10G10R10A2_UNORM: - case PIPE_FORMAT_R10SG10SB10SA2U_NORM: - return V_028C70_COLOR_2_10_10_10; - - case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_028C70_COLOR_8_24; - - case PIPE_FORMAT_X8Z24_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - return V_028C70_COLOR_24_8; - - case PIPE_FORMAT_R32_FLOAT: - return V_028C70_COLOR_32_FLOAT; - - case PIPE_FORMAT_R16G16_FLOAT: - return V_028C70_COLOR_16_16_FLOAT; - - case PIPE_FORMAT_R16G16_SSCALED: - case PIPE_FORMAT_R16G16_UNORM: - return V_028C70_COLOR_16_16; - - case PIPE_FORMAT_R11G11B10_FLOAT: - return V_028C70_COLOR_10_11_11_FLOAT; - - /* 64-bit buffers. */ - case PIPE_FORMAT_R16G16B16_USCALED: - case PIPE_FORMAT_R16G16B16A16_USCALED: - case PIPE_FORMAT_R16G16B16_SSCALED: - case PIPE_FORMAT_R16G16B16A16_SSCALED: - case PIPE_FORMAT_R16G16B16A16_UNORM: - case PIPE_FORMAT_R16G16B16A16_SNORM: - return V_028C70_COLOR_16_16_16_16; - - case PIPE_FORMAT_R16G16B16_FLOAT: - case PIPE_FORMAT_R16G16B16A16_FLOAT: - return V_028C70_COLOR_16_16_16_16_FLOAT; - - case PIPE_FORMAT_R32G32_FLOAT: - return V_028C70_COLOR_32_32_FLOAT; - - case PIPE_FORMAT_R32G32_USCALED: - case PIPE_FORMAT_R32G32_SSCALED: - return V_028C70_COLOR_32_32; - - /* 96-bit buffers. */ - case PIPE_FORMAT_R32G32B32_FLOAT: - return V_028C70_COLOR_32_32_32_FLOAT; - - /* 128-bit buffers. */ - case PIPE_FORMAT_R32G32B32A32_SNORM: - case PIPE_FORMAT_R32G32B32A32_UNORM: - return V_028C70_COLOR_32_32_32_32; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - return V_028C70_COLOR_32_32_32_32_FLOAT; - - /* YUV buffers. */ - case PIPE_FORMAT_UYVY: - case PIPE_FORMAT_YUYV: - default: - return ~0; /* Unsupported. */ - } -} - -static INLINE uint32_t r600_colorformat_endian_swap(uint32_t colorformat) -{ - if (R600_BIG_ENDIAN) { - switch(colorformat) { - case V_028C70_COLOR_4_4: - return(ENDIAN_NONE); - - /* 8-bit buffers. */ - case V_028C70_COLOR_8: - return(ENDIAN_NONE); - - /* 16-bit buffers. */ - case V_028C70_COLOR_5_6_5: - case V_028C70_COLOR_1_5_5_5: - case V_028C70_COLOR_4_4_4_4: - case V_028C70_COLOR_16: - case V_028C70_COLOR_8_8: - return(ENDIAN_8IN16); - - /* 32-bit buffers. */ - case V_028C70_COLOR_8_8_8_8: - case V_028C70_COLOR_2_10_10_10: - case V_028C70_COLOR_8_24: - case V_028C70_COLOR_24_8: - case V_028C70_COLOR_32_FLOAT: - case V_028C70_COLOR_16_16_FLOAT: - case V_028C70_COLOR_16_16: - return(ENDIAN_8IN32); - - /* 64-bit buffers. */ - case V_028C70_COLOR_16_16_16_16: - case V_028C70_COLOR_16_16_16_16_FLOAT: - return(ENDIAN_8IN16); - - case V_028C70_COLOR_32_32_FLOAT: - case V_028C70_COLOR_32_32: - return(ENDIAN_8IN32); - - /* 96-bit buffers. */ - case V_028C70_COLOR_32_32_32_FLOAT: - /* 128-bit buffers. */ - case V_028C70_COLOR_32_32_32_32_FLOAT: - case V_028C70_COLOR_32_32_32_32: - return(ENDIAN_8IN32); - default: - return ENDIAN_NONE; /* Unsupported. */ - } - } else { - return ENDIAN_NONE; - } -} - -static INLINE boolean r600_is_sampler_format_supported(struct pipe_screen *screen, enum pipe_format format) -{ - return r600_translate_texformat(screen, format, NULL, NULL, NULL) != ~0; -} - -static INLINE boolean r600_is_colorbuffer_format_supported(enum pipe_format format) -{ - return r600_translate_colorformat(format) != ~0 && - r600_translate_colorswap(format) != ~0; -} - -static INLINE boolean r600_is_zs_format_supported(enum pipe_format format) -{ - return r600_translate_dbformat(format) != ~0; -} - -#endif diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c index f86e4d4e3af..c9eaf94a2ae 100644 --- a/src/gallium/drivers/r600/evergreen_state.c +++ b/src/gallium/drivers/r600/evergreen_state.c @@ -46,7 +46,587 @@ #include "r600_resource.h" #include "r600_shader.h" #include "r600_pipe.h" -#include "eg_state_inlines.h" +#include "r600_formats.h" + +static uint32_t r600_translate_blend_function(int blend_func) +{ + switch (blend_func) { + case PIPE_BLEND_ADD: + return V_028780_COMB_DST_PLUS_SRC; + case PIPE_BLEND_SUBTRACT: + return V_028780_COMB_SRC_MINUS_DST; + case PIPE_BLEND_REVERSE_SUBTRACT: + return V_028780_COMB_DST_MINUS_SRC; + case PIPE_BLEND_MIN: + return V_028780_COMB_MIN_DST_SRC; + case PIPE_BLEND_MAX: + return V_028780_COMB_MAX_DST_SRC; + default: + R600_ERR("Unknown blend function %d\n", blend_func); + assert(0); + break; + } + return 0; +} + +static uint32_t r600_translate_blend_factor(int blend_fact) +{ + switch (blend_fact) { + case PIPE_BLENDFACTOR_ONE: + return V_028780_BLEND_ONE; + case PIPE_BLENDFACTOR_SRC_COLOR: + return V_028780_BLEND_SRC_COLOR; + case PIPE_BLENDFACTOR_SRC_ALPHA: + return V_028780_BLEND_SRC_ALPHA; + case PIPE_BLENDFACTOR_DST_ALPHA: + return V_028780_BLEND_DST_ALPHA; + case PIPE_BLENDFACTOR_DST_COLOR: + return V_028780_BLEND_DST_COLOR; + case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: + return V_028780_BLEND_SRC_ALPHA_SATURATE; + case PIPE_BLENDFACTOR_CONST_COLOR: + return V_028780_BLEND_CONST_COLOR; + case PIPE_BLENDFACTOR_CONST_ALPHA: + return V_028780_BLEND_CONST_ALPHA; + case PIPE_BLENDFACTOR_ZERO: + return V_028780_BLEND_ZERO; + case PIPE_BLENDFACTOR_INV_SRC_COLOR: + return V_028780_BLEND_ONE_MINUS_SRC_COLOR; + case PIPE_BLENDFACTOR_INV_SRC_ALPHA: + return V_028780_BLEND_ONE_MINUS_SRC_ALPHA; + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + return V_028780_BLEND_ONE_MINUS_DST_ALPHA; + case PIPE_BLENDFACTOR_INV_DST_COLOR: + return V_028780_BLEND_ONE_MINUS_DST_COLOR; + case PIPE_BLENDFACTOR_INV_CONST_COLOR: + return V_028780_BLEND_ONE_MINUS_CONST_COLOR; + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + return V_028780_BLEND_ONE_MINUS_CONST_ALPHA; + case PIPE_BLENDFACTOR_SRC1_COLOR: + return V_028780_BLEND_SRC1_COLOR; + case PIPE_BLENDFACTOR_SRC1_ALPHA: + return V_028780_BLEND_SRC1_ALPHA; + case PIPE_BLENDFACTOR_INV_SRC1_COLOR: + return V_028780_BLEND_INV_SRC1_COLOR; + case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: + return V_028780_BLEND_INV_SRC1_ALPHA; + default: + R600_ERR("Bad blend factor %d not supported!\n", blend_fact); + assert(0); + break; + } + return 0; +} + +static uint32_t r600_translate_stencil_op(int s_op) +{ + switch (s_op) { + case PIPE_STENCIL_OP_KEEP: + return V_028800_STENCIL_KEEP; + case PIPE_STENCIL_OP_ZERO: + return V_028800_STENCIL_ZERO; + case PIPE_STENCIL_OP_REPLACE: + return V_028800_STENCIL_REPLACE; + case PIPE_STENCIL_OP_INCR: + return V_028800_STENCIL_INCR; + case PIPE_STENCIL_OP_DECR: + return V_028800_STENCIL_DECR; + case PIPE_STENCIL_OP_INCR_WRAP: + return V_028800_STENCIL_INCR_WRAP; + case PIPE_STENCIL_OP_DECR_WRAP: + return V_028800_STENCIL_DECR_WRAP; + case PIPE_STENCIL_OP_INVERT: + return V_028800_STENCIL_INVERT; + default: + R600_ERR("Unknown stencil op %d", s_op); + assert(0); + break; + } + return 0; +} + +static uint32_t r600_translate_fill(uint32_t func) +{ + switch(func) { + case PIPE_POLYGON_MODE_FILL: + return 2; + case PIPE_POLYGON_MODE_LINE: + return 1; + case PIPE_POLYGON_MODE_POINT: + return 0; + default: + assert(0); + return 0; + } +} + +/* translates straight */ +static uint32_t r600_translate_ds_func(int func) +{ + return func; +} + +static unsigned r600_tex_wrap(unsigned wrap) +{ + switch (wrap) { + default: + case PIPE_TEX_WRAP_REPEAT: + return V_03C000_SQ_TEX_WRAP; + case PIPE_TEX_WRAP_CLAMP: + return V_03C000_SQ_TEX_CLAMP_HALF_BORDER; + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return V_03C000_SQ_TEX_CLAMP_LAST_TEXEL; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + return V_03C000_SQ_TEX_CLAMP_BORDER; + case PIPE_TEX_WRAP_MIRROR_REPEAT: + return V_03C000_SQ_TEX_MIRROR; + case PIPE_TEX_WRAP_MIRROR_CLAMP: + return V_03C000_SQ_TEX_MIRROR_ONCE_HALF_BORDER; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + return V_03C000_SQ_TEX_MIRROR_ONCE_LAST_TEXEL; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + return V_03C000_SQ_TEX_MIRROR_ONCE_BORDER; + } +} + +static unsigned r600_tex_filter(unsigned filter) +{ + switch (filter) { + default: + case PIPE_TEX_FILTER_NEAREST: + return V_03C000_SQ_TEX_XY_FILTER_POINT; + case PIPE_TEX_FILTER_LINEAR: + return V_03C000_SQ_TEX_XY_FILTER_BILINEAR; + } +} + +static unsigned r600_tex_mipfilter(unsigned filter) +{ + switch (filter) { + case PIPE_TEX_MIPFILTER_NEAREST: + return V_03C000_SQ_TEX_Z_FILTER_POINT; + case PIPE_TEX_MIPFILTER_LINEAR: + return V_03C000_SQ_TEX_Z_FILTER_LINEAR; + default: + case PIPE_TEX_MIPFILTER_NONE: + return V_03C000_SQ_TEX_Z_FILTER_NONE; + } +} + +static unsigned r600_tex_compare(unsigned compare) +{ + switch (compare) { + default: + case PIPE_FUNC_NEVER: + return V_03C000_SQ_TEX_DEPTH_COMPARE_NEVER; + case PIPE_FUNC_LESS: + return V_03C000_SQ_TEX_DEPTH_COMPARE_LESS; + case PIPE_FUNC_EQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_EQUAL; + case PIPE_FUNC_LEQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_LESSEQUAL; + case PIPE_FUNC_GREATER: + return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATER; + case PIPE_FUNC_NOTEQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_NOTEQUAL; + case PIPE_FUNC_GEQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATEREQUAL; + case PIPE_FUNC_ALWAYS: + return V_03C000_SQ_TEX_DEPTH_COMPARE_ALWAYS; + } +} + +static unsigned r600_tex_dim(unsigned dim) +{ + switch (dim) { + default: + case PIPE_TEXTURE_1D: + return V_030000_SQ_TEX_DIM_1D; + case PIPE_TEXTURE_1D_ARRAY: + return V_030000_SQ_TEX_DIM_1D_ARRAY; + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: + return V_030000_SQ_TEX_DIM_2D; + case PIPE_TEXTURE_2D_ARRAY: + return V_030000_SQ_TEX_DIM_2D_ARRAY; + case PIPE_TEXTURE_3D: + return V_030000_SQ_TEX_DIM_3D; + case PIPE_TEXTURE_CUBE: + return V_030000_SQ_TEX_DIM_CUBEMAP; + } +} + +static uint32_t r600_translate_dbformat(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_Z16_UNORM: + return V_028040_Z_16; + case PIPE_FORMAT_Z24X8_UNORM: + return V_028040_Z_24; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return V_028040_Z_24; + default: + return ~0U; + } +} + +static uint32_t r600_translate_stencilformat(enum pipe_format format) +{ + if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) + return 1; + else + return 0; +} + +static uint32_t r600_translate_colorswap(enum pipe_format format) +{ + switch (format) { + /* 8-bit buffers. */ + case PIPE_FORMAT_L4A4_UNORM: + return V_028C70_SWAP_ALT; + + case PIPE_FORMAT_A8_UNORM: + return V_028C70_SWAP_ALT_REV; + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SRGB: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + return V_028C70_SWAP_STD; + + /* 16-bit buffers. */ + case PIPE_FORMAT_B5G6R5_UNORM: + return V_028C70_SWAP_STD_REV; + + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B5G5R5X1_UNORM: + return V_028C70_SWAP_ALT; + + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + return V_028C70_SWAP_ALT; + + case PIPE_FORMAT_Z16_UNORM: + return V_028C70_SWAP_STD; + + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_L8A8_SRGB: + return V_028C70_SWAP_ALT; + case PIPE_FORMAT_R8G8_UNORM: + return V_028C70_SWAP_STD; + + case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16_FLOAT: + return V_028C70_SWAP_STD; + + /* 32-bit buffers. */ + case PIPE_FORMAT_A8B8G8R8_SRGB: + return V_028C70_SWAP_STD_REV; + case PIPE_FORMAT_B8G8R8A8_SRGB: + return V_028C70_SWAP_ALT; + + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + return V_028C70_SWAP_ALT; + + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + return V_028C70_SWAP_ALT_REV; + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + return V_028C70_SWAP_STD; + + case PIPE_FORMAT_A8B8G8R8_UNORM: + case PIPE_FORMAT_X8B8G8R8_UNORM: + /* case PIPE_FORMAT_R8SG8SB8UX8U_NORM: */ + return V_028C70_SWAP_STD_REV; + + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return V_028C70_SWAP_STD; + + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + return V_028C70_SWAP_STD; + + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + case PIPE_FORMAT_R10SG10SB10SA2U_NORM: + return V_028C70_SWAP_STD; + + case PIPE_FORMAT_B10G10R10A2_UNORM: + return V_028C70_SWAP_ALT; + + case PIPE_FORMAT_R11G11B10_FLOAT: + case PIPE_FORMAT_R32_FLOAT: + case PIPE_FORMAT_R16G16_FLOAT: + case PIPE_FORMAT_R16G16_UNORM: + return V_028C70_SWAP_STD; + + /* 64-bit buffers. */ + case PIPE_FORMAT_R32G32_FLOAT: + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + + /* 128-bit buffers. */ + case PIPE_FORMAT_R32G32B32A32_FLOAT: + case PIPE_FORMAT_R32G32B32A32_SNORM: + case PIPE_FORMAT_R32G32B32A32_UNORM: + return V_028C70_SWAP_STD; + default: + R600_ERR("unsupported colorswap format %d\n", format); + return ~0U; + } + return ~0U; +} + +static uint32_t r600_translate_colorformat(enum pipe_format format) +{ + switch (format) { + /* 8-bit buffers. */ + case PIPE_FORMAT_L4A4_UNORM: + return V_028C70_COLOR_4_4; + + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SRGB: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + return V_028C70_COLOR_8; + + /* 16-bit buffers. */ + case PIPE_FORMAT_B5G6R5_UNORM: + return V_028C70_COLOR_5_6_5; + + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B5G5R5X1_UNORM: + return V_028C70_COLOR_1_5_5_5; + + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + return V_028C70_COLOR_4_4_4_4; + + case PIPE_FORMAT_Z16_UNORM: + return V_028C70_COLOR_16; + + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_L8A8_SRGB: + case PIPE_FORMAT_R8G8_UNORM: + return V_028C70_COLOR_8_8; + + case PIPE_FORMAT_R16_UNORM: + return V_028C70_COLOR_16; + + case PIPE_FORMAT_R16_FLOAT: + return V_028C70_COLOR_16_FLOAT; + + /* 32-bit buffers. */ + case PIPE_FORMAT_A8B8G8R8_SRGB: + case PIPE_FORMAT_A8B8G8R8_UNORM: + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_B8G8R8A8_SRGB: + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + case PIPE_FORMAT_R8SG8SB8UX8U_NORM: + case PIPE_FORMAT_X8B8G8R8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_R8G8B8_UNORM: + return V_028C70_COLOR_8_8_8_8; + + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + case PIPE_FORMAT_B10G10R10A2_UNORM: + case PIPE_FORMAT_R10SG10SB10SA2U_NORM: + return V_028C70_COLOR_2_10_10_10; + + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return V_028C70_COLOR_8_24; + + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + return V_028C70_COLOR_24_8; + + case PIPE_FORMAT_R32_FLOAT: + return V_028C70_COLOR_32_FLOAT; + + case PIPE_FORMAT_R16G16_FLOAT: + return V_028C70_COLOR_16_16_FLOAT; + + case PIPE_FORMAT_R16G16_SSCALED: + case PIPE_FORMAT_R16G16_UNORM: + return V_028C70_COLOR_16_16; + + case PIPE_FORMAT_R11G11B10_FLOAT: + return V_028C70_COLOR_10_11_11_FLOAT; + + /* 64-bit buffers. */ + case PIPE_FORMAT_R16G16B16_USCALED: + case PIPE_FORMAT_R16G16B16A16_USCALED: + case PIPE_FORMAT_R16G16B16_SSCALED: + case PIPE_FORMAT_R16G16B16A16_SSCALED: + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + return V_028C70_COLOR_16_16_16_16; + + case PIPE_FORMAT_R16G16B16_FLOAT: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + return V_028C70_COLOR_16_16_16_16_FLOAT; + + case PIPE_FORMAT_R32G32_FLOAT: + return V_028C70_COLOR_32_32_FLOAT; + + case PIPE_FORMAT_R32G32_USCALED: + case PIPE_FORMAT_R32G32_SSCALED: + return V_028C70_COLOR_32_32; + + /* 96-bit buffers. */ + case PIPE_FORMAT_R32G32B32_FLOAT: + return V_028C70_COLOR_32_32_32_FLOAT; + + /* 128-bit buffers. */ + case PIPE_FORMAT_R32G32B32A32_SNORM: + case PIPE_FORMAT_R32G32B32A32_UNORM: + return V_028C70_COLOR_32_32_32_32; + case PIPE_FORMAT_R32G32B32A32_FLOAT: + return V_028C70_COLOR_32_32_32_32_FLOAT; + + /* YUV buffers. */ + case PIPE_FORMAT_UYVY: + case PIPE_FORMAT_YUYV: + default: + return ~0U; /* Unsupported. */ + } +} + +static uint32_t r600_colorformat_endian_swap(uint32_t colorformat) +{ + if (R600_BIG_ENDIAN) { + switch(colorformat) { + case V_028C70_COLOR_4_4: + return ENDIAN_NONE; + + /* 8-bit buffers. */ + case V_028C70_COLOR_8: + return ENDIAN_NONE; + + /* 16-bit buffers. */ + case V_028C70_COLOR_5_6_5: + case V_028C70_COLOR_1_5_5_5: + case V_028C70_COLOR_4_4_4_4: + case V_028C70_COLOR_16: + case V_028C70_COLOR_8_8: + return ENDIAN_8IN16; + + /* 32-bit buffers. */ + case V_028C70_COLOR_8_8_8_8: + case V_028C70_COLOR_2_10_10_10: + case V_028C70_COLOR_8_24: + case V_028C70_COLOR_24_8: + case V_028C70_COLOR_32_FLOAT: + case V_028C70_COLOR_16_16_FLOAT: + case V_028C70_COLOR_16_16: + return ENDIAN_8IN32; + + /* 64-bit buffers. */ + case V_028C70_COLOR_16_16_16_16: + case V_028C70_COLOR_16_16_16_16_FLOAT: + return ENDIAN_8IN16; + + case V_028C70_COLOR_32_32_FLOAT: + case V_028C70_COLOR_32_32: + return ENDIAN_8IN32; + + /* 96-bit buffers. */ + case V_028C70_COLOR_32_32_32_FLOAT: + /* 128-bit buffers. */ + case V_028C70_COLOR_32_32_32_32_FLOAT: + case V_028C70_COLOR_32_32_32_32: + return ENDIAN_8IN32; + default: + return ENDIAN_NONE; /* Unsupported. */ + } + } else { + return ENDIAN_NONE; + } +} + +static bool r600_is_sampler_format_supported(struct pipe_screen *screen, enum pipe_format format) +{ + return r600_translate_texformat(screen, format, NULL, NULL, NULL) != ~0U; +} + +static bool r600_is_colorbuffer_format_supported(enum pipe_format format) +{ + return r600_translate_colorformat(format) != ~0U && + r600_translate_colorswap(format) != ~0U; +} + +static bool r600_is_zs_format_supported(enum pipe_format format) +{ + return r600_translate_dbformat(format) != ~0U; +} + +boolean evergreen_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned usage) +{ + unsigned retval = 0; + + if (target >= PIPE_MAX_TEXTURE_TYPES) { + R600_ERR("r600: unsupported texture type %d\n", target); + return FALSE; + } + + if (!util_format_is_supported(format, usage)) + return FALSE; + + /* Multisample */ + if (sample_count > 1) + return FALSE; + + if ((usage & PIPE_BIND_SAMPLER_VIEW) && + r600_is_sampler_format_supported(screen, format)) { + retval |= PIPE_BIND_SAMPLER_VIEW; + } + + if ((usage & (PIPE_BIND_RENDER_TARGET | + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED)) && + r600_is_colorbuffer_format_supported(format)) { + retval |= usage & + (PIPE_BIND_RENDER_TARGET | + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED); + } + + if ((usage & PIPE_BIND_DEPTH_STENCIL) && + r600_is_zs_format_supported(format)) { + retval |= PIPE_BIND_DEPTH_STENCIL; + } + + if ((usage & PIPE_BIND_VERTEX_BUFFER) && + r600_is_vertex_format_supported(format)) { + retval |= PIPE_BIND_VERTEX_BUFFER; + } + + if (usage & PIPE_BIND_TRANSFER_READ) + retval |= PIPE_BIND_TRANSFER_READ; + if (usage & PIPE_BIND_TRANSFER_WRITE) + retval |= PIPE_BIND_TRANSFER_WRITE; + + return retval == usage; +} static void evergreen_set_blend_color(struct pipe_context *ctx, const struct pipe_blend_color *state) @@ -77,13 +657,11 @@ static void *evergreen_create_blend_state(struct pipe_context *ctx, u32 color_control, target_mask; /* FIXME there is more then 8 framebuffer */ unsigned blend_cntl[8]; - enum radeon_family family; if (blend == NULL) { return NULL; } - family = r600_get_family(rctx->radeon); rstate = &blend->rstate; rstate->id = R600_PIPE_STATE_BLEND; @@ -110,7 +688,7 @@ static void *evergreen_create_blend_state(struct pipe_context *ctx, r600_pipe_state_add_reg(rstate, R_028808_CB_COLOR_CONTROL, color_control, 0xFFFFFFFD, NULL); - if (family != CHIP_CAYMAN) + if (rctx->chip_class != CAYMAN) r600_pipe_state_add_reg(rstate, R_028C3C_PA_SC_AA_MASK, 0xFFFFFFFF, 0xFFFFFFFF, NULL); else { r600_pipe_state_add_reg(rstate, CM_R_028C38_PA_SC_AA_MASK_X0Y0_X1Y0, 0xFFFFFFFF, 0xFFFFFFFF, NULL); @@ -247,15 +825,14 @@ static void *evergreen_create_rs_state(struct pipe_context *ctx, unsigned tmp; unsigned prov_vtx = 1, polygon_dual_mode; unsigned clip_rule; - enum radeon_family family; - - family = r600_get_family(rctx->radeon); if (rs == NULL) { return NULL; } rstate = &rs->rstate; + rs->clamp_vertex_color = state->clamp_vertex_color; + rs->clamp_fragment_color = state->clamp_fragment_color; rs->flatshade = state->flatshade; rs->sprite_coord_enable = state->sprite_coord_enable; @@ -306,7 +883,7 @@ static void *evergreen_create_rs_state(struct pipe_context *ctx, tmp = (unsigned)state->line_width * 8; r600_pipe_state_add_reg(rstate, R_028A08_PA_SU_LINE_CNTL, S_028A08_WIDTH(tmp), 0xFFFFFFFF, NULL); - if (family == CHIP_CAYMAN) { + if (rctx->chip_class == CAYMAN) { r600_pipe_state_add_reg(rstate, CM_R_028BDC_PA_SC_LINE_CNTL, 0x00000400, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, CM_R_028BE4_PA_SU_VTX_CNTL, S_028C08_PIX_CENTER_HALF(state->gl_rasterization_rules), @@ -446,8 +1023,8 @@ static struct pipe_sampler_view *evergreen_create_sampler_view(struct pipe_conte rstate->val[1] = (S_030004_TEX_HEIGHT(texture->height0 - 1) | S_030004_TEX_DEPTH(texture->depth0 - 1) | S_030004_ARRAY_MODE(array_mode)); - rstate->val[2] = (tmp->offset[0] + r600_bo_offset(bo[0])) >> 8; - rstate->val[3] = (tmp->offset[1] + r600_bo_offset(bo[1])) >> 8; + rstate->val[2] = tmp->offset[0] >> 8; + rstate->val[3] = tmp->offset[1] >> 8; rstate->val[4] = (word4 | S_030010_SRF_MODE_ALL(V_030010_SRF_MODE_ZERO_CLAMP_MINUS_ONE) | S_030010_ENDIAN_SWAP(endian) | @@ -777,7 +1354,7 @@ static void evergreen_cb(struct r600_pipe_context *rctx, struct r600_pipe_state /* FIXME handle enabling of CB beyond BASE8 which has different offset */ r600_pipe_state_add_reg(rstate, R_028C60_CB_COLOR0_BASE + cb * 0x3C, - (offset + r600_bo_offset(bo[0])) >> 8, 0xFFFFFFFF, bo[0]); + offset >> 8, 0xFFFFFFFF, bo[0]); r600_pipe_state_add_reg(rstate, R_028C78_CB_COLOR0_DIM + cb * 0x3C, 0x0, 0xFFFFFFFF, NULL); @@ -830,18 +1407,18 @@ static void evergreen_db(struct r600_pipe_context *rctx, struct r600_pipe_state stencil_format = r600_translate_stencilformat(state->zsbuf->texture->format); r600_pipe_state_add_reg(rstate, R_028048_DB_Z_READ_BASE, - (offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo); + offset >> 8, 0xFFFFFFFF, rbuffer->bo); r600_pipe_state_add_reg(rstate, R_028050_DB_Z_WRITE_BASE, - (offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo); + offset >> 8, 0xFFFFFFFF, rbuffer->bo); if (stencil_format) { uint32_t stencil_offset; stencil_offset = ((surf->aligned_height * rtex->pitch_in_bytes[level]) + 255) & ~255; r600_pipe_state_add_reg(rstate, R_02804C_DB_STENCIL_READ_BASE, - (offset + stencil_offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo); + (offset + stencil_offset) >> 8, 0xFFFFFFFF, rbuffer->bo); r600_pipe_state_add_reg(rstate, R_028054_DB_STENCIL_WRITE_BASE, - (offset + stencil_offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo); + (offset + stencil_offset) >> 8, 0xFFFFFFFF, rbuffer->bo); } r600_pipe_state_add_reg(rstate, R_028008_DB_DEPTH_VIEW, 0x00000000, 0xFFFFFFFF, NULL); @@ -865,14 +1442,11 @@ static void evergreen_set_framebuffer_state(struct pipe_context *ctx, struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; struct r600_pipe_state *rstate = CALLOC_STRUCT(r600_pipe_state); u32 shader_mask, tl, br, target_mask; - enum radeon_family family; int tl_x, tl_y, br_x, br_y; if (rstate == NULL) return; - family = r600_get_family(rctx->radeon); - evergreen_context_flush_dest_caches(&rctx->ctx); rctx->ctx.num_dest_buffers = state->nr_cbufs; @@ -883,6 +1457,7 @@ static void evergreen_set_framebuffer_state(struct pipe_context *ctx, /* build states */ rctx->have_depth_fb = 0; + rctx->nr_cbufs = state->nr_cbufs; for (int i = 0; i < state->nr_cbufs; i++) { evergreen_cb(rctx, rstate, state, i); } @@ -908,7 +1483,7 @@ static void evergreen_set_framebuffer_state(struct pipe_context *ctx, if (br_y == 0) tl_y = 1; /* cayman hw workaround */ - if (family == CHIP_CAYMAN) { + if (rctx->chip_class == CAYMAN) { if (br_x == 1 && br_y == 1) br_x = 2; } @@ -952,7 +1527,7 @@ static void evergreen_set_framebuffer_state(struct pipe_context *ctx, shader_mask, 0xFFFFFFFF, NULL); - if (family == CHIP_CAYMAN) { + if (rctx->chip_class == CAYMAN) { r600_pipe_state_add_reg(rstate, CM_R_028BE0_PA_SC_AA_CONFIG, 0x00000000, 0xFFFFFFFF, NULL); } else { @@ -1139,9 +1714,9 @@ void evergreen_init_config(struct r600_pipe_context *rctx) enum radeon_family family; unsigned tmp; - family = r600_get_family(rctx->radeon); + family = rctx->family; - if (family == CHIP_CAYMAN) { + if (rctx->chip_class == CAYMAN) { cayman_init_config(rctx); return; } @@ -1451,6 +2026,11 @@ void evergreen_init_config(struct r600_pipe_context *rctx) tmp |= S_008C28_NUM_LS_STACK_ENTRIES(num_ls_stack_entries); r600_pipe_state_add_reg(rstate, R_008C28_SQ_STACK_RESOURCE_MGMT_3, tmp, 0xFFFFFFFF, NULL); + tmp = 0; + tmp |= S_008E2C_NUM_PS_LDS(0x1000); + tmp |= S_008E2C_NUM_LS_LDS(0x1000); + r600_pipe_state_add_reg(rstate, R_008E2C_SQ_LDS_RESOURCE_MGMT, tmp, 0xFFFFFFFF, NULL); + r600_pipe_state_add_reg(rstate, R_009100_SPI_CONFIG_CNTL, 0x0, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_00913C_SPI_CONFIG_CNTL_1, S_00913C_VTX_DONE_DELAY(4), 0xFFFFFFFF, NULL); @@ -1629,7 +2209,10 @@ void evergreen_pipe_shader_ps(struct pipe_context *ctx, struct r600_pipe_shader rshader->output[i].name == TGSI_SEMANTIC_STENCIL) exports_ps |= 1; else if (rshader->output[i].name == TGSI_SEMANTIC_COLOR) { - num_cout++; + if (rshader->fs_write_all) + num_cout = rshader->nr_cbufs; + else + num_cout++; } } exports_ps |= S_02884C_EXPORT_COLORS(num_cout); @@ -1682,7 +2265,7 @@ void evergreen_pipe_shader_ps(struct pipe_context *ctx, struct r600_pipe_shader r600_pipe_state_add_reg(rstate, R_028840_SQ_PGM_START_PS, - (r600_bo_offset(shader->bo)) >> 8, 0xFFFFFFFF, shader->bo); + 0, 0xFFFFFFFF, shader->bo); r600_pipe_state_add_reg(rstate, R_028844_SQ_PGM_RESOURCES_PS, S_028844_NUM_GPRS(rshader->bc.ngpr) | @@ -1715,7 +2298,7 @@ void evergreen_pipe_shader_vs(struct pipe_context *ctx, struct r600_pipe_shader struct r600_pipe_state *rstate = &shader->rstate; struct r600_shader *rshader = &shader->shader; unsigned spi_vs_out_id[10]; - unsigned i, tmp; + unsigned i, tmp, nparams; /* clear previous register */ rstate->nregs = 0; @@ -1734,9 +2317,17 @@ void evergreen_pipe_shader_vs(struct pipe_context *ctx, struct r600_pipe_shader spi_vs_out_id[i], 0xFFFFFFFF, NULL); } + /* Certain attributes (position, psize, etc.) don't count as params. + * VS is required to export at least one param and r600_shader_from_tgsi() + * takes care of adding a dummy export. + */ + nparams = rshader->noutput - rshader->npos; + if (nparams < 1) + nparams = 1; + r600_pipe_state_add_reg(rstate, R_0286C4_SPI_VS_OUT_CONFIG, - S_0286C4_VS_EXPORT_COUNT(rshader->noutput - 2), + S_0286C4_VS_EXPORT_COUNT(nparams - 1), 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028860_SQ_PGM_RESOURCES_VS, @@ -1748,7 +2339,7 @@ void evergreen_pipe_shader_vs(struct pipe_context *ctx, struct r600_pipe_shader 0x0, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_02885C_SQ_PGM_START_VS, - (r600_bo_offset(shader->bo)) >> 8, 0xFFFFFFFF, shader->bo); + 0, 0xFFFFFFFF, shader->bo); r600_pipe_state_add_reg(rstate, R_03A200_SQ_LOOP_CONST_0 + (32 * 4), 0x01000FFF, @@ -1765,7 +2356,7 @@ void evergreen_fetch_shader(struct pipe_context *ctx, r600_pipe_state_add_reg(rstate, R_0288A8_SQ_PGM_RESOURCES_FS, 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_0288A4_SQ_PGM_START_FS, - (r600_bo_offset(ve->fetch_shader)) >> 8, + 0, 0xFFFFFFFF, ve->fetch_shader); } diff --git a/src/gallium/drivers/r600/evergreend.h b/src/gallium/drivers/r600/evergreend.h index d795f5757ed..96dbd4da91b 100644 --- a/src/gallium/drivers/r600/evergreend.h +++ b/src/gallium/drivers/r600/evergreend.h @@ -216,6 +216,13 @@ #define S_008C28_NUM_LS_STACK_ENTRIES(x) (((x) & 0xFFF) << 16) #define G_008C28_NUM_LS_STACK_ENTRIES(x) (((x) >> 16) & 0xFFF) #define C_008C28_NUM_LS_STACK_ENTRIES(x) 0xF000FFFF +#define R_008E2C_SQ_LDS_RESOURCE_MGMT 0x00008E2C +#define S_008E2C_NUM_PS_LDS(x) (((x) & 0xFFFF) << 0) +#define G_008E2C_NUM_PS_LDS(x) (((x) >> 0) & 0xFFFF) +#define C_008E2C_NUM_PS_LDS(x) 0x0000FFFF +#define S_008E2C_NUM_LS_LDS(x) (((x) & 0xFFFF) << 16) +#define G_008E2C_NUM_LS_LDS(x) (((x) >> 16) & 0xFFFF) +#define C_008E2C_NUM_LS_LDS(x) 0xFFFF0000 #define R_008CF0_SQ_MS_FIFO_SIZES 0x00008CF0 #define S_008CF0_CACHE_FIFO_SIZE(x) (((x) & 0xFF) << 0) diff --git a/src/gallium/drivers/r600/r600.h b/src/gallium/drivers/r600/r600.h index 225c17c2540..2ac5ed465c1 100644 --- a/src/gallium/drivers/r600/r600.h +++ b/src/gallium/drivers/r600/r600.h @@ -94,6 +94,8 @@ struct r600_tiling_info *r600_get_tiling_info(struct radeon *radeon); unsigned r600_get_clock_crystal_freq(struct radeon *radeon); unsigned r600_get_minor_version(struct radeon *radeon); unsigned r600_get_num_backends(struct radeon *radeon); +unsigned r600_get_num_tile_pipes(struct radeon *radeon); +unsigned r600_get_backend_map(struct radeon *radeon); /* r600_bo.c */ struct r600_bo; @@ -105,11 +107,8 @@ struct r600_bo *r600_bo_handle(struct radeon *radeon, void *r600_bo_map(struct radeon *radeon, struct r600_bo *bo, unsigned usage, void *ctx); void r600_bo_unmap(struct radeon *radeon, struct r600_bo *bo); boolean r600_bo_get_winsys_handle(struct radeon *radeon, struct r600_bo *pb_bo, - unsigned stride, struct winsys_handle *whandle); -static INLINE unsigned r600_bo_offset(struct r600_bo *bo) -{ - return 0; -} + unsigned stride, struct winsys_handle *whandle); + void r600_bo_destroy(struct radeon *radeon, struct r600_bo *bo); /* this relies on the pipe_reference being the first member of r600_bo */ @@ -211,14 +210,21 @@ struct r600_reloc { */ struct r600_query { u64 result; - /* The kind of query. Currently only OQ is supported. */ + /* The kind of query */ unsigned type; - /* How many results have been written, in dwords. It's incremented - * after end_query and flush. */ - unsigned num_results; - /* if we've flushed the query */ + /* Offset of the first result for current query */ + unsigned results_start; + /* Offset of the next free result after current query data */ + unsigned results_end; + /* Size of the result */ + unsigned result_size; + /* Count of new queries started in one stream without flushing */ + unsigned queries_emitted; + /* State flags */ unsigned state; - /* The buffer where query results are stored. */ + /* The buffer where query results are stored. It's used as a ring, + * data blocks for current query are stored sequentially from + * results_start to results_end, with wrapping on the buffer end */ struct r600_bo *buffer; unsigned buffer_size; /* linked list of queries */ @@ -228,6 +234,7 @@ struct r600_query { #define R600_QUERY_STATE_STARTED (1 << 0) #define R600_QUERY_STATE_ENDED (1 << 1) #define R600_QUERY_STATE_SUSPENDED (1 << 2) +#define R600_QUERY_STATE_FLUSHED (1 << 3) #define R600_CONTEXT_DRAW_PENDING (1 << 0) #define R600_CONTEXT_DST_CACHES_DIRTY (1 << 1) @@ -245,6 +252,7 @@ struct r600_context { unsigned pm4_cdwords; unsigned pm4_dirty_cdwords; unsigned ctx_pm4_ndwords; + unsigned init_dwords; unsigned nreloc; unsigned creloc; struct r600_reloc *reloc; @@ -252,6 +260,7 @@ struct r600_context { u32 *pm4; struct list_head query_list; unsigned num_query_running; + unsigned backend_mask; struct list_head fenced_bo; unsigned max_db; /* for OQ */ unsigned num_dest_buffers; @@ -273,6 +282,7 @@ struct r600_draw { struct r600_bo *indices; }; +void r600_get_backend_mask(struct r600_context *ctx); int r600_context_init(struct r600_context *ctx, struct radeon *radeon); void r600_context_fini(struct r600_context *ctx); void r600_context_pipe_state_set(struct r600_context *ctx, struct r600_pipe_state *state); @@ -282,7 +292,6 @@ void r600_context_pipe_state_set_fs_resource(struct r600_context *ctx, struct r6 void r600_context_pipe_state_set_ps_sampler(struct r600_context *ctx, struct r600_pipe_state *state, unsigned id); void r600_context_pipe_state_set_vs_sampler(struct r600_context *ctx, struct r600_pipe_state *state, unsigned id); void r600_context_flush(struct r600_context *ctx); -void r600_context_dump_bof(struct r600_context *ctx, const char *file); void r600_context_draw(struct r600_context *ctx, const struct r600_draw *draw); struct r600_query *r600_context_query_create(struct r600_context *ctx, unsigned query_type); @@ -293,7 +302,7 @@ boolean r600_context_query_result(struct r600_context *ctx, void r600_query_begin(struct r600_context *ctx, struct r600_query *query); void r600_query_end(struct r600_context *ctx, struct r600_query *query); void r600_context_queries_suspend(struct r600_context *ctx); -void r600_context_queries_resume(struct r600_context *ctx); +void r600_context_queries_resume(struct r600_context *ctx, boolean flushed); void r600_query_predication(struct r600_context *ctx, struct r600_query *query, int operation, int flag_wait); void r600_context_emit_fence(struct r600_context *ctx, struct r600_bo *fence, diff --git a/src/gallium/drivers/r600/r600_asm.c b/src/gallium/drivers/r600/r600_asm.c index c447a031063..5fae2b00c8b 100644 --- a/src/gallium/drivers/r600/r600_asm.c +++ b/src/gallium/drivers/r600/r600_asm.c @@ -41,9 +41,9 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc *bc, struct r if(alu->is_op3) return 3; - switch (bc->chiprev) { - case CHIPREV_R600: - case CHIPREV_R700: + switch (bc->chip_class) { + case R600: + case R700: switch (alu->inst) { case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP: return 0; @@ -93,8 +93,8 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc *bc, struct r "Need instruction operand number for 0x%x.\n", alu->inst); } break; - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: switch (alu->inst) { case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP: return 0; @@ -195,48 +195,10 @@ static struct r600_bc_tex *r600_bc_tex(void) return tex; } -int r600_bc_init(struct r600_bc *bc, enum radeon_family family) +void r600_bc_init(struct r600_bc *bc, enum chip_class chip_class) { LIST_INITHEAD(&bc->cf); - bc->family = family; - switch (bc->family) { - case CHIP_R600: - case CHIP_RV610: - case CHIP_RV630: - case CHIP_RV670: - case CHIP_RV620: - case CHIP_RV635: - case CHIP_RS780: - case CHIP_RS880: - bc->chiprev = CHIPREV_R600; - break; - case CHIP_RV770: - case CHIP_RV730: - case CHIP_RV710: - case CHIP_RV740: - bc->chiprev = CHIPREV_R700; - break; - case CHIP_CEDAR: - case CHIP_REDWOOD: - case CHIP_JUNIPER: - case CHIP_CYPRESS: - case CHIP_HEMLOCK: - case CHIP_PALM: - case CHIP_SUMO: - case CHIP_SUMO2: - case CHIP_BARTS: - case CHIP_TURKS: - case CHIP_CAICOS: - bc->chiprev = CHIPREV_EVERGREEN; - break; - case CHIP_CAYMAN: - bc->chiprev = CHIPREV_CAYMAN; - break; - default: - R600_ERR("unknown family %d\n", bc->family); - return -EINVAL; - } - return 0; + bc->chip_class = chip_class; } static int r600_bc_add_cf(struct r600_bc *bc) @@ -301,9 +263,9 @@ int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output) /* alu instructions that can ony exits once per group */ static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { - switch (bc->chiprev) { - case CHIPREV_R600: - case CHIPREV_R700: + switch (bc->chip_class) { + case R600: + case R700: return !alu->is_op3 && ( alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT || @@ -339,8 +301,8 @@ static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_PUSH_INT || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLT_PUSH_INT || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLE_PUSH_INT); - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: default: return !alu->is_op3 && ( alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE || @@ -382,16 +344,16 @@ static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) static int is_alu_reduction_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { - switch (bc->chiprev) { - case CHIPREV_R600: - case CHIPREV_R700: + switch (bc->chip_class) { + case R600: + case R700: return !alu->is_op3 && ( alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4 || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4_IEEE || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX4); - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: default: return !alu->is_op3 && ( alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE || @@ -403,13 +365,13 @@ static int is_alu_reduction_inst(struct r600_bc *bc, struct r600_bc_alu *alu) static int is_alu_cube_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { - switch (bc->chiprev) { - case CHIPREV_R600: - case CHIPREV_R700: + switch (bc->chip_class) { + case R600: + case R700: return !alu->is_op3 && alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE; - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: default: return !alu->is_op3 && alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE; @@ -418,15 +380,15 @@ static int is_alu_cube_inst(struct r600_bc *bc, struct r600_bc_alu *alu) static int is_alu_mova_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { - switch (bc->chiprev) { - case CHIPREV_R600: - case CHIPREV_R700: + switch (bc->chip_class) { + case R600: + case R700: return !alu->is_op3 && ( alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_INT); - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: default: return !alu->is_op3 && ( alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_INT); @@ -438,16 +400,16 @@ static int is_alu_vec_unit_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { return is_alu_reduction_inst(bc, alu) || is_alu_mova_inst(bc, alu) || - (bc->chiprev == CHIPREV_EVERGREEN && + (bc->chip_class == EVERGREEN && alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT_FLOOR); } /* alu instructions that can only execute on the trans unit */ static int is_alu_trans_unit_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { - switch (bc->chiprev) { - case CHIPREV_R600: - case CHIPREV_R700: + switch (bc->chip_class) { + case R600: + case R700: if (!alu->is_op3) return alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ASHR_INT || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT || @@ -478,8 +440,8 @@ static int is_alu_trans_unit_inst(struct r600_bc *bc, struct r600_bc_alu *alu) alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_D2 || alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M2 || alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M4; - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: default: if (!alu->is_op3) /* Note that FLT_TO_INT_* instructions are vector-only instructions @@ -525,7 +487,7 @@ static int assign_alu_units(struct r600_bc *bc, struct r600_bc_alu *alu_first, { struct r600_bc_alu *alu; unsigned i, chan, trans; - int max_slots = bc->chiprev == CHIPREV_CAYMAN ? 4 : 5; + int max_slots = bc->chip_class == CAYMAN ? 4 : 5; for (i = 0; i < max_slots; i++) assignment[i] = NULL; @@ -612,7 +574,7 @@ static int reserve_gpr(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan, static int reserve_cfile(struct r600_bc *bc, struct alu_bank_swizzle *bs, unsigned sel, unsigned chan) { int res, num_res = 4; - if (bc->chiprev >= CHIPREV_R700) { + if (bc->chip_class >= R700) { num_res = 2; chan /= 2; } @@ -733,8 +695,8 @@ static int check_and_set_bank_swizzle(struct r600_bc *bc, struct alu_bank_swizzle bs; int bank_swizzle[5]; int i, r = 0, forced = 0; - boolean scalar_only = bc->chiprev == CHIPREV_CAYMAN ? false : true; - int max_slots = bc->chiprev == CHIPREV_CAYMAN ? 4 : 5; + boolean scalar_only = bc->chip_class == CAYMAN ? false : true; + int max_slots = bc->chip_class == CAYMAN ? 4 : 5; for (i = 0; i < max_slots; i++) { if (slots[i] && slots[i]->bank_swizzle_force) { @@ -806,7 +768,7 @@ static int replace_gpr_with_pv_ps(struct r600_bc *bc, struct r600_bc_alu *prev[5]; int gpr[5], chan[5]; int i, j, r, src, num_src; - int max_slots = bc->chiprev == CHIPREV_CAYMAN ? 4 : 5; + int max_slots = bc->chip_class == CAYMAN ? 4 : 5; r = assign_alu_units(bc, alu_prev, prev); if (r) @@ -834,7 +796,7 @@ static int replace_gpr_with_pv_ps(struct r600_bc *bc, if (!is_gpr(alu->src[src].sel) || alu->src[src].rel) continue; - if (bc->chiprev < CHIPREV_CAYMAN) { + if (bc->chip_class < CAYMAN) { if (alu->src[src].sel == gpr[4] && alu->src[src].chan == chan[4]) { alu->src[src].sel = V_SQ_ALU_SRC_PS; @@ -948,7 +910,7 @@ static int merge_inst_groups(struct r600_bc *bc, struct r600_bc_alu *slots[5], int i, j, r, src, num_src; int num_once_inst = 0; int have_mova = 0, have_rel = 0; - int max_slots = bc->chiprev == CHIPREV_CAYMAN ? 4 : 5; + int max_slots = bc->chip_class == CAYMAN ? 4 : 5; r = assign_alu_units(bc, alu_prev, prev); if (r) @@ -1252,7 +1214,7 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int uint32_t literal[4]; unsigned nliteral; struct r600_bc_alu *slots[5]; - int max_slots = bc->chiprev == CHIPREV_CAYMAN ? 4 : 5; + int max_slots = bc->chip_class == CAYMAN ? 4 : 5; r = assign_alu_units(bc, bc->cf_last->curr_bs_head, slots); if (r) return r; @@ -1302,26 +1264,26 @@ int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) static unsigned r600_bc_num_tex_and_vtx_instructions(const struct r600_bc *bc) { - switch (bc->chiprev) { - case CHIPREV_R600: + switch (bc->chip_class) { + case R600: return 8; - case CHIPREV_R700: + case R700: return 16; - case CHIPREV_EVERGREEN: - case CHIPREV_CAYMAN: + case EVERGREEN: + case CAYMAN: return 64; default: - R600_ERR("Unknown chiprev %d.\n", bc->chiprev); + R600_ERR("Unknown chip class %d.\n", bc->chip_class); return 8; } } static inline boolean last_inst_was_vtx_fetch(struct r600_bc *bc) { - if (bc->chiprev == CHIPREV_CAYMAN) { + if (bc->chip_class == CAYMAN) { if (bc->cf_last->inst != CM_V_SQ_CF_WORD1_SQ_CF_INST_TC) return TRUE; } else { @@ -1350,7 +1312,7 @@ int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx) free(nvtx); return r; } - if (bc->chiprev == CHIPREV_CAYMAN) + if (bc->chip_class == CAYMAN) bc->cf_last->inst = CM_V_SQ_CF_WORD1_SQ_CF_INST_TC; else bc->cf_last->inst = V_SQ_CF_WORD1_SQ_CF_INST_VTX; @@ -1438,7 +1400,7 @@ static int r600_bc_vtx_build(struct r600_bc *bc, struct r600_bc_vtx *vtx, unsign S_SQ_VTX_WORD0_FETCH_TYPE(vtx->fetch_type) | S_SQ_VTX_WORD0_SRC_GPR(vtx->src_gpr) | S_SQ_VTX_WORD0_SRC_SEL_X(vtx->src_sel_x); - if (bc->chiprev < CHIPREV_CAYMAN) + if (bc->chip_class < CAYMAN) bc->bytecode[id] |= S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(vtx->mega_fetch_count); id++; bc->bytecode[id++] = S_SQ_VTX_WORD1_DST_SEL_X(vtx->dst_sel_x) | @@ -1453,7 +1415,7 @@ static int r600_bc_vtx_build(struct r600_bc *bc, struct r600_bc_vtx *vtx, unsign S_SQ_VTX_WORD1_GPR_DST_GPR(vtx->dst_gpr); bc->bytecode[id] = S_SQ_VTX_WORD2_OFFSET(vtx->offset)| S_SQ_VTX_WORD2_ENDIAN_SWAP(vtx->endian); - if (bc->chiprev < CHIPREV_CAYMAN) + if (bc->chip_class < CAYMAN) bc->bytecode[id] |= S_SQ_VTX_WORD2_MEGA_FETCH(1); id++; bc->bytecode[id++] = 0; @@ -1560,13 +1522,13 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) S_SQ_CF_ALU_WORD1_KCACHE_ADDR0(cf->kcache[0].addr) | S_SQ_CF_ALU_WORD1_KCACHE_ADDR1(cf->kcache[1].addr) | S_SQ_CF_ALU_WORD1_BARRIER(1) | - S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == CHIPREV_R600 ? cf->r6xx_uses_waterfall : 0) | + S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chip_class == R600 ? cf->r6xx_uses_waterfall : 0) | S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1); break; case V_SQ_CF_WORD1_SQ_CF_INST_TEX: case V_SQ_CF_WORD1_SQ_CF_INST_VTX: case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC: - if (bc->chiprev == CHIPREV_R700) + if (bc->chip_class == R700) r700_bc_cf_vtx_build(&bc->bytecode[id], cf); else r600_bc_cf_vtx_build(&bc->bytecode[id], cf); @@ -1673,7 +1635,7 @@ int r600_bc_build(struct r600_bc *bc) return -ENOMEM; LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) { addr = cf->addr; - if (bc->chiprev >= CHIPREV_EVERGREEN) + if (bc->chip_class >= EVERGREEN) r = eg_bc_cf_build(bc, cf); else r = r600_bc_cf_build(bc, cf); @@ -1691,17 +1653,17 @@ int r600_bc_build(struct r600_bc *bc) if (r) return r; r600_bc_alu_adjust_literals(bc, alu, literal, nliteral); - switch(bc->chiprev) { - case CHIPREV_R600: + switch(bc->chip_class) { + case R600: r = r600_bc_alu_build(bc, alu, addr); break; - case CHIPREV_R700: - case CHIPREV_EVERGREEN: /* eg alu is same encoding as r700 */ - case CHIPREV_CAYMAN: /* eg alu is same encoding as r700 */ + case R700: + case EVERGREEN: /* eg alu is same encoding as r700 */ + case CAYMAN: /* eg alu is same encoding as r700 */ r = r700_bc_alu_build(bc, alu, addr); break; default: - R600_ERR("unknown family %d\n", bc->family); + R600_ERR("unknown chip class %d.\n", bc->chip_class); return -EINVAL; } if (r) @@ -1726,7 +1688,7 @@ int r600_bc_build(struct r600_bc *bc) } break; case V_SQ_CF_WORD1_SQ_CF_INST_TEX: - if (bc->chiprev == CHIPREV_CAYMAN) { + if (bc->chip_class == CAYMAN) { LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) { r = r600_bc_vtx_build(bc, vtx, addr); if (r) @@ -1812,17 +1774,17 @@ void r600_bc_dump(struct r600_bc *bc) unsigned nliteral; char chip = '6'; - switch (bc->chiprev) { - case 1: + switch (bc->chip_class) { + case R700: chip = '7'; break; - case 2: + case EVERGREEN: chip = 'E'; break; - case 3: + case CAYMAN: chip = 'C'; break; - case 0: + case R600: default: chip = '6'; break; @@ -1863,6 +1825,8 @@ void r600_bc_dump(struct r600_bc *bc) break; case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: + case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: + case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]); fprintf(stderr, "GPR:%X ", cf->output.gpr); fprintf(stderr, "ELEM_SIZE:%X ", cf->output.elem_size); @@ -1991,7 +1955,7 @@ void r600_bc_dump(struct r600_bc *bc) fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]); fprintf(stderr, "SRC(GPR:%d ", vtx->src_gpr); fprintf(stderr, "SEL_X:%d) ", vtx->src_sel_x); - if (bc->chiprev < CHIPREV_CAYMAN) + if (bc->chip_class < CAYMAN) fprintf(stderr, "MEGA_FETCH_COUNT:%d ", vtx->mega_fetch_count); else fprintf(stderr, "SEL_Y:%d) ", 0); @@ -2160,7 +2124,7 @@ int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, stru struct r600_bc_vtx vtx; struct pipe_vertex_element *elements = ve->elements; const struct util_format_description *desc; - unsigned fetch_resource_start = rctx->family >= CHIP_CEDAR ? 0 : 160; + unsigned fetch_resource_start = rctx->chip_class >= EVERGREEN ? 0 : 160; unsigned format, num_format, format_comp, endian; u32 *bytecode; int i, r; @@ -2178,9 +2142,7 @@ int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, stru } memset(&bc, 0, sizeof(bc)); - r = r600_bc_init(&bc, r600_get_family(rctx->radeon)); - if (r) - return r; + r600_bc_init(&bc, rctx->chip_class); for (i = 0; i < ve->count; i++) { if (elements[i].instance_divisor > 1) { @@ -2285,7 +2247,7 @@ int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, stru r600_bo_unmap(rctx->radeon, ve->fetch_shader); r600_bc_clear(&bc); - if (rctx->family >= CHIP_CEDAR) + if (rctx->chip_class >= EVERGREEN) evergreen_fetch_shader(&rctx->context, ve); else r600_fetch_shader(&rctx->context, ve); diff --git a/src/gallium/drivers/r600/r600_asm.h b/src/gallium/drivers/r600/r600_asm.h index 540f45bbd06..cbdaacf7178 100644 --- a/src/gallium/drivers/r600/r600_asm.h +++ b/src/gallium/drivers/r600/r600_asm.h @@ -171,8 +171,7 @@ struct r600_cf_callstack { }; struct r600_bc { - enum radeon_family family; - int chiprev; /* 0 - r600, 1 - r700, 2 - evergreen */ + enum chip_class chip_class; int type; struct list_head cf; struct r600_bc_cf *cf_last; @@ -193,7 +192,7 @@ struct r600_bc { int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf); /* r600_asm.c */ -int r600_bc_init(struct r600_bc *bc, enum radeon_family family); +void r600_bc_init(struct r600_bc *bc, enum chip_class chip_class); void r600_bc_clear(struct r600_bc *bc); int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu); int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx); diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index 043c8759f56..35e68b6e222 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -97,7 +97,7 @@ static void r600_blitter_end(struct pipe_context *ctx) rctx->saved_render_cond_mode); rctx->saved_render_cond = NULL; } - r600_context_queries_resume(&rctx->ctx); + r600_context_queries_resume(&rctx->ctx, FALSE); rctx->blit = false; } @@ -294,6 +294,8 @@ static void r600_resource_copy_region(struct pipe_context *ctx, { struct r600_resource_texture *rsrc = (struct r600_resource_texture*)src; struct texture_orig_info orig_info[2]; + struct pipe_box sbox; + const struct pipe_box *psbox; boolean restore_orig[2]; /* Fallback for buffers. */ @@ -311,7 +313,15 @@ static void r600_resource_copy_region(struct pipe_context *ctx, if (util_format_is_compressed(src->format)) { r600_compressed_to_blittable(src, src_level, &orig_info[0]); restore_orig[0] = TRUE; - } + sbox.x = util_format_get_nblocksx(orig_info[0].format, src_box->x); + sbox.y = util_format_get_nblocksy(orig_info[0].format, src_box->y); + sbox.z = src_box->z; + sbox.width = util_format_get_nblocksx(orig_info[0].format, src_box->width); + sbox.height = util_format_get_nblocksy(orig_info[0].format, src_box->height); + sbox.depth = src_box->depth; + psbox=&sbox; + } else + psbox=src_box; if (util_format_is_compressed(dst->format)) { r600_compressed_to_blittable(dst, dst_level, &orig_info[1]); @@ -322,7 +332,7 @@ static void r600_resource_copy_region(struct pipe_context *ctx, } r600_hw_copy_region(ctx, dst, dst_level, dstx, dsty, dstz, - src, src_level, src_box); + src, src_level, psbox); if (restore_orig[0]) r600_reset_blittable_to_compressed(src, src_level, &orig_info[0]); diff --git a/src/gallium/drivers/r600/r600_formats.h b/src/gallium/drivers/r600/r600_formats.h index ae0bc432ad2..1c1089d89d2 100644 --- a/src/gallium/drivers/r600/r600_formats.h +++ b/src/gallium/drivers/r600/r600_formats.h @@ -81,4 +81,36 @@ static INLINE unsigned r600_endian_swap(unsigned size) } } +static INLINE bool r600_is_vertex_format_supported(enum pipe_format format) +{ + const struct util_format_description *desc = util_format_description(format); + unsigned i; + + if (!desc) + return false; + + /* Find the first non-VOID channel. */ + for (i = 0; i < 4; i++) { + if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) + break; + } + if (i == 4) + return false; + + /* No fixed, no double. */ + if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || + desc->channel[i].type == UTIL_FORMAT_TYPE_FIXED || + (desc->channel[i].size == 64 && + desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT)) + return false; + + /* No scaled/norm formats with 32 bits per channel. */ + if (desc->channel[i].size == 32 && + (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED || + desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED)) + return false; + + return true; +} + #endif diff --git a/src/gallium/drivers/r600/r600_opcodes.h b/src/gallium/drivers/r600/r600_opcodes.h index 184f32c9960..7ae091ea5cd 100644 --- a/src/gallium/drivers/r600/r600_opcodes.h +++ b/src/gallium/drivers/r600/r600_opcodes.h @@ -409,14 +409,8 @@ #define EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_MEM_EXPORT_COMBINED 0x0000005B #define EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_MEM_RAT_COMBINED_CACHELESS 0x0000005C +#define BC_INST(bc, x) ((bc)->chip_class >= EVERGREEN ? EG_##x : x) -#define CHIPREV_R600 0 -#define CHIPREV_R700 1 -#define CHIPREV_EVERGREEN 2 -#define CHIPREV_CAYMAN 3 - -#define BC_INST(bc, x) ((bc)->chiprev >= CHIPREV_EVERGREEN ? EG_##x : x) - -#define CTX_INST(x) (ctx->bc->chiprev >= CHIPREV_EVERGREEN ? EG_##x : x) +#define CTX_INST(x) (ctx->bc->chip_class >= EVERGREEN ? EG_##x : x) #endif diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 2d744137522..461f59439e8 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -38,6 +38,8 @@ #include <util/u_memory.h> #include <util/u_inlines.h> #include "util/u_upload_mgr.h" +#include <vl/vl_decoder.h> +#include <vl/vl_video_buffer.h> #include "os/os_time.h" #include <pipebuffer/pb_buffer.h> #include "r600.h" @@ -45,7 +47,6 @@ #include "r600_resource.h" #include "r600_shader.h" #include "r600_pipe.h" -#include "r600_state_inlines.h" /* * pipe_context @@ -61,7 +62,7 @@ static struct r600_fence *r600_create_fence(struct r600_pipe_context *ctx) R600_ERR("r600: failed to create bo for fence objects\n"); return NULL; } - ctx->fences.data = r600_bo_map(ctx->radeon, ctx->fences.bo, PB_USAGE_UNSYNCHRONIZED, NULL); + ctx->fences.data = r600_bo_map(ctx->radeon, ctx->fences.bo, PIPE_TRANSFER_UNSYNCHRONIZED, NULL); } if (!LIST_IS_EMPTY(&ctx->fences.pool)) { @@ -118,25 +119,9 @@ static void r600_flush(struct pipe_context *ctx, struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; struct r600_fence **rfence = (struct r600_fence**)fence; -#if 0 - static int dc = 0; - char dname[256]; -#endif - if (rfence) *rfence = r600_create_fence(rctx); - if (!rctx->ctx.pm4_cdwords) - return; - -#if 0 - sprintf(dname, "gallium-%08d.bof", dc); - if (dc < 20) { - r600_context_dump_bof(&rctx->ctx, dname); - R600_ERR("dumped %s\n", dname); - } - dc++; -#endif r600_context_flush(&rctx->ctx); } @@ -198,7 +183,6 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void { struct r600_pipe_context *rctx = CALLOC_STRUCT(r600_pipe_context); struct r600_screen* rscreen = (struct r600_screen *)screen; - enum chip_class class; if (rctx == NULL) return NULL; @@ -215,6 +199,7 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void rctx->screen = rscreen; rctx->radeon = rscreen->radeon; rctx->family = r600_get_family(rctx->radeon); + rctx->chip_class = r600_get_family_class(rctx->radeon); rctx->fences.bo = NULL; rctx->fences.data = NULL; @@ -228,47 +213,32 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void r600_init_surface_functions(rctx); rctx->context.draw_vbo = r600_draw_vbo; - switch (r600_get_family(rctx->radeon)) { - case CHIP_R600: - case CHIP_RV610: - case CHIP_RV630: - case CHIP_RV670: - case CHIP_RV620: - case CHIP_RV635: - case CHIP_RS780: - case CHIP_RS880: - case CHIP_RV770: - case CHIP_RV730: - case CHIP_RV710: - case CHIP_RV740: + rctx->context.create_video_decoder = vl_create_decoder; + rctx->context.create_video_buffer = vl_video_buffer_create; + + switch (rctx->chip_class) { + case R600: + case R700: r600_init_state_functions(rctx); if (r600_context_init(&rctx->ctx, rctx->radeon)) { r600_destroy_context(&rctx->context); return NULL; } r600_init_config(rctx); + rctx->custom_dsa_flush = r600_create_db_flush_dsa(rctx); break; - case CHIP_CEDAR: - case CHIP_REDWOOD: - case CHIP_JUNIPER: - case CHIP_CYPRESS: - case CHIP_HEMLOCK: - case CHIP_PALM: - case CHIP_SUMO: - case CHIP_SUMO2: - case CHIP_BARTS: - case CHIP_TURKS: - case CHIP_CAICOS: - case CHIP_CAYMAN: + case EVERGREEN: + case CAYMAN: evergreen_init_state_functions(rctx); if (evergreen_context_init(&rctx->ctx, rctx->radeon)) { r600_destroy_context(&rctx->context); return NULL; } evergreen_init_config(rctx); + rctx->custom_dsa_flush = evergreen_create_db_flush_dsa(rctx); break; default: - R600_ERR("unsupported family %d\n", r600_get_family(rctx->radeon)); + R600_ERR("Unsupported chip class %d.\n", rctx->chip_class); r600_destroy_context(&rctx->context); return NULL; } @@ -293,12 +263,6 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void return NULL; } - class = r600_get_family_class(rctx->radeon); - if (class == R600 || class == R700) - rctx->custom_dsa_flush = r600_create_db_flush_dsa(rctx); - else - rctx->custom_dsa_flush = evergreen_create_db_flush_dsa(rctx); - return &rctx->context; } @@ -376,6 +340,8 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: case PIPE_CAP_SM3: + case PIPE_CAP_SEAMLESS_CUBE_MAP: + case PIPE_CAP_FRAGMENT_COLOR_CLAMP_CONTROL: return 1; /* Supported except the original R600. */ @@ -385,14 +351,12 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param) return family == CHIP_R600 ? 0 : 1; /* Supported on Evergreen. */ - case PIPE_CAP_SEAMLESS_CUBE_MAP: case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: return family >= CHIP_CEDAR ? 1 : 0; /* Unsupported features. */ case PIPE_CAP_STREAM_OUTPUT: case PIPE_CAP_PRIMITIVE_RESTART: - case PIPE_CAP_FRAGMENT_COLOR_CLAMP_CONTROL: case PIPE_CAP_TGSI_INSTANCEID: case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: @@ -481,9 +445,9 @@ static int r600_get_shader_param(struct pipe_screen* pscreen, unsigned shader, e return 8; /* FIXME */ case PIPE_SHADER_CAP_MAX_INPUTS: if(shader == PIPE_SHADER_FRAGMENT) - return 10; + return 34; else - return 16; + return 32; case PIPE_SHADER_CAP_MAX_TEMPS: return 256; /* Max native temporaries. */ case PIPE_SHADER_CAP_MAX_ADDRS: @@ -511,62 +475,21 @@ static int r600_get_shader_param(struct pipe_screen* pscreen, unsigned shader, e } } -static boolean r600_is_format_supported(struct pipe_screen* screen, - enum pipe_format format, - enum pipe_texture_target target, - unsigned sample_count, - unsigned usage) +static int r600_get_video_param(struct pipe_screen *screen, + enum pipe_video_profile profile, + enum pipe_video_cap param) { - unsigned retval = 0; - if (target >= PIPE_MAX_TEXTURE_TYPES) { - R600_ERR("r600: unsupported texture type %d\n", target); - return FALSE; - } - - if (!util_format_is_supported(format, usage)) - return FALSE; - - /* Multisample */ - if (sample_count > 1) - return FALSE; - - if ((usage & PIPE_BIND_SAMPLER_VIEW) && - r600_is_sampler_format_supported(screen, format)) { - retval |= PIPE_BIND_SAMPLER_VIEW; - } - - if ((usage & (PIPE_BIND_RENDER_TARGET | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_SCANOUT | - PIPE_BIND_SHARED)) && - r600_is_colorbuffer_format_supported(format)) { - retval |= usage & - (PIPE_BIND_RENDER_TARGET | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_SCANOUT | - PIPE_BIND_SHARED); - } - - if ((usage & PIPE_BIND_DEPTH_STENCIL) && - r600_is_zs_format_supported(format)) { - retval |= PIPE_BIND_DEPTH_STENCIL; - } - - if (usage & PIPE_BIND_VERTEX_BUFFER) { - struct r600_screen *rscreen = (struct r600_screen *)screen; - enum radeon_family family = r600_get_family(rscreen->radeon); - - if (r600_is_vertex_format_supported(format, family)) { - retval |= PIPE_BIND_VERTEX_BUFFER; - } + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vl_profile_supported(screen, profile); + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 1; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vl_video_buffer_max_size(screen); + default: + return 0; } - - if (usage & PIPE_BIND_TRANSFER_READ) - retval |= PIPE_BIND_TRANSFER_READ; - if (usage & PIPE_BIND_TRANSFER_WRITE) - retval |= PIPE_BIND_TRANSFER_WRITE; - - return retval == usage; } static void r600_destroy_screen(struct pipe_screen* pscreen) @@ -657,7 +580,13 @@ struct pipe_screen *r600_screen_create(struct radeon *radeon) rscreen->screen.get_param = r600_get_param; rscreen->screen.get_shader_param = r600_get_shader_param; rscreen->screen.get_paramf = r600_get_paramf; - rscreen->screen.is_format_supported = r600_is_format_supported; + rscreen->screen.get_video_param = r600_get_video_param; + if (r600_get_family_class(radeon) >= EVERGREEN) { + rscreen->screen.is_format_supported = evergreen_is_format_supported; + } else { + rscreen->screen.is_format_supported = r600_is_format_supported; + } + rscreen->screen.is_video_format_supported = vl_video_buffer_is_format_supported; rscreen->screen.context_create = r600_create_context; rscreen->screen.fence_reference = r600_fence_reference; rscreen->screen.fence_signalled = r600_fence_signalled; diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 84a45bec05d..6f399ed43b0 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -50,6 +50,7 @@ enum r600_pipe_state_id { R600_PIPE_STATE_BLEND = 0, R600_PIPE_STATE_BLEND_COLOR, R600_PIPE_STATE_CONFIG, + R600_PIPE_STATE_SEAMLESS_CUBEMAP, R600_PIPE_STATE_CLIP, R600_PIPE_STATE_SCISSOR, R600_PIPE_STATE_VIEWPORT, @@ -87,6 +88,8 @@ struct r600_pipe_sampler_view { struct r600_pipe_rasterizer { struct r600_pipe_state rstate; + boolean clamp_vertex_color; + boolean clamp_fragment_color; boolean flatshade; unsigned sprite_coord_enable; float offset_units; @@ -124,6 +127,12 @@ struct r600_pipe_shader { struct r600_bo *bo; struct r600_bo *bo_fetch; struct r600_vertex_element vertex_elements; + struct tgsi_token *tokens; +}; + +struct r600_pipe_sampler_state { + struct r600_pipe_state rstate; + boolean seamless_cube_map; }; /* needed for blitter save */ @@ -166,7 +175,8 @@ struct r600_pipe_fences { struct r600_pipe_context { struct pipe_context context; struct blitter_context *blitter; - unsigned family; + enum radeon_family family; + enum chip_class chip_class; void *custom_dsa_flush; struct r600_screen *screen; struct radeon *radeon; @@ -196,11 +206,15 @@ struct r600_pipe_context { struct pipe_query *saved_render_cond; unsigned saved_render_cond_mode; /* shader information */ + boolean clamp_vertex_color; + boolean clamp_fragment_color; + boolean spi_dirty; unsigned sprite_coord_enable; boolean flatshade; boolean export_16bpc; unsigned alpha_ref; boolean alpha_ref_dirty; + unsigned nr_cbufs; struct r600_textures_info ps_samplers; struct r600_pipe_fences fences; @@ -234,6 +248,11 @@ void evergreen_pipe_init_buffer_resource(struct r600_pipe_context *rctx, void evergreen_pipe_mod_buffer_resource(struct r600_pipe_resource_state *rstate, struct r600_resource *rbuffer, unsigned offset, unsigned stride); +boolean evergreen_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned usage); /* r600_blit.c */ void r600_init_blit_functions(struct r600_pipe_context *rctx); @@ -258,7 +277,7 @@ void r600_init_query_functions(struct r600_pipe_context *rctx); void r600_init_context_resource_functions(struct r600_pipe_context *r600); /* r600_shader.c */ -int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader, const struct tgsi_token *tokens); +int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader); void r600_pipe_shader_destroy(struct pipe_context *ctx, struct r600_pipe_shader *shader); int r600_find_vs_semantic_index(struct r600_shader *vs, struct r600_shader *ps, int id); @@ -277,6 +296,11 @@ void r600_pipe_mod_buffer_resource(struct r600_pipe_resource_state *rstate, struct r600_resource *rbuffer, unsigned offset, unsigned stride); void r600_adjust_gprs(struct r600_pipe_context *rctx); +boolean r600_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned usage); /* r600_texture.c */ void r600_init_screen_texture_functions(struct pipe_screen *screen); diff --git a/src/gallium/drivers/r600/r600_query.c b/src/gallium/drivers/r600/r600_query.c index bedb48b6031..de1f5d05f4e 100644 --- a/src/gallium/drivers/r600/r600_query.c +++ b/src/gallium/drivers/r600/r600_query.c @@ -43,7 +43,7 @@ static void r600_begin_query(struct pipe_context *ctx, struct pipe_query *query) struct r600_query *rquery = (struct r600_query *)query; rquery->result = 0; - rquery->num_results = 0; + rquery->results_start = rquery->results_end; r600_query_begin(&rctx->ctx, (struct r600_query *)query); } @@ -61,10 +61,7 @@ static boolean r600_get_query_result(struct pipe_context *ctx, struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; struct r600_query *rquery = (struct r600_query *)query; - if (rquery->num_results) { - ctx->flush(ctx, NULL); - } - return r600_context_query_result(&rctx->ctx, (struct r600_query *)query, wait, vresult); + return r600_context_query_result(&rctx->ctx, rquery, wait, vresult); } static void r600_render_condition(struct pipe_context *ctx, @@ -75,12 +72,18 @@ static void r600_render_condition(struct pipe_context *ctx, struct r600_query *rquery = (struct r600_query *)query; int wait_flag = 0; + /* If we already have nonzero result, render unconditionally */ + if (query != NULL && rquery->result != 0) + return; + rctx->current_render_cond = query; rctx->current_render_cond_mode = mode; - if (!query) { - rctx->ctx.predicate_drawing = false; - r600_query_predication(&rctx->ctx, NULL, PREDICATION_OP_CLEAR, 1); + if (query == NULL) { + if (rctx->ctx.predicate_drawing) { + rctx->ctx.predicate_drawing = false; + r600_query_predication(&rctx->ctx, NULL, PREDICATION_OP_CLEAR, 1); + } return; } @@ -91,7 +94,6 @@ static void r600_render_condition(struct pipe_context *ctx, rctx->ctx.predicate_drawing = true; r600_query_predication(&rctx->ctx, rquery, PREDICATION_OP_ZPASS, wait_flag); - } void r600_init_query_functions(struct r600_pipe_context *rctx) diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index b8a86b03143..c55cdd707eb 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -99,14 +99,14 @@ static int r600_pipe_shader(struct pipe_context *ctx, struct r600_pipe_shader *s /* build state */ switch (rshader->processor_type) { case TGSI_PROCESSOR_VERTEX: - if (rshader->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_shader_vs(ctx, shader); } else { r600_pipe_shader_vs(ctx, shader); } break; case TGSI_PROCESSOR_FRAGMENT: - if (rshader->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_shader_ps(ctx, shader); } else { r600_pipe_shader_ps(ctx, shader); @@ -118,9 +118,9 @@ static int r600_pipe_shader(struct pipe_context *ctx, struct r600_pipe_shader *s return 0; } -static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader); +static int r600_shader_from_tgsi(struct r600_pipe_context * rctx, struct r600_pipe_shader *pipeshader); -int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader, const struct tgsi_token *tokens) +int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader) { static int dump_shaders = -1; struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; @@ -133,10 +133,9 @@ int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *s if (dump_shaders) { fprintf(stderr, "--------------------------------------------------------------\n"); - tgsi_dump(tokens, 0); + tgsi_dump(shader->tokens, 0); } - shader->shader.family = r600_get_family(rctx->radeon); - r = r600_shader_from_tgsi(tokens, &shader->shader); + r = r600_shader_from_tgsi(rctx, shader); if (r) { R600_ERR("translation from TGSI failed !\n"); return r; @@ -159,6 +158,8 @@ void r600_pipe_shader_destroy(struct pipe_context *ctx, struct r600_pipe_shader r600_bo_reference(rctx->radeon, &shader->bo, NULL); r600_bc_clear(&shader->shader.bc); + + memset(&shader->shader,0,sizeof(struct r600_shader)); } /* @@ -315,7 +316,7 @@ static int tgsi_declaration(struct r600_shader_ctx *ctx) ctx->shader->input[i].interpolate = d->Declaration.Interpolate; ctx->shader->input[i].centroid = d->Declaration.Centroid; ctx->shader->input[i].gpr = ctx->file_offset[TGSI_FILE_INPUT] + i; - if (ctx->type == TGSI_PROCESSOR_FRAGMENT && ctx->bc->chiprev >= CHIPREV_EVERGREEN) { + if (ctx->type == TGSI_PROCESSOR_FRAGMENT && ctx->bc->chip_class >= EVERGREEN) { /* turn input into interpolate on EG */ if (ctx->shader->input[i].name != TGSI_SEMANTIC_POSITION) { if (ctx->shader->input[i].interpolate > 0) { @@ -331,6 +332,12 @@ static int tgsi_declaration(struct r600_shader_ctx *ctx) ctx->shader->output[i].sid = d->Semantic.Index; ctx->shader->output[i].gpr = ctx->file_offset[TGSI_FILE_OUTPUT] + i; ctx->shader->output[i].interpolate = d->Declaration.Interpolate; + if (ctx->type == TGSI_PROCESSOR_VERTEX) { + /* these don't count as vertex param exports */ + if ((ctx->shader->output[i].name == TGSI_SEMANTIC_POSITION) || + (ctx->shader->output[i].name == TGSI_SEMANTIC_PSIZE)) + ctx->shader->npos++; + } break; case TGSI_FILE_CONSTANT: case TGSI_FILE_TEMPORARY: @@ -594,21 +601,21 @@ static int tgsi_split_literal_constant(struct r600_shader_ctx *ctx) return 0; } -static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader) +static int r600_shader_from_tgsi(struct r600_pipe_context * rctx, struct r600_pipe_shader *pipeshader) { + struct r600_shader *shader = &pipeshader->shader; + struct tgsi_token *tokens = pipeshader->tokens; struct tgsi_full_immediate *immediate; struct tgsi_full_property *property; struct r600_shader_ctx ctx; struct r600_bc_output output[32]; unsigned output_done, noutput; unsigned opcode; - int i, r = 0, pos0; + int i, j, r = 0, pos0; ctx.bc = &shader->bc; ctx.shader = shader; - r = r600_bc_init(ctx.bc, shader->family); - if (r) - return r; + r600_bc_init(ctx.bc, rctx->chip_class); ctx.tokens = tokens; tgsi_scan_shader(tokens, &ctx.info); tgsi_parse_init(&ctx.parse, tokens); @@ -616,6 +623,11 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh shader->processor_type = ctx.type; ctx.bc->type = shader->processor_type; + shader->clamp_color = (((ctx.type == TGSI_PROCESSOR_FRAGMENT) && rctx->clamp_fragment_color) || + ((ctx.type == TGSI_PROCESSOR_VERTEX) && rctx->clamp_vertex_color)); + + shader->nr_cbufs = rctx->nr_cbufs; + /* register allocations */ /* Values [0,127] correspond to GPR[0..127]. * Values [128,159] correspond to constant buffer bank 0 @@ -642,19 +654,19 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh } if (ctx.type == TGSI_PROCESSOR_VERTEX) { ctx.file_offset[TGSI_FILE_INPUT] = 1; - if (ctx.bc->chiprev >= CHIPREV_EVERGREEN) { + if (ctx.bc->chip_class >= EVERGREEN) { r600_bc_add_cfinst(ctx.bc, EG_V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS); } else { r600_bc_add_cfinst(ctx.bc, V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS); } } - if (ctx.type == TGSI_PROCESSOR_FRAGMENT && ctx.bc->chiprev >= CHIPREV_EVERGREEN) { + if (ctx.type == TGSI_PROCESSOR_FRAGMENT && ctx.bc->chip_class >= EVERGREEN) { ctx.file_offset[TGSI_FILE_INPUT] = evergreen_gpr_count(&ctx); } ctx.file_offset[TGSI_FILE_OUTPUT] = ctx.file_offset[TGSI_FILE_INPUT] + - ctx.info.file_count[TGSI_FILE_INPUT]; + ctx.info.file_max[TGSI_FILE_INPUT] + 1; ctx.file_offset[TGSI_FILE_TEMPORARY] = ctx.file_offset[TGSI_FILE_OUTPUT] + - ctx.info.file_count[TGSI_FILE_OUTPUT]; + ctx.info.file_max[TGSI_FILE_OUTPUT] + 1; /* Outside the GPR range. This will be translated to one of the * kcache banks later. */ @@ -662,7 +674,7 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh ctx.file_offset[TGSI_FILE_IMMEDIATE] = V_SQ_ALU_SRC_LITERAL; ctx.ar_reg = ctx.file_offset[TGSI_FILE_TEMPORARY] + - ctx.info.file_count[TGSI_FILE_TEMPORARY]; + ctx.info.file_max[TGSI_FILE_TEMPORARY] + 1; ctx.temp_reg = ctx.ar_reg + 1; ctx.nliterals = 0; @@ -702,9 +714,9 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh goto out_err; if ((r = tgsi_split_literal_constant(&ctx))) goto out_err; - if (ctx.bc->chiprev == CHIPREV_CAYMAN) + if (ctx.bc->chip_class == CAYMAN) ctx.inst_info = &cm_shader_tgsi_instruction[opcode]; - else if (ctx.bc->chiprev >= CHIPREV_EVERGREEN) + else if (ctx.bc->chip_class >= EVERGREEN) ctx.inst_info = &eg_shader_tgsi_instruction[opcode]; else ctx.inst_info = &r600_shader_tgsi_instruction[opcode]; @@ -725,52 +737,103 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh goto out_err; } } - /* export output */ + noutput = shader->noutput; + + /* clamp color outputs */ + if (shader->clamp_color) { + for (i = 0; i < noutput; i++) { + if (shader->output[i].name == TGSI_SEMANTIC_COLOR || + shader->output[i].name == TGSI_SEMANTIC_BCOLOR) { + + int j; + for (j = 0; j < 4; j++) { + struct r600_bc_alu alu; + memset(&alu, 0, sizeof(struct r600_bc_alu)); + + /* MOV_SAT R, R */ + alu.inst = BC_INST(ctx.bc, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV); + alu.dst.sel = shader->output[i].gpr; + alu.dst.chan = j; + alu.dst.write = 1; + alu.dst.clamp = 1; + alu.src[0].sel = alu.dst.sel; + alu.src[0].chan = j; + + if (j == 3) { + alu.last = 1; + } + r = r600_bc_add_alu(ctx.bc, &alu); + if (r) + return r; + } + } + } + } + + /* export output */ + j = 0; for (i = 0, pos0 = 0; i < noutput; i++) { memset(&output[i], 0, sizeof(struct r600_bc_output)); - output[i].gpr = shader->output[i].gpr; - output[i].elem_size = 3; - output[i].swizzle_x = 0; - output[i].swizzle_y = 1; - output[i].swizzle_z = 2; - output[i].swizzle_w = 3; - output[i].burst_count = 1; - output[i].barrier = 1; - output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM; - output[i].array_base = i - pos0; - output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); + output[i + j].gpr = shader->output[i].gpr; + output[i + j].elem_size = 3; + output[i + j].swizzle_x = 0; + output[i + j].swizzle_y = 1; + output[i + j].swizzle_z = 2; + output[i + j].swizzle_w = 3; + output[i + j].burst_count = 1; + output[i + j].barrier = 1; + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM; + output[i + j].array_base = i - pos0; + output[i + j].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); switch (ctx.type) { case TGSI_PROCESSOR_VERTEX: if (shader->output[i].name == TGSI_SEMANTIC_POSITION) { - output[i].array_base = 60; - output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_POS; + output[i + j].array_base = 60; + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_POS; /* position doesn't count in array_base */ pos0++; } if (shader->output[i].name == TGSI_SEMANTIC_PSIZE) { - output[i].array_base = 61; - output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_POS; + output[i + j].array_base = 61; + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_POS; /* position doesn't count in array_base */ pos0++; } break; case TGSI_PROCESSOR_FRAGMENT: if (shader->output[i].name == TGSI_SEMANTIC_COLOR) { - output[i].array_base = shader->output[i].sid; - output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; + output[i + j].array_base = shader->output[i].sid; + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; + if (shader->fs_write_all && (rctx->chip_class >= EVERGREEN)) { + for (j = 1; j < shader->nr_cbufs; j++) { + memset(&output[i + j], 0, sizeof(struct r600_bc_output)); + output[i + j].gpr = shader->output[i].gpr; + output[i + j].elem_size = 3; + output[i + j].swizzle_x = 0; + output[i + j].swizzle_y = 1; + output[i + j].swizzle_z = 2; + output[i + j].swizzle_w = 3; + output[i + j].burst_count = 1; + output[i + j].barrier = 1; + output[i + j].array_base = shader->output[i].sid + j; + output[i + j].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; + } + j--; + } } else if (shader->output[i].name == TGSI_SEMANTIC_POSITION) { - output[i].array_base = 61; - output[i].swizzle_x = 2; - output[i].swizzle_y = 7; - output[i].swizzle_z = output[i].swizzle_w = 7; - output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; + output[i + j].array_base = 61; + output[i + j].swizzle_x = 2; + output[i + j].swizzle_y = 7; + output[i + j].swizzle_z = output[i + j].swizzle_w = 7; + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; } else if (shader->output[i].name == TGSI_SEMANTIC_STENCIL) { - output[i].array_base = 61; - output[i].swizzle_x = 7; - output[i].swizzle_y = 1; - output[i].swizzle_z = output[i].swizzle_w = 7; - output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; + output[i + j].array_base = 61; + output[i + j].swizzle_x = 7; + output[i + j].swizzle_y = 1; + output[i + j].swizzle_z = output[i + j].swizzle_w = 7; + output[i + j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; } else { R600_ERR("unsupported fragment output name %d\n", shader->output[i].name); r = -EINVAL; @@ -783,6 +846,7 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh goto out_err; } } + noutput += j; /* add fake param output for vertex shader if no param is exported */ if (ctx.type == TGSI_PROCESSOR_VERTEX) { for (i = 0, pos0 = 0; i < noutput; i++) { @@ -825,7 +889,7 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh } /* set export done on last export of each type */ for (i = noutput - 1, output_done = 0; i >= 0; i--) { - if (ctx.bc->chiprev < CHIPREV_CAYMAN) { + if (ctx.bc->chip_class < CAYMAN) { if (i == (noutput - 1)) { output[i].end_of_program = 1; } @@ -842,7 +906,7 @@ static int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_sh goto out_err; } /* add program end */ - if (ctx.bc->chiprev == CHIPREV_CAYMAN) + if (ctx.bc->chip_class == CAYMAN) cm_bc_add_cf_end(ctx.bc); free(ctx.literals); @@ -878,6 +942,17 @@ static void r600_bc_src(struct r600_bc_alu_src *bc_src, bc_src->value = shader_src->value[bc_src->chan]; } +static void r600_bc_src_set_abs(struct r600_bc_alu_src *bc_src) +{ + bc_src->abs = 1; + bc_src->neg = 0; +} + +static void r600_bc_src_toggle_neg(struct r600_bc_alu_src *bc_src) +{ + bc_src->neg = !bc_src->neg; +} + static void tgsi_dst(struct r600_shader_ctx *ctx, const struct tgsi_full_dst_register *tgsi_dst, unsigned swizzle, @@ -934,12 +1009,10 @@ static int tgsi_op2_s(struct r600_shader_ctx *ctx, int swap) /* handle some special cases */ switch (ctx->inst_info->tgsi_opcode) { case TGSI_OPCODE_SUB: - alu.src[1].neg = 1; + r600_bc_src_toggle_neg(&alu.src[1]); break; case TGSI_OPCODE_ABS: - alu.src[0].abs = 1; - if (alu.src[0].neg) - alu.src[0].neg = 0; + r600_bc_src_set_abs(&alu.src[0]); break; default: break; @@ -1053,7 +1126,7 @@ static int tgsi_setup_trig(struct r600_shader_ctx *ctx) alu.src[2].sel = V_SQ_ALU_SRC_LITERAL; alu.src[2].chan = 0; - if (ctx->bc->chiprev == CHIPREV_R600) { + if (ctx->bc->chip_class == R600) { alu.src[1].value = *(uint32_t *)&double_pi; alu.src[2].value = *(uint32_t *)&neg_pi; } else { @@ -1160,7 +1233,7 @@ static int tgsi_scs(struct r600_shader_ctx *ctx) /* dst.x = COS */ if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0 ; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS); @@ -1194,7 +1267,7 @@ static int tgsi_scs(struct r600_shader_ctx *ctx) /* dst.y = SIN */ if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0 ; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN); @@ -1303,36 +1376,17 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) struct r600_bc_alu alu; int r; - /* dst.x, <- 1.0 */ - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV); - alu.src[0].sel = V_SQ_ALU_SRC_1; /*1.0*/ - alu.src[0].chan = 0; - tgsi_dst(ctx, &inst->Dst[0], 0, &alu.dst); - alu.dst.write = (inst->Dst[0].Register.WriteMask >> 0) & 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; - - /* dst.y = max(src.x, 0.0) */ + /* tmp.x = max(src.y, 0.0) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX); - r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src(&alu.src[0], &ctx->src[0], 1); alu.src[1].sel = V_SQ_ALU_SRC_0; /*0.0*/ - alu.src[1].chan = 0; - tgsi_dst(ctx, &inst->Dst[0], 1, &alu.dst); - alu.dst.write = (inst->Dst[0].Register.WriteMask >> 1) & 1; - r = r600_bc_add_alu(ctx->bc, &alu); - if (r) - return r; + alu.src[1].chan = 1; + + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 0; + alu.dst.write = 1; - /* dst.w, <- 1.0 */ - memset(&alu, 0, sizeof(struct r600_bc_alu)); - alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV); - alu.src[0].sel = V_SQ_ALU_SRC_1; - alu.src[0].chan = 0; - tgsi_dst(ctx, &inst->Dst[0], 3, &alu.dst); - alu.dst.write = (inst->Dst[0].Register.WriteMask >> 3) & 1; alu.last = 1; r = r600_bc_add_alu(ctx->bc, &alu); if (r) @@ -1344,13 +1398,15 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) int sel; int i; - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { - /* dst.z = log(src.y) */ + /* tmp.z = log(tmp.x) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED); - r600_bc_src(&alu.src[0], &ctx->src[0], 1); - tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = i; if (i == 2) { alu.dst.write = 1; alu.last = 1; @@ -1362,11 +1418,14 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) return r; } } else { - /* dst.z = log(src.y) */ + /* tmp.z = log(tmp.x) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED); - r600_bc_src(&alu.src[0], &ctx->src[0], 1); - tgsi_dst(ctx, &inst->Dst[0], 2, &alu.dst); + alu.src[0].sel = ctx->temp_reg; + alu.src[0].chan = 0; + alu.dst.sel = ctx->temp_reg; + alu.dst.chan = 2; + alu.dst.write = 1; alu.last = 1; r = r600_bc_add_alu(ctx->bc, &alu); if (r) @@ -1376,13 +1435,12 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) chan = alu.dst.chan; sel = alu.dst.sel; - /* tmp.x = amd MUL_LIT(src.w, dst.z, src.x ) */ + /* tmp.x = amd MUL_LIT(tmp.z, src.w, src.x ) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT); - r600_bc_src(&alu.src[0], &ctx->src[0], 3); - alu.src[1].sel = sel; - alu.src[1].chan = chan; - + alu.src[0].sel = sel; + alu.src[0].chan = chan; + r600_bc_src(&alu.src[1], &ctx->src[0], 3); r600_bc_src(&alu.src[2], &ctx->src[0], 0); alu.dst.sel = ctx->temp_reg; alu.dst.chan = 0; @@ -1393,7 +1451,7 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) if (r) return r; - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { /* dst.z = exp(tmp.x) */ memset(&alu, 0, sizeof(struct r600_bc_alu)); @@ -1423,6 +1481,42 @@ static int tgsi_lit(struct r600_shader_ctx *ctx) return r; } } + + /* dst.x, <- 1.0 */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV); + alu.src[0].sel = V_SQ_ALU_SRC_1; /*1.0*/ + alu.src[0].chan = 0; + tgsi_dst(ctx, &inst->Dst[0], 0, &alu.dst); + alu.dst.write = (inst->Dst[0].Register.WriteMask >> 0) & 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + /* dst.y = max(src.x, 0.0) */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX); + r600_bc_src(&alu.src[0], &ctx->src[0], 0); + alu.src[1].sel = V_SQ_ALU_SRC_0; /*0.0*/ + alu.src[1].chan = 0; + tgsi_dst(ctx, &inst->Dst[0], 1, &alu.dst); + alu.dst.write = (inst->Dst[0].Register.WriteMask >> 1) & 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + + /* dst.w, <- 1.0 */ + memset(&alu, 0, sizeof(struct r600_bc_alu)); + alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV); + alu.src[0].sel = V_SQ_ALU_SRC_1; + alu.src[0].chan = 0; + tgsi_dst(ctx, &inst->Dst[0], 3, &alu.dst); + alu.dst.write = (inst->Dst[0].Register.WriteMask >> 3) & 1; + alu.last = 1; + r = r600_bc_add_alu(ctx->bc, &alu); + if (r) + return r; + return 0; } @@ -1442,7 +1536,7 @@ static int tgsi_rsq(struct r600_shader_ctx *ctx) for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { r600_bc_src(&alu.src[i], &ctx->src[i], 0); - alu.src[i].abs = 1; + r600_bc_src_set_abs(&alu.src[i]); } alu.dst.sel = ctx->temp_reg; alu.dst.write = 1; @@ -1834,7 +1928,7 @@ static int tgsi_tex(struct r600_shader_ctx *ctx) } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXP) { int out_chan; /* Add perspective divide */ - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { out_chan = 2; for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); @@ -1916,7 +2010,7 @@ static int tgsi_tex(struct r600_shader_ctx *ctx) } /* tmp1.z = RCP_e(|tmp1.z|) */ - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE); @@ -2128,7 +2222,7 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx) alu.src[0].sel = V_SQ_ALU_SRC_1; alu.src[0].chan = 0; r600_bc_src(&alu.src[1], &ctx->src[0], i); - alu.src[1].neg = 1; + r600_bc_src_toggle_neg(&alu.src[1]); alu.dst.sel = ctx->temp_reg; alu.dst.chan = i; if (i == lasti) { @@ -2309,7 +2403,7 @@ static int tgsi_exp(struct r600_shader_ctx *ctx) if (r) return r; - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE); alu.src[0].sel = ctx->temp_reg; @@ -2365,7 +2459,7 @@ static int tgsi_exp(struct r600_shader_ctx *ctx) /* result.z = RoughApprox2ToX(tmp);*/ if ((inst->Dst[0].Register.WriteMask >> 2) & 0x1) { - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE); @@ -2425,14 +2519,15 @@ static int tgsi_log(struct r600_shader_ctx *ctx) int r; int i; - /* result.x = floor(log2(src)); */ + /* result.x = floor(log2(|src|)); */ if (inst->Dst[0].Register.WriteMask & 1) { - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.dst.sel = ctx->temp_reg; alu.dst.chan = i; @@ -2450,6 +2545,7 @@ static int tgsi_log(struct r600_shader_ctx *ctx) alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.dst.sel = ctx->temp_reg; alu.dst.chan = 0; @@ -2474,15 +2570,16 @@ static int tgsi_log(struct r600_shader_ctx *ctx) return r; } - /* result.y = src.x / (2 ^ floor(log2(src.x))); */ + /* result.y = |src.x| / (2 ^ floor(log2(|src.x|))); */ if ((inst->Dst[0].Register.WriteMask >> 1) & 1) { - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.dst.sel = ctx->temp_reg; alu.dst.chan = i; @@ -2500,6 +2597,7 @@ static int tgsi_log(struct r600_shader_ctx *ctx) alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.dst.sel = ctx->temp_reg; alu.dst.chan = 1; @@ -2526,7 +2624,7 @@ static int tgsi_log(struct r600_shader_ctx *ctx) if (r) return r; - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE); @@ -2560,7 +2658,7 @@ static int tgsi_log(struct r600_shader_ctx *ctx) return r; } - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE); @@ -2599,6 +2697,7 @@ static int tgsi_log(struct r600_shader_ctx *ctx) alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.src[1].sel = ctx->temp_reg; alu.src[1].chan = 1; @@ -2613,14 +2712,15 @@ static int tgsi_log(struct r600_shader_ctx *ctx) return r; } - /* result.z = log2(src);*/ + /* result.z = log2(|src|);*/ if ((inst->Dst[0].Register.WriteMask >> 2) & 1) { - if (ctx->bc->chiprev == CHIPREV_CAYMAN) { + if (ctx->bc->chip_class == CAYMAN) { for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bc_alu)); alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.dst.sel = ctx->temp_reg; if (i == 2) @@ -2638,6 +2738,7 @@ static int tgsi_log(struct r600_shader_ctx *ctx) alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE); r600_bc_src(&alu.src[0], &ctx->src[0], 0); + r600_bc_src_set_abs(&alu.src[0]); alu.dst.sel = ctx->temp_reg; alu.dst.write = 1; @@ -2831,25 +2932,34 @@ static int emit_logic_pred(struct r600_shader_ctx *ctx, int opcode) static int pops(struct r600_shader_ctx *ctx, int pops) { - int alu_pop = 3; - if (ctx->bc->cf_last) { - if (ctx->bc->cf_last->inst == CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU) << 3) - alu_pop = 0; - else if (ctx->bc->cf_last->inst == CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER) << 3) - alu_pop = 1; - } - alu_pop += pops; - if (alu_pop == 1) { - ctx->bc->cf_last->inst = CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER) << 3; - ctx->bc->force_add_cf = 1; - } else if (alu_pop == 2) { - ctx->bc->cf_last->inst = CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER) << 3; - ctx->bc->force_add_cf = 1; - } else { + unsigned force_pop = ctx->bc->force_add_cf; + + if (!force_pop) { + int alu_pop = 3; + if (ctx->bc->cf_last) { + if (ctx->bc->cf_last->inst == CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU) << 3) + alu_pop = 0; + else if (ctx->bc->cf_last->inst == CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER) << 3) + alu_pop = 1; + } + alu_pop += pops; + if (alu_pop == 1) { + ctx->bc->cf_last->inst = CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER) << 3; + ctx->bc->force_add_cf = 1; + } else if (alu_pop == 2) { + ctx->bc->cf_last->inst = CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER) << 3; + ctx->bc->force_add_cf = 1; + } else { + force_pop = 1; + } + } + + if (force_pop) { r600_bc_add_cfinst(ctx->bc, CTX_INST(V_SQ_CF_WORD1_SQ_CF_INST_POP)); ctx->bc->cf_last->pop_count = pops; ctx->bc->cf_last->cf_addr = ctx->bc->cf_last->id + 2; } + return 0; } @@ -3266,7 +3376,7 @@ static struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] = { {TGSI_OPCODE_MOV, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV, tgsi_op2}, {TGSI_OPCODE_LIT, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_lit}, {TGSI_OPCODE_RCP, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE, tgsi_trans_srcx_replicate}, - {TGSI_OPCODE_RSQ, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE, tgsi_trans_srcx_replicate}, + {TGSI_OPCODE_RSQ, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE, tgsi_rsq}, {TGSI_OPCODE_EXP, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_exp}, {TGSI_OPCODE_LOG, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP, tgsi_log}, {TGSI_OPCODE_MUL, 0, EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL, tgsi_op2}, diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h index 8f96ce5085c..600c3e2f540 100644 --- a/src/gallium/drivers/r600/r600_shader.h +++ b/src/gallium/drivers/r600/r600_shader.h @@ -40,12 +40,14 @@ struct r600_shader { struct r600_bc bc; unsigned ninput; unsigned noutput; + unsigned npos; unsigned nlds; struct r600_shader_io input[32]; struct r600_shader_io output[32]; - enum radeon_family family; boolean uses_kill; boolean fs_write_all; + boolean clamp_color; + unsigned nr_cbufs; }; #endif diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index d927e4a945e..487b1df0052 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -44,7 +44,590 @@ #include "r600_resource.h" #include "r600_shader.h" #include "r600_pipe.h" -#include "r600_state_inlines.h" +#include "r600_formats.h" + +static uint32_t r600_translate_blend_function(int blend_func) +{ + switch (blend_func) { + case PIPE_BLEND_ADD: + return V_028804_COMB_DST_PLUS_SRC; + case PIPE_BLEND_SUBTRACT: + return V_028804_COMB_SRC_MINUS_DST; + case PIPE_BLEND_REVERSE_SUBTRACT: + return V_028804_COMB_DST_MINUS_SRC; + case PIPE_BLEND_MIN: + return V_028804_COMB_MIN_DST_SRC; + case PIPE_BLEND_MAX: + return V_028804_COMB_MAX_DST_SRC; + default: + R600_ERR("Unknown blend function %d\n", blend_func); + assert(0); + break; + } + return 0; +} + +static uint32_t r600_translate_blend_factor(int blend_fact) +{ + switch (blend_fact) { + case PIPE_BLENDFACTOR_ONE: + return V_028804_BLEND_ONE; + case PIPE_BLENDFACTOR_SRC_COLOR: + return V_028804_BLEND_SRC_COLOR; + case PIPE_BLENDFACTOR_SRC_ALPHA: + return V_028804_BLEND_SRC_ALPHA; + case PIPE_BLENDFACTOR_DST_ALPHA: + return V_028804_BLEND_DST_ALPHA; + case PIPE_BLENDFACTOR_DST_COLOR: + return V_028804_BLEND_DST_COLOR; + case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: + return V_028804_BLEND_SRC_ALPHA_SATURATE; + case PIPE_BLENDFACTOR_CONST_COLOR: + return V_028804_BLEND_CONST_COLOR; + case PIPE_BLENDFACTOR_CONST_ALPHA: + return V_028804_BLEND_CONST_ALPHA; + case PIPE_BLENDFACTOR_ZERO: + return V_028804_BLEND_ZERO; + case PIPE_BLENDFACTOR_INV_SRC_COLOR: + return V_028804_BLEND_ONE_MINUS_SRC_COLOR; + case PIPE_BLENDFACTOR_INV_SRC_ALPHA: + return V_028804_BLEND_ONE_MINUS_SRC_ALPHA; + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + return V_028804_BLEND_ONE_MINUS_DST_ALPHA; + case PIPE_BLENDFACTOR_INV_DST_COLOR: + return V_028804_BLEND_ONE_MINUS_DST_COLOR; + case PIPE_BLENDFACTOR_INV_CONST_COLOR: + return V_028804_BLEND_ONE_MINUS_CONST_COLOR; + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + return V_028804_BLEND_ONE_MINUS_CONST_ALPHA; + case PIPE_BLENDFACTOR_SRC1_COLOR: + return V_028804_BLEND_SRC1_COLOR; + case PIPE_BLENDFACTOR_SRC1_ALPHA: + return V_028804_BLEND_SRC1_ALPHA; + case PIPE_BLENDFACTOR_INV_SRC1_COLOR: + return V_028804_BLEND_INV_SRC1_COLOR; + case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: + return V_028804_BLEND_INV_SRC1_ALPHA; + default: + R600_ERR("Bad blend factor %d not supported!\n", blend_fact); + assert(0); + break; + } + return 0; +} + +static uint32_t r600_translate_stencil_op(int s_op) +{ + switch (s_op) { + case PIPE_STENCIL_OP_KEEP: + return V_028800_STENCIL_KEEP; + case PIPE_STENCIL_OP_ZERO: + return V_028800_STENCIL_ZERO; + case PIPE_STENCIL_OP_REPLACE: + return V_028800_STENCIL_REPLACE; + case PIPE_STENCIL_OP_INCR: + return V_028800_STENCIL_INCR; + case PIPE_STENCIL_OP_DECR: + return V_028800_STENCIL_DECR; + case PIPE_STENCIL_OP_INCR_WRAP: + return V_028800_STENCIL_INCR_WRAP; + case PIPE_STENCIL_OP_DECR_WRAP: + return V_028800_STENCIL_DECR_WRAP; + case PIPE_STENCIL_OP_INVERT: + return V_028800_STENCIL_INVERT; + default: + R600_ERR("Unknown stencil op %d", s_op); + assert(0); + break; + } + return 0; +} + +static uint32_t r600_translate_fill(uint32_t func) +{ + switch(func) { + case PIPE_POLYGON_MODE_FILL: + return 2; + case PIPE_POLYGON_MODE_LINE: + return 1; + case PIPE_POLYGON_MODE_POINT: + return 0; + default: + assert(0); + return 0; + } +} + +/* translates straight */ +static uint32_t r600_translate_ds_func(int func) +{ + return func; +} + +static unsigned r600_tex_wrap(unsigned wrap) +{ + switch (wrap) { + default: + case PIPE_TEX_WRAP_REPEAT: + return V_03C000_SQ_TEX_WRAP; + case PIPE_TEX_WRAP_CLAMP: + return V_03C000_SQ_TEX_CLAMP_HALF_BORDER; + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return V_03C000_SQ_TEX_CLAMP_LAST_TEXEL; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + return V_03C000_SQ_TEX_CLAMP_BORDER; + case PIPE_TEX_WRAP_MIRROR_REPEAT: + return V_03C000_SQ_TEX_MIRROR; + case PIPE_TEX_WRAP_MIRROR_CLAMP: + return V_03C000_SQ_TEX_MIRROR_ONCE_HALF_BORDER; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + return V_03C000_SQ_TEX_MIRROR_ONCE_LAST_TEXEL; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + return V_03C000_SQ_TEX_MIRROR_ONCE_BORDER; + } +} + +static unsigned r600_tex_filter(unsigned filter) +{ + switch (filter) { + default: + case PIPE_TEX_FILTER_NEAREST: + return V_03C000_SQ_TEX_XY_FILTER_POINT; + case PIPE_TEX_FILTER_LINEAR: + return V_03C000_SQ_TEX_XY_FILTER_BILINEAR; + } +} + +static unsigned r600_tex_mipfilter(unsigned filter) +{ + switch (filter) { + case PIPE_TEX_MIPFILTER_NEAREST: + return V_03C000_SQ_TEX_Z_FILTER_POINT; + case PIPE_TEX_MIPFILTER_LINEAR: + return V_03C000_SQ_TEX_Z_FILTER_LINEAR; + default: + case PIPE_TEX_MIPFILTER_NONE: + return V_03C000_SQ_TEX_Z_FILTER_NONE; + } +} + +static unsigned r600_tex_compare(unsigned compare) +{ + switch (compare) { + default: + case PIPE_FUNC_NEVER: + return V_03C000_SQ_TEX_DEPTH_COMPARE_NEVER; + case PIPE_FUNC_LESS: + return V_03C000_SQ_TEX_DEPTH_COMPARE_LESS; + case PIPE_FUNC_EQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_EQUAL; + case PIPE_FUNC_LEQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_LESSEQUAL; + case PIPE_FUNC_GREATER: + return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATER; + case PIPE_FUNC_NOTEQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_NOTEQUAL; + case PIPE_FUNC_GEQUAL: + return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATEREQUAL; + case PIPE_FUNC_ALWAYS: + return V_03C000_SQ_TEX_DEPTH_COMPARE_ALWAYS; + } +} + +static unsigned r600_tex_dim(unsigned dim) +{ + switch (dim) { + default: + case PIPE_TEXTURE_1D: + return V_038000_SQ_TEX_DIM_1D; + case PIPE_TEXTURE_1D_ARRAY: + return V_038000_SQ_TEX_DIM_1D_ARRAY; + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: + return V_038000_SQ_TEX_DIM_2D; + case PIPE_TEXTURE_2D_ARRAY: + return V_038000_SQ_TEX_DIM_2D_ARRAY; + case PIPE_TEXTURE_3D: + return V_038000_SQ_TEX_DIM_3D; + case PIPE_TEXTURE_CUBE: + return V_038000_SQ_TEX_DIM_CUBEMAP; + } +} + +static uint32_t r600_translate_dbformat(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_Z16_UNORM: + return V_028010_DEPTH_16; + case PIPE_FORMAT_Z24X8_UNORM: + return V_028010_DEPTH_X8_24; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return V_028010_DEPTH_8_24; + case PIPE_FORMAT_Z32_FLOAT: + return V_028010_DEPTH_32_FLOAT; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + return V_028010_DEPTH_X24_8_32_FLOAT; + default: + return ~0U; + } +} + +static uint32_t r600_translate_colorswap(enum pipe_format format) +{ + switch (format) { + /* 8-bit buffers. */ + case PIPE_FORMAT_A8_UNORM: + return V_0280A0_SWAP_ALT_REV; + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SRGB: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_L4A4_UNORM: + return V_0280A0_SWAP_ALT; + + /* 16-bit buffers. */ + case PIPE_FORMAT_B5G6R5_UNORM: + return V_0280A0_SWAP_STD_REV; + + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B5G5R5X1_UNORM: + return V_0280A0_SWAP_ALT; + + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + return V_0280A0_SWAP_ALT; + + case PIPE_FORMAT_Z16_UNORM: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_L8A8_SRGB: + return V_0280A0_SWAP_ALT; + case PIPE_FORMAT_R8G8_UNORM: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16_FLOAT: + return V_0280A0_SWAP_STD; + + /* 32-bit buffers. */ + + case PIPE_FORMAT_A8B8G8R8_SRGB: + return V_0280A0_SWAP_STD_REV; + case PIPE_FORMAT_B8G8R8A8_SRGB: + return V_0280A0_SWAP_ALT; + + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + return V_0280A0_SWAP_ALT; + + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + return V_0280A0_SWAP_ALT_REV; + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_A8B8G8R8_UNORM: + case PIPE_FORMAT_X8B8G8R8_UNORM: + /* case PIPE_FORMAT_R8SG8SB8UX8U_NORM: */ + return V_0280A0_SWAP_STD_REV; + + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + case PIPE_FORMAT_R10SG10SB10SA2U_NORM: + return V_0280A0_SWAP_STD; + + case PIPE_FORMAT_B10G10R10A2_UNORM: + return V_0280A0_SWAP_ALT; + + case PIPE_FORMAT_R11G11B10_FLOAT: + case PIPE_FORMAT_R16G16_UNORM: + case PIPE_FORMAT_R16G16_FLOAT: + case PIPE_FORMAT_R32_FLOAT: + case PIPE_FORMAT_Z32_FLOAT: + return V_0280A0_SWAP_STD; + + /* 64-bit buffers. */ + case PIPE_FORMAT_R32G32_FLOAT: + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + + /* 128-bit buffers. */ + case PIPE_FORMAT_R32G32B32A32_FLOAT: + case PIPE_FORMAT_R32G32B32A32_SNORM: + case PIPE_FORMAT_R32G32B32A32_UNORM: + return V_0280A0_SWAP_STD; + default: + R600_ERR("unsupported colorswap format %d\n", format); + return ~0U; + } + return ~0U; +} + +static uint32_t r600_translate_colorformat(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_L4A4_UNORM: + return V_0280A0_COLOR_4_4; + + /* 8-bit buffers. */ + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_I8_UNORM: + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SRGB: + case PIPE_FORMAT_R8_UNORM: + case PIPE_FORMAT_R8_SNORM: + return V_0280A0_COLOR_8; + + /* 16-bit buffers. */ + case PIPE_FORMAT_B5G6R5_UNORM: + return V_0280A0_COLOR_5_6_5; + + case PIPE_FORMAT_B5G5R5A1_UNORM: + case PIPE_FORMAT_B5G5R5X1_UNORM: + return V_0280A0_COLOR_1_5_5_5; + + case PIPE_FORMAT_B4G4R4A4_UNORM: + case PIPE_FORMAT_B4G4R4X4_UNORM: + return V_0280A0_COLOR_4_4_4_4; + + case PIPE_FORMAT_Z16_UNORM: + return V_0280A0_COLOR_16; + + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_L8A8_SRGB: + case PIPE_FORMAT_R8G8_UNORM: + return V_0280A0_COLOR_8_8; + + case PIPE_FORMAT_R16_UNORM: + return V_0280A0_COLOR_16; + + case PIPE_FORMAT_R16_FLOAT: + return V_0280A0_COLOR_16_FLOAT; + + /* 32-bit buffers. */ + case PIPE_FORMAT_A8B8G8R8_SRGB: + case PIPE_FORMAT_A8B8G8R8_UNORM: + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_B8G8R8A8_SRGB: + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + case PIPE_FORMAT_R8G8B8A8_SNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: + case PIPE_FORMAT_R8G8B8X8_UNORM: + case PIPE_FORMAT_R8SG8SB8UX8U_NORM: + case PIPE_FORMAT_X8B8G8R8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_R8G8B8_UNORM: + return V_0280A0_COLOR_8_8_8_8; + + case PIPE_FORMAT_R10G10B10A2_UNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + case PIPE_FORMAT_B10G10R10A2_UNORM: + case PIPE_FORMAT_R10SG10SB10SA2U_NORM: + return V_0280A0_COLOR_2_10_10_10; + + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return V_0280A0_COLOR_8_24; + + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + return V_0280A0_COLOR_24_8; + + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + return V_0280A0_COLOR_X24_8_32_FLOAT; + + case PIPE_FORMAT_R32_FLOAT: + case PIPE_FORMAT_Z32_FLOAT: + return V_0280A0_COLOR_32_FLOAT; + + case PIPE_FORMAT_R16G16_FLOAT: + return V_0280A0_COLOR_16_16_FLOAT; + + case PIPE_FORMAT_R16G16_SSCALED: + case PIPE_FORMAT_R16G16_UNORM: + return V_0280A0_COLOR_16_16; + + case PIPE_FORMAT_R11G11B10_FLOAT: + return V_0280A0_COLOR_10_11_11_FLOAT; + + /* 64-bit buffers. */ + case PIPE_FORMAT_R16G16B16_USCALED: + case PIPE_FORMAT_R16G16B16A16_USCALED: + case PIPE_FORMAT_R16G16B16_SSCALED: + case PIPE_FORMAT_R16G16B16A16_SSCALED: + case PIPE_FORMAT_R16G16B16A16_UNORM: + case PIPE_FORMAT_R16G16B16A16_SNORM: + return V_0280A0_COLOR_16_16_16_16; + + case PIPE_FORMAT_R16G16B16_FLOAT: + case PIPE_FORMAT_R16G16B16A16_FLOAT: + return V_0280A0_COLOR_16_16_16_16_FLOAT; + + case PIPE_FORMAT_R32G32_FLOAT: + return V_0280A0_COLOR_32_32_FLOAT; + + case PIPE_FORMAT_R32G32_USCALED: + case PIPE_FORMAT_R32G32_SSCALED: + return V_0280A0_COLOR_32_32; + + /* 96-bit buffers. */ + case PIPE_FORMAT_R32G32B32_FLOAT: + return V_0280A0_COLOR_32_32_32_FLOAT; + + /* 128-bit buffers. */ + case PIPE_FORMAT_R32G32B32A32_FLOAT: + return V_0280A0_COLOR_32_32_32_32_FLOAT; + case PIPE_FORMAT_R32G32B32A32_SNORM: + case PIPE_FORMAT_R32G32B32A32_UNORM: + return V_0280A0_COLOR_32_32_32_32; + + /* YUV buffers. */ + case PIPE_FORMAT_UYVY: + case PIPE_FORMAT_YUYV: + default: + return ~0U; /* Unsupported. */ + } +} + +static uint32_t r600_colorformat_endian_swap(uint32_t colorformat) +{ + if (R600_BIG_ENDIAN) { + switch(colorformat) { + case V_0280A0_COLOR_4_4: + return ENDIAN_NONE; + + /* 8-bit buffers. */ + case V_0280A0_COLOR_8: + return ENDIAN_NONE; + + /* 16-bit buffers. */ + case V_0280A0_COLOR_5_6_5: + case V_0280A0_COLOR_1_5_5_5: + case V_0280A0_COLOR_4_4_4_4: + case V_0280A0_COLOR_16: + case V_0280A0_COLOR_8_8: + return ENDIAN_8IN16; + + /* 32-bit buffers. */ + case V_0280A0_COLOR_8_8_8_8: + case V_0280A0_COLOR_2_10_10_10: + case V_0280A0_COLOR_8_24: + case V_0280A0_COLOR_24_8: + case V_0280A0_COLOR_32_FLOAT: + case V_0280A0_COLOR_16_16_FLOAT: + case V_0280A0_COLOR_16_16: + return ENDIAN_8IN32; + + /* 64-bit buffers. */ + case V_0280A0_COLOR_16_16_16_16: + case V_0280A0_COLOR_16_16_16_16_FLOAT: + return ENDIAN_8IN16; + + case V_0280A0_COLOR_32_32_FLOAT: + case V_0280A0_COLOR_32_32: + case V_0280A0_COLOR_X24_8_32_FLOAT: + return ENDIAN_8IN32; + + /* 128-bit buffers. */ + case V_0280A0_COLOR_32_32_32_FLOAT: + case V_0280A0_COLOR_32_32_32_32_FLOAT: + case V_0280A0_COLOR_32_32_32_32: + return ENDIAN_8IN32; + default: + return ENDIAN_NONE; /* Unsupported. */ + } + } else { + return ENDIAN_NONE; + } +} + +static bool r600_is_sampler_format_supported(struct pipe_screen *screen, enum pipe_format format) +{ + return r600_translate_texformat(screen, format, NULL, NULL, NULL) != ~0U; +} + +static bool r600_is_colorbuffer_format_supported(enum pipe_format format) +{ + return r600_translate_colorformat(format) != ~0U && + r600_translate_colorswap(format) != ~0U; +} + +static bool r600_is_zs_format_supported(enum pipe_format format) +{ + return r600_translate_dbformat(format) != ~0U; +} + +boolean r600_is_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned usage) +{ + unsigned retval = 0; + + if (target >= PIPE_MAX_TEXTURE_TYPES) { + R600_ERR("r600: unsupported texture type %d\n", target); + return FALSE; + } + + if (!util_format_is_supported(format, usage)) + return FALSE; + + /* Multisample */ + if (sample_count > 1) + return FALSE; + + if ((usage & PIPE_BIND_SAMPLER_VIEW) && + r600_is_sampler_format_supported(screen, format)) { + retval |= PIPE_BIND_SAMPLER_VIEW; + } + + if ((usage & (PIPE_BIND_RENDER_TARGET | + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED)) && + r600_is_colorbuffer_format_supported(format)) { + retval |= usage & + (PIPE_BIND_RENDER_TARGET | + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED); + } + + if ((usage & PIPE_BIND_DEPTH_STENCIL) && + r600_is_zs_format_supported(format)) { + retval |= PIPE_BIND_DEPTH_STENCIL; + } + + if ((usage & PIPE_BIND_VERTEX_BUFFER) && + r600_is_vertex_format_supported(format)) { + retval |= PIPE_BIND_VERTEX_BUFFER; + } + + if (usage & PIPE_BIND_TRANSFER_READ) + retval |= PIPE_BIND_TRANSFER_READ; + if (usage & PIPE_BIND_TRANSFER_WRITE) + retval |= PIPE_BIND_TRANSFER_WRITE; + + return retval == usage; +} void r600_polygon_offset_update(struct r600_pipe_context *rctx) { @@ -63,6 +646,7 @@ void r600_polygon_offset_update(struct r600_pipe_context *rctx) offset_units *= 2.0f; break; case PIPE_FORMAT_Z32_FLOAT: + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: depth = -23; offset_units *= 1.0f; offset_db_fmt_cntl |= S_028DF8_POLY_OFFSET_DB_IS_FLOAT_FMT(1); @@ -299,6 +883,8 @@ static void *r600_create_rs_state(struct pipe_context *ctx, } rstate = &rs->rstate; + rs->clamp_vertex_color = state->clamp_vertex_color; + rs->clamp_fragment_color = state->clamp_fragment_color; rs->flatshade = state->flatshade; rs->sprite_coord_enable = state->sprite_coord_enable; @@ -369,14 +955,17 @@ static void *r600_create_rs_state(struct pipe_context *ctx, static void *r600_create_sampler_state(struct pipe_context *ctx, const struct pipe_sampler_state *state) { - struct r600_pipe_state *rstate = CALLOC_STRUCT(r600_pipe_state); + struct r600_pipe_sampler_state *ss = CALLOC_STRUCT(r600_pipe_sampler_state); + struct r600_pipe_state *rstate; union util_color uc; unsigned aniso_flag_offset = state->max_anisotropy > 1 ? 4 : 0; - if (rstate == NULL) { + if (ss == NULL) { return NULL; } + ss->seamless_cube_map = state->seamless_cube_map; + rstate = &ss->rstate; rstate->id = R600_PIPE_STATE_SAMPLER; util_pack_color(state->border_color, PIPE_FORMAT_B8G8R8A8_UNORM, &uc); r600_pipe_state_add_reg_noblock(rstate, R_03C000_SQ_TEX_SAMPLER_WORD0_0, @@ -488,8 +1077,8 @@ static struct pipe_sampler_view *r600_create_sampler_view(struct pipe_context *c rstate->val[1] = (S_038004_TEX_HEIGHT(height - 1) | S_038004_TEX_DEPTH(depth - 1) | S_038004_DATA_FORMAT(format)); - rstate->val[2] = (tmp->offset[offset_level] + r600_bo_offset(bo[0])) >> 8; - rstate->val[3] = (tmp->offset[offset_level+1] + r600_bo_offset(bo[1])) >> 8; + rstate->val[2] = tmp->offset[offset_level] >> 8; + rstate->val[3] = tmp->offset[offset_level+1] >> 8; rstate->val[4] = (word4 | S_038010_SRF_MODE_ALL(V_038010_SRF_MODE_ZERO_CLAMP_MINUS_ONE) | S_038010_REQUEST_SIZE(1) | @@ -559,27 +1148,57 @@ static void r600_set_ps_sampler_view(struct pipe_context *ctx, unsigned count, rctx->ps_samplers.n_views = count; } +static void r600_set_seamless_cubemap(struct r600_pipe_context *rctx, boolean enable) +{ + struct r600_pipe_state *rstate = CALLOC_STRUCT(r600_pipe_state); + if (rstate == NULL) + return; + + rstate->id = R600_PIPE_STATE_SEAMLESS_CUBEMAP; + r600_pipe_state_add_reg(rstate, R_009508_TA_CNTL_AUX, + (enable ? 0 : S_009508_DISABLE_CUBE_WRAP(1)), + 1, NULL); + + free(rctx->states[R600_PIPE_STATE_SEAMLESS_CUBEMAP]); + rctx->states[R600_PIPE_STATE_SEAMLESS_CUBEMAP] = rstate; + r600_context_pipe_state_set(&rctx->ctx, rstate); +} + static void r600_bind_ps_sampler(struct pipe_context *ctx, unsigned count, void **states) { struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; - struct r600_pipe_state **rstates = (struct r600_pipe_state **)states; + struct r600_pipe_sampler_state **sstates = (struct r600_pipe_sampler_state **)states; + int seamless = -1; memcpy(rctx->ps_samplers.samplers, states, sizeof(void*) * count); rctx->ps_samplers.n_samplers = count; for (int i = 0; i < count; i++) { - r600_context_pipe_state_set_ps_sampler(&rctx->ctx, rstates[i], i); + r600_context_pipe_state_set_ps_sampler(&rctx->ctx, &sstates[i]->rstate, i); + + if (sstates[i]) + seamless = sstates[i]->seamless_cube_map; } + + if (seamless != -1) + r600_set_seamless_cubemap(rctx, seamless); } static void r600_bind_vs_sampler(struct pipe_context *ctx, unsigned count, void **states) { struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; - struct r600_pipe_state **rstates = (struct r600_pipe_state **)states; + struct r600_pipe_sampler_state **sstates = (struct r600_pipe_sampler_state **)states; + int seamless = -1; for (int i = 0; i < count; i++) { - r600_context_pipe_state_set_vs_sampler(&rctx->ctx, rstates[i], i); + r600_context_pipe_state_set_vs_sampler(&rctx->ctx, &sstates[i]->rstate, i); + + if (sstates[i]) + seamless = sstates[i]->seamless_cube_map; } + + if (seamless != -1) + r600_set_seamless_cubemap(rctx, seamless); } static void r600_set_clip_state(struct pipe_context *ctx, @@ -792,7 +1411,7 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta /* EXPORT_NORM is an optimzation that can be enabled for better * performance in certain cases */ - if (rctx->family < CHIP_RV770) { + if (rctx->chip_class == R600) { /* EXPORT_NORM can be enabled if: * - 11-bit or smaller UNORM/SNORM/SRGB * - BLEND_CLAMP is enabled @@ -822,7 +1441,7 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta r600_pipe_state_add_reg(rstate, R_028040_CB_COLOR0_BASE + cb * 4, - (offset + r600_bo_offset(bo[0])) >> 8, 0xFFFFFFFF, bo[0]); + offset >> 8, 0xFFFFFFFF, bo[0]); r600_pipe_state_add_reg(rstate, R_0280A0_CB_COLOR0_INFO + cb * 4, color_info, 0xFFFFFFFF, bo[0]); @@ -836,10 +1455,10 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_0280E0_CB_COLOR0_FRAG + cb * 4, - r600_bo_offset(bo[1]) >> 8, 0xFFFFFFFF, bo[1]); + 0, 0xFFFFFFFF, bo[1]); r600_pipe_state_add_reg(rstate, R_0280C0_CB_COLOR0_TILE + cb * 4, - r600_bo_offset(bo[2]) >> 8, 0xFFFFFFFF, bo[2]); + 0, 0xFFFFFFFF, bo[2]); r600_pipe_state_add_reg(rstate, R_028100_CB_COLOR0_MASK + cb * 4, 0x00000000, 0xFFFFFFFF, NULL); @@ -873,7 +1492,7 @@ static void r600_db(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta format = r600_translate_dbformat(state->zsbuf->texture->format); r600_pipe_state_add_reg(rstate, R_02800C_DB_DEPTH_BASE, - (offset + r600_bo_offset(rbuffer->bo)) >> 8, 0xFFFFFFFF, rbuffer->bo); + offset >> 8, 0xFFFFFFFF, rbuffer->bo); r600_pipe_state_add_reg(rstate, R_028000_DB_DEPTH_SIZE, S_028000_PITCH_TILE_MAX(pitch) | S_028000_SLICE_TILE_MAX(slice), 0xFFFFFFFF, NULL); @@ -952,7 +1571,7 @@ static void r600_set_framebuffer_state(struct pipe_context *ctx, r600_pipe_state_add_reg(rstate, R_028200_PA_SC_WINDOW_OFFSET, 0x00000000, 0xFFFFFFFF, NULL); - if (rctx->family >= CHIP_RV770) { + if (rctx->chip_class >= R700) { r600_pipe_state_add_reg(rstate, R_028230_PA_SC_EDGERULE, 0xAAAAAAAA, 0xFFFFFFFF, NULL); @@ -1046,16 +1665,13 @@ void r600_init_state_functions(struct r600_pipe_context *rctx) void r600_adjust_gprs(struct r600_pipe_context *rctx) { - enum radeon_family family; struct r600_pipe_state rstate; unsigned num_ps_gprs = rctx->default_ps_gprs; unsigned num_vs_gprs = rctx->default_vs_gprs; unsigned tmp; int diff; - family = r600_get_family(rctx->radeon); - - if (family >= CHIP_CEDAR) + if (rctx->chip_class >= EVERGREEN) return; if (!rctx->ps_shader && !rctx->vs_shader) @@ -1107,7 +1723,7 @@ void r600_init_config(struct r600_pipe_context *rctx) struct r600_pipe_state *rstate = &rctx->config; u32 tmp; - family = r600_get_family(rctx->radeon); + family = rctx->family; ps_prio = 0; vs_prio = 1; gs_prio = 2; @@ -1288,16 +1904,24 @@ void r600_init_config(struct r600_pipe_context *rctx) r600_pipe_state_add_reg(rstate, R_009714_VC_ENHANCE, 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028350_SX_MISC, 0x00000000, 0xFFFFFFFF, NULL); - if (family >= CHIP_RV770) { + if (rctx->chip_class >= R700) { r600_pipe_state_add_reg(rstate, R_008D8C_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ, 0x00004000, 0xFFFFFFFF, NULL); - r600_pipe_state_add_reg(rstate, R_009508_TA_CNTL_AUX, 0x07000002, 0xFFFFFFFF, NULL); + r600_pipe_state_add_reg(rstate, R_009508_TA_CNTL_AUX, + S_009508_DISABLE_CUBE_ANISO(1) | + S_009508_SYNC_GRADIENT(1) | + S_009508_SYNC_WALKER(1) | + S_009508_SYNC_ALIGNER(1), 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_009830_DB_DEBUG, 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_009838_DB_WATERMARKS, 0x00420204, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_0286C8_SPI_THREAD_GROUPING, 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028A4C_PA_SC_MODE_CNTL, 0x00514002, 0xFFFFFFFF, NULL); } else { r600_pipe_state_add_reg(rstate, R_008D8C_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ, 0x00000000, 0xFFFFFFFF, NULL); - r600_pipe_state_add_reg(rstate, R_009508_TA_CNTL_AUX, 0x07000003, 0xFFFFFFFF, NULL); + r600_pipe_state_add_reg(rstate, R_009508_TA_CNTL_AUX, + S_009508_DISABLE_CUBE_ANISO(1) | + S_009508_SYNC_GRADIENT(1) | + S_009508_SYNC_WALKER(1) | + S_009508_SYNC_ALIGNER(1), 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_009830_DB_DEBUG, 0x82000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_009838_DB_WATERMARKS, 0x01020204, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_0286C8_SPI_THREAD_GROUPING, 0x00000001, 0xFFFFFFFF, NULL); @@ -1403,7 +2027,7 @@ void r600_pipe_shader_ps(struct pipe_context *ctx, struct r600_pipe_shader *shad r600_pipe_state_add_reg(rstate, R_0286D8_SPI_INPUT_Z, spi_input_z, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028840_SQ_PGM_START_PS, - r600_bo_offset(shader->bo) >> 8, 0xFFFFFFFF, shader->bo); + 0, 0xFFFFFFFF, shader->bo); r600_pipe_state_add_reg(rstate, R_028850_SQ_PGM_RESOURCES_PS, S_028868_NUM_GPRS(rshader->bc.ngpr) | @@ -1438,7 +2062,7 @@ void r600_pipe_shader_vs(struct pipe_context *ctx, struct r600_pipe_shader *shad struct r600_pipe_state *rstate = &shader->rstate; struct r600_shader *rshader = &shader->shader; unsigned spi_vs_out_id[10]; - unsigned i, tmp; + unsigned i, tmp, nparams; /* clear previous register */ rstate->nregs = 0; @@ -1460,9 +2084,17 @@ void r600_pipe_shader_vs(struct pipe_context *ctx, struct r600_pipe_shader *shad spi_vs_out_id[i], 0xFFFFFFFF, NULL); } + /* Certain attributes (position, psize, etc.) don't count as params. + * VS is required to export at least one param and r600_shader_from_tgsi() + * takes care of adding a dummy export. + */ + nparams = rshader->noutput - rshader->npos; + if (nparams < 1) + nparams = 1; + r600_pipe_state_add_reg(rstate, R_0286C4_SPI_VS_OUT_CONFIG, - S_0286C4_VS_EXPORT_COUNT(rshader->noutput - 2), + S_0286C4_VS_EXPORT_COUNT(nparams - 1), 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028868_SQ_PGM_RESOURCES_VS, @@ -1474,7 +2106,7 @@ void r600_pipe_shader_vs(struct pipe_context *ctx, struct r600_pipe_shader *shad 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028858_SQ_PGM_START_VS, - r600_bo_offset(shader->bo) >> 8, 0xFFFFFFFF, shader->bo); + 0, 0xFFFFFFFF, shader->bo); r600_pipe_state_add_reg(rstate, R_03E200_SQ_LOOP_CONST_0 + (32 * 4), 0x01000FFF, @@ -1495,7 +2127,7 @@ void r600_fetch_shader(struct pipe_context *ctx, r600_pipe_state_add_reg(rstate, R_0288DC_SQ_PGM_CF_OFFSET_FS, 0x00000000, 0xFFFFFFFF, NULL); r600_pipe_state_add_reg(rstate, R_028894_SQ_PGM_START_FS, - r600_bo_offset(ve->fetch_shader) >> 8, + 0, 0xFFFFFFFF, ve->fetch_shader); } diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index fa0c5cb89d7..9f3ab89fdf7 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -28,6 +28,7 @@ #include <util/u_format.h> #include <pipebuffer/pb_buffer.h> #include "pipe/p_shader_tokens.h" +#include "tgsi/tgsi_parse.h" #include "r600_formats.h" #include "r600_pipe.h" #include "r600d.h" @@ -99,6 +100,8 @@ void r600_bind_rs_state(struct pipe_context *ctx, void *state) if (state == NULL) return; + rctx->clamp_vertex_color = rs->clamp_vertex_color; + rctx->clamp_fragment_color = rs->clamp_fragment_color; rctx->flatshade = rs->flatshade; rctx->sprite_coord_enable = rs->sprite_coord_enable; rctx->rasterizer = rs; @@ -106,13 +109,13 @@ void r600_bind_rs_state(struct pipe_context *ctx, void *state) rctx->states[rs->rstate.id] = &rs->rstate; r600_context_pipe_state_set(&rctx->ctx, &rs->rstate); - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_polygon_offset_update(rctx); } else { r600_polygon_offset_update(rctx); } if (rctx->ps_shader && rctx->vs_shader) - r600_spi_update(rctx); + rctx->spi_dirty = true; } void r600_delete_rs_state(struct pipe_context *ctx, void *state) @@ -209,7 +212,7 @@ void r600_set_vertex_buffers(struct pipe_context *ctx, unsigned count, /* Zero states. */ for (i = 0; i < count; i++) { if (!buffers[i].buffer) { - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_context_pipe_state_set_fs_resource(&rctx->ctx, NULL, i); } else { r600_context_pipe_state_set_fs_resource(&rctx->ctx, NULL, i); @@ -217,7 +220,7 @@ void r600_set_vertex_buffers(struct pipe_context *ctx, unsigned count, } } for (; i < rctx->vbuf_mgr->nr_real_vertex_buffers; i++) { - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_context_pipe_state_set_fs_resource(&rctx->ctx, NULL, i); } else { r600_context_pipe_state_set_fs_resource(&rctx->ctx, NULL, i); @@ -257,7 +260,9 @@ void *r600_create_shader_state(struct pipe_context *ctx, struct r600_pipe_shader *shader = CALLOC_STRUCT(r600_pipe_shader); int r; - r = r600_pipe_shader_create(ctx, shader, state->tokens); + shader->tokens = tgsi_dup_tokens(state->tokens); + + r = r600_pipe_shader_create(ctx, shader); if (r) { return NULL; } @@ -274,7 +279,7 @@ void r600_bind_ps_shader(struct pipe_context *ctx, void *state) r600_context_pipe_state_set(&rctx->ctx, &rctx->ps_shader->rstate); } if (rctx->ps_shader && rctx->vs_shader) { - r600_spi_update(rctx); + rctx->spi_dirty = true; r600_adjust_gprs(rctx); } } @@ -289,7 +294,7 @@ void r600_bind_vs_shader(struct pipe_context *ctx, void *state) r600_context_pipe_state_set(&rctx->ctx, &rctx->vs_shader->rstate); } if (rctx->ps_shader && rctx->vs_shader) { - r600_spi_update(rctx); + rctx->spi_dirty = true; r600_adjust_gprs(rctx); } } @@ -303,6 +308,7 @@ void r600_delete_ps_shader(struct pipe_context *ctx, void *state) rctx->ps_shader = NULL; } + free(shader->tokens); r600_pipe_shader_destroy(ctx, shader); free(shader); } @@ -316,6 +322,7 @@ void r600_delete_vs_shader(struct pipe_context *ctx, void *state) rctx->vs_shader = NULL; } + free(shader->tokens); r600_pipe_shader_destroy(ctx, shader); free(shader); } @@ -351,7 +358,7 @@ static void r600_spi_update(struct r600_pipe_context *rctx) struct r600_pipe_shader *shader = rctx->ps_shader; struct r600_pipe_state *rstate = &rctx->spi; struct r600_shader *rshader = &shader->shader; - unsigned i, tmp; + unsigned i, tmp, sid; if (rctx->spi.id == 0) r600_spi_block_init(rctx, &rctx->spi); @@ -360,9 +367,14 @@ static void r600_spi_update(struct r600_pipe_context *rctx) for (i = 0; i < rshader->ninput; i++) { if (rshader->input[i].name == TGSI_SEMANTIC_POSITION || rshader->input[i].name == TGSI_SEMANTIC_FACE) - continue; + if (rctx->chip_class >= EVERGREEN) + continue; + else + sid=0; + else + sid=r600_find_vs_semantic_index(&rctx->vs_shader->shader, rshader, i); - tmp = S_028644_SEMANTIC(r600_find_vs_semantic_index(&rctx->vs_shader->shader, rshader, i)); + tmp = S_028644_SEMANTIC(sid); if (rshader->input[i].name == TGSI_SEMANTIC_COLOR || rshader->input[i].name == TGSI_SEMANTIC_BCOLOR || @@ -375,7 +387,7 @@ static void r600_spi_update(struct r600_pipe_context *rctx) tmp |= S_028644_PT_SPRITE_TEX(1); } - if (rctx->family < CHIP_CEDAR) { + if (rctx->chip_class < EVERGREEN) { if (rshader->input[i].centroid) tmp |= S_028644_SEL_CENTROID(1); @@ -386,6 +398,7 @@ static void r600_spi_update(struct r600_pipe_context *rctx) r600_pipe_state_mod_reg(rstate, tmp); } + rctx->spi_dirty = false; r600_context_pipe_state_set(&rctx->ctx, rstate); } @@ -405,7 +418,6 @@ void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint index, } r600_upload_const_buffer(rctx, &rbuffer, &offset); - offset += r600_bo_offset(rbuffer->r.bo); switch (shader) { case PIPE_SHADER_VERTEX: @@ -421,14 +433,14 @@ void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint index, rstate = &rctx->vs_const_buffer_resource[index]; if (!rstate->id) { - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_init_buffer_resource(rctx, rstate); } else { r600_pipe_init_buffer_resource(rctx, rstate); } } - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_mod_buffer_resource(rstate, &rbuffer->r, offset, 16); evergreen_context_pipe_state_set_vs_resource(&rctx->ctx, rstate, index); } else { @@ -449,13 +461,13 @@ void r600_set_constant_buffer(struct pipe_context *ctx, uint shader, uint index, rstate = &rctx->ps_const_buffer_resource[index]; if (!rstate->id) { - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_init_buffer_resource(rctx, rstate); } else { r600_pipe_init_buffer_resource(rctx, rstate); } } - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_mod_buffer_resource(rstate, &rbuffer->r, offset, 16); evergreen_context_pipe_state_set_ps_resource(&rctx->ctx, rstate, index); } else { @@ -505,17 +517,17 @@ static void r600_vertex_buffer_update(struct r600_pipe_context *rctx) } if (vertex_buffer == NULL || rbuffer == NULL) continue; - offset += vertex_buffer->buffer_offset + r600_bo_offset(rbuffer->bo); + offset += vertex_buffer->buffer_offset; if (!rstate->id) { - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_init_buffer_resource(rctx, rstate); } else { r600_pipe_init_buffer_resource(rctx, rstate); } } - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_pipe_mod_buffer_resource(rstate, rbuffer, offset, vertex_buffer->stride); evergreen_context_pipe_state_set_fs_resource(&rctx->ctx, rstate, i); } else { @@ -525,24 +537,39 @@ static void r600_vertex_buffer_update(struct r600_pipe_context *rctx) } } +static int r600_shader_rebuild(struct pipe_context * ctx, struct r600_pipe_shader * shader) +{ + struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; + int r; + + r600_pipe_shader_destroy(ctx, shader); + r = r600_pipe_shader_create(ctx, shader); + if (r) { + return r; + } + r600_context_pipe_state_set(&rctx->ctx, &shader->rstate); + + return 0; +} + void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) { struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; struct r600_resource *rbuffer; - u32 vgt_dma_index_type, vgt_dma_swap_mode, vgt_draw_initiator, mask; struct r600_draw rdraw; - struct r600_drawl draw = {}; - unsigned prim; + struct r600_drawl draw; + unsigned prim, mask; if (!rctx->blit) { if (rctx->have_depth_fb || rctx->have_depth_texture) r600_flush_depth_textures(rctx); } - u_vbuf_mgr_draw_begin(rctx->vbuf_mgr, info, NULL, NULL); + u_vbuf_mgr_draw_begin(rctx->vbuf_mgr, info); r600_vertex_buffer_update(rctx); draw.info = *info; draw.ctx = ctx; + draw.index_buffer = NULL; if (info->indexed && rctx->index_buffer.buffer) { draw.info.start += rctx->index_buffer.offset / rctx->index_buffer.index_size; pipe_resource_reference(&draw.index_buffer, rctx->index_buffer.buffer); @@ -560,57 +587,29 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) r600_upload_index_buffer(rctx, &draw); } } else { + draw.index_size = 0; + draw.index_buffer_offset = 0; draw.info.index_bias = info->start; } - vgt_dma_swap_mode = 0; - switch (draw.index_size) { - case 2: - vgt_draw_initiator = 0; - vgt_dma_index_type = 0; - if (R600_BIG_ENDIAN) { - vgt_dma_swap_mode = ENDIAN_8IN16; - } - break; - case 4: - vgt_draw_initiator = 0; - vgt_dma_index_type = 1; - if (R600_BIG_ENDIAN) { - vgt_dma_swap_mode = ENDIAN_8IN32; - } - break; - case 0: - vgt_draw_initiator = 2; - vgt_dma_index_type = 0; - break; - default: - R600_ERR("unsupported index size %d\n", draw.index_size); - return; - } if (r600_conv_pipe_prim(draw.info.mode, &prim)) return; - if (unlikely(rctx->ps_shader == NULL)) { - R600_ERR("missing vertex shader\n"); - return; - } - if (unlikely(rctx->vs_shader == NULL)) { - R600_ERR("missing vertex shader\n"); - return; - } - /* there should be enough input */ - if (rctx->vertex_elements->count < rctx->vs_shader->shader.bc.nresource) { - R600_ERR("%d resources provided, expecting %d\n", - rctx->vertex_elements->count, rctx->vs_shader->shader.bc.nresource); - return; - } + + if (rctx->vs_shader->shader.clamp_color != rctx->clamp_vertex_color) + r600_shader_rebuild(ctx, rctx->vs_shader); + + if ((rctx->ps_shader->shader.clamp_color != rctx->clamp_fragment_color) || + ((rctx->chip_class >= EVERGREEN) && rctx->ps_shader->shader.fs_write_all && + (rctx->ps_shader->shader.nr_cbufs != rctx->nr_cbufs))) + r600_shader_rebuild(ctx, rctx->ps_shader); + + if (rctx->spi_dirty) + r600_spi_update(rctx); if (rctx->alpha_ref_dirty) r600_update_alpha_ref(rctx); - mask = 0; - for (int i = 0; i < rctx->framebuffer.nr_cbufs; i++) { - mask |= (0xF << (i * 4)); - } + mask = (1ULL << ((unsigned)rctx->framebuffer.nr_cbufs * 4)) - 1; if (rctx->vgt.id != R600_PIPE_STATE_VGT) { rctx->vgt.id = R600_PIPE_STATE_VGT; @@ -644,8 +643,10 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) rdraw.vgt_num_indices = draw.info.count; rdraw.vgt_num_instances = draw.info.instance_count; - rdraw.vgt_index_type = vgt_dma_index_type | (vgt_dma_swap_mode << 2); - rdraw.vgt_draw_initiator = vgt_draw_initiator; + rdraw.vgt_index_type = ((draw.index_size == 4) ? 1 : 0); + if (R600_BIG_ENDIAN) + rdraw.vgt_index_type |= (draw.index_size >> 1) << 2; + rdraw.vgt_draw_initiator = draw.index_size ? 0 : 2; rdraw.indices = NULL; if (draw.index_buffer) { rbuffer = (struct r600_resource*)draw.index_buffer; @@ -653,7 +654,7 @@ void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) rdraw.indices_bo_offset = draw.index_buffer_offset; } - if (rctx->family >= CHIP_CEDAR) { + if (rctx->chip_class >= EVERGREEN) { evergreen_context_draw(&rctx->ctx, &rdraw); } else { r600_context_draw(&rctx->ctx, &rdraw); diff --git a/src/gallium/drivers/r600/r600_state_inlines.h b/src/gallium/drivers/r600/r600_state_inlines.h deleted file mode 100644 index 5418570756f..00000000000 --- a/src/gallium/drivers/r600/r600_state_inlines.h +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright 2010 Red Hat 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 - * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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. - */ -#ifndef R600_STATE_INLINES_H -#define R600_STATE_INLINES_H - -#include "util/u_format.h" -#include "r600d.h" -#include "r600_formats.h" - -static INLINE uint32_t r600_translate_blend_function(int blend_func) -{ - switch (blend_func) { - case PIPE_BLEND_ADD: - return V_028804_COMB_DST_PLUS_SRC; - case PIPE_BLEND_SUBTRACT: - return V_028804_COMB_SRC_MINUS_DST; - case PIPE_BLEND_REVERSE_SUBTRACT: - return V_028804_COMB_DST_MINUS_SRC; - case PIPE_BLEND_MIN: - return V_028804_COMB_MIN_DST_SRC; - case PIPE_BLEND_MAX: - return V_028804_COMB_MAX_DST_SRC; - default: - R600_ERR("Unknown blend function %d\n", blend_func); - assert(0); - break; - } - return 0; -} - -static INLINE uint32_t r600_translate_blend_factor(int blend_fact) -{ - switch (blend_fact) { - case PIPE_BLENDFACTOR_ONE: - return V_028804_BLEND_ONE; - case PIPE_BLENDFACTOR_SRC_COLOR: - return V_028804_BLEND_SRC_COLOR; - case PIPE_BLENDFACTOR_SRC_ALPHA: - return V_028804_BLEND_SRC_ALPHA; - case PIPE_BLENDFACTOR_DST_ALPHA: - return V_028804_BLEND_DST_ALPHA; - case PIPE_BLENDFACTOR_DST_COLOR: - return V_028804_BLEND_DST_COLOR; - case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - return V_028804_BLEND_SRC_ALPHA_SATURATE; - case PIPE_BLENDFACTOR_CONST_COLOR: - return V_028804_BLEND_CONST_COLOR; - case PIPE_BLENDFACTOR_CONST_ALPHA: - return V_028804_BLEND_CONST_ALPHA; - case PIPE_BLENDFACTOR_ZERO: - return V_028804_BLEND_ZERO; - case PIPE_BLENDFACTOR_INV_SRC_COLOR: - return V_028804_BLEND_ONE_MINUS_SRC_COLOR; - case PIPE_BLENDFACTOR_INV_SRC_ALPHA: - return V_028804_BLEND_ONE_MINUS_SRC_ALPHA; - case PIPE_BLENDFACTOR_INV_DST_ALPHA: - return V_028804_BLEND_ONE_MINUS_DST_ALPHA; - case PIPE_BLENDFACTOR_INV_DST_COLOR: - return V_028804_BLEND_ONE_MINUS_DST_COLOR; - case PIPE_BLENDFACTOR_INV_CONST_COLOR: - return V_028804_BLEND_ONE_MINUS_CONST_COLOR; - case PIPE_BLENDFACTOR_INV_CONST_ALPHA: - return V_028804_BLEND_ONE_MINUS_CONST_ALPHA; - case PIPE_BLENDFACTOR_SRC1_COLOR: - return V_028804_BLEND_SRC1_COLOR; - case PIPE_BLENDFACTOR_SRC1_ALPHA: - return V_028804_BLEND_SRC1_ALPHA; - case PIPE_BLENDFACTOR_INV_SRC1_COLOR: - return V_028804_BLEND_INV_SRC1_COLOR; - case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: - return V_028804_BLEND_INV_SRC1_ALPHA; - default: - R600_ERR("Bad blend factor %d not supported!\n", blend_fact); - assert(0); - break; - } - return 0; -} - -static INLINE uint32_t r600_translate_stencil_op(int s_op) -{ - switch (s_op) { - case PIPE_STENCIL_OP_KEEP: - return V_028800_STENCIL_KEEP; - case PIPE_STENCIL_OP_ZERO: - return V_028800_STENCIL_ZERO; - case PIPE_STENCIL_OP_REPLACE: - return V_028800_STENCIL_REPLACE; - case PIPE_STENCIL_OP_INCR: - return V_028800_STENCIL_INCR; - case PIPE_STENCIL_OP_DECR: - return V_028800_STENCIL_DECR; - case PIPE_STENCIL_OP_INCR_WRAP: - return V_028800_STENCIL_INCR_WRAP; - case PIPE_STENCIL_OP_DECR_WRAP: - return V_028800_STENCIL_DECR_WRAP; - case PIPE_STENCIL_OP_INVERT: - return V_028800_STENCIL_INVERT; - default: - R600_ERR("Unknown stencil op %d", s_op); - assert(0); - break; - } - return 0; -} - -static INLINE uint32_t r600_translate_fill(uint32_t func) -{ - switch(func) { - case PIPE_POLYGON_MODE_FILL: - return 2; - case PIPE_POLYGON_MODE_LINE: - return 1; - case PIPE_POLYGON_MODE_POINT: - return 0; - default: - assert(0); - return 0; - } -} - -/* translates straight */ -static INLINE uint32_t r600_translate_ds_func(int func) -{ - return func; -} - -static inline unsigned r600_tex_wrap(unsigned wrap) -{ - switch (wrap) { - default: - case PIPE_TEX_WRAP_REPEAT: - return V_03C000_SQ_TEX_WRAP; - case PIPE_TEX_WRAP_CLAMP: - return V_03C000_SQ_TEX_CLAMP_HALF_BORDER; - case PIPE_TEX_WRAP_CLAMP_TO_EDGE: - return V_03C000_SQ_TEX_CLAMP_LAST_TEXEL; - case PIPE_TEX_WRAP_CLAMP_TO_BORDER: - return V_03C000_SQ_TEX_CLAMP_BORDER; - case PIPE_TEX_WRAP_MIRROR_REPEAT: - return V_03C000_SQ_TEX_MIRROR; - case PIPE_TEX_WRAP_MIRROR_CLAMP: - return V_03C000_SQ_TEX_MIRROR_ONCE_HALF_BORDER; - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: - return V_03C000_SQ_TEX_MIRROR_ONCE_LAST_TEXEL; - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: - return V_03C000_SQ_TEX_MIRROR_ONCE_BORDER; - } -} - -static inline unsigned r600_tex_filter(unsigned filter) -{ - switch (filter) { - default: - case PIPE_TEX_FILTER_NEAREST: - return V_03C000_SQ_TEX_XY_FILTER_POINT; - case PIPE_TEX_FILTER_LINEAR: - return V_03C000_SQ_TEX_XY_FILTER_BILINEAR; - } -} - -static inline unsigned r600_tex_mipfilter(unsigned filter) -{ - switch (filter) { - case PIPE_TEX_MIPFILTER_NEAREST: - return V_03C000_SQ_TEX_Z_FILTER_POINT; - case PIPE_TEX_MIPFILTER_LINEAR: - return V_03C000_SQ_TEX_Z_FILTER_LINEAR; - default: - case PIPE_TEX_MIPFILTER_NONE: - return V_03C000_SQ_TEX_Z_FILTER_NONE; - } -} - -static inline unsigned r600_tex_compare(unsigned compare) -{ - switch (compare) { - default: - case PIPE_FUNC_NEVER: - return V_03C000_SQ_TEX_DEPTH_COMPARE_NEVER; - case PIPE_FUNC_LESS: - return V_03C000_SQ_TEX_DEPTH_COMPARE_LESS; - case PIPE_FUNC_EQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_EQUAL; - case PIPE_FUNC_LEQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_LESSEQUAL; - case PIPE_FUNC_GREATER: - return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATER; - case PIPE_FUNC_NOTEQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_NOTEQUAL; - case PIPE_FUNC_GEQUAL: - return V_03C000_SQ_TEX_DEPTH_COMPARE_GREATEREQUAL; - case PIPE_FUNC_ALWAYS: - return V_03C000_SQ_TEX_DEPTH_COMPARE_ALWAYS; - } -} - -static inline unsigned r600_tex_swizzle(unsigned swizzle) -{ - switch (swizzle) { - case PIPE_SWIZZLE_RED: - return V_038010_SQ_SEL_X; - case PIPE_SWIZZLE_GREEN: - return V_038010_SQ_SEL_Y; - case PIPE_SWIZZLE_BLUE: - return V_038010_SQ_SEL_Z; - case PIPE_SWIZZLE_ALPHA: - return V_038010_SQ_SEL_W; - case PIPE_SWIZZLE_ZERO: - return V_038010_SQ_SEL_0; - default: - case PIPE_SWIZZLE_ONE: - return V_038010_SQ_SEL_1; - } -} - -static inline unsigned r600_format_type(unsigned format_type) -{ - switch (format_type) { - default: - case UTIL_FORMAT_TYPE_UNSIGNED: - return V_038010_SQ_FORMAT_COMP_UNSIGNED; - case UTIL_FORMAT_TYPE_SIGNED: - return V_038010_SQ_FORMAT_COMP_SIGNED; - case UTIL_FORMAT_TYPE_FIXED: - return V_038010_SQ_FORMAT_COMP_UNSIGNED_BIASED; - } -} - -static inline unsigned r600_tex_dim(unsigned dim) -{ - switch (dim) { - default: - case PIPE_TEXTURE_1D: - return V_038000_SQ_TEX_DIM_1D; - case PIPE_TEXTURE_1D_ARRAY: - return V_038000_SQ_TEX_DIM_1D_ARRAY; - case PIPE_TEXTURE_2D: - case PIPE_TEXTURE_RECT: - return V_038000_SQ_TEX_DIM_2D; - case PIPE_TEXTURE_2D_ARRAY: - return V_038000_SQ_TEX_DIM_2D_ARRAY; - case PIPE_TEXTURE_3D: - return V_038000_SQ_TEX_DIM_3D; - case PIPE_TEXTURE_CUBE: - return V_038000_SQ_TEX_DIM_CUBEMAP; - } -} - -static inline uint32_t r600_translate_dbformat(enum pipe_format format) -{ - switch (format) { - case PIPE_FORMAT_Z16_UNORM: - return V_028010_DEPTH_16; - case PIPE_FORMAT_Z24X8_UNORM: - return V_028010_DEPTH_X8_24; - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_028010_DEPTH_8_24; - default: - return ~0; - } -} - -static inline uint32_t r600_translate_colorswap(enum pipe_format format) -{ - switch (format) { - /* 8-bit buffers. */ - case PIPE_FORMAT_A8_UNORM: - return V_0280A0_SWAP_ALT_REV; - case PIPE_FORMAT_I8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_L8_SRGB: - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R8_SNORM: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_L4A4_UNORM: - return V_0280A0_SWAP_ALT; - - /* 16-bit buffers. */ - case PIPE_FORMAT_B5G6R5_UNORM: - return V_0280A0_SWAP_STD_REV; - - case PIPE_FORMAT_B5G5R5A1_UNORM: - case PIPE_FORMAT_B5G5R5X1_UNORM: - return V_0280A0_SWAP_ALT; - - case PIPE_FORMAT_B4G4R4A4_UNORM: - case PIPE_FORMAT_B4G4R4X4_UNORM: - return V_0280A0_SWAP_ALT; - - case PIPE_FORMAT_Z16_UNORM: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_L8A8_SRGB: - return V_0280A0_SWAP_ALT; - case PIPE_FORMAT_R8G8_UNORM: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_R16_UNORM: - return V_0280A0_SWAP_STD; - - /* 32-bit buffers. */ - - case PIPE_FORMAT_A8B8G8R8_SRGB: - return V_0280A0_SWAP_STD_REV; - case PIPE_FORMAT_B8G8R8A8_SRGB: - return V_0280A0_SWAP_ALT; - - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - return V_0280A0_SWAP_ALT; - - case PIPE_FORMAT_A8R8G8B8_UNORM: - case PIPE_FORMAT_X8R8G8B8_UNORM: - return V_0280A0_SWAP_ALT_REV; - case PIPE_FORMAT_R8G8B8A8_SNORM: - case PIPE_FORMAT_R8G8B8A8_UNORM: - case PIPE_FORMAT_R8G8B8X8_UNORM: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_A8B8G8R8_UNORM: - case PIPE_FORMAT_X8B8G8R8_UNORM: - /* case PIPE_FORMAT_R8SG8SB8UX8U_NORM: */ - return V_0280A0_SWAP_STD_REV; - - case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_X8Z24_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_R10G10B10A2_UNORM: - case PIPE_FORMAT_R10G10B10X2_SNORM: - case PIPE_FORMAT_R10SG10SB10SA2U_NORM: - return V_0280A0_SWAP_STD; - - case PIPE_FORMAT_B10G10R10A2_UNORM: - return V_0280A0_SWAP_ALT; - - case PIPE_FORMAT_R11G11B10_FLOAT: - case PIPE_FORMAT_R16G16_UNORM: - case PIPE_FORMAT_R16G16_FLOAT: - case PIPE_FORMAT_R32_FLOAT: - return V_0280A0_SWAP_STD; - - /* 64-bit buffers. */ - case PIPE_FORMAT_R32G32_FLOAT: - case PIPE_FORMAT_R16G16B16A16_UNORM: - case PIPE_FORMAT_R16G16B16A16_SNORM: - case PIPE_FORMAT_R16G16B16A16_FLOAT: - - /* 128-bit buffers. */ - case PIPE_FORMAT_R32G32B32A32_FLOAT: - case PIPE_FORMAT_R32G32B32A32_SNORM: - case PIPE_FORMAT_R32G32B32A32_UNORM: - return V_0280A0_SWAP_STD; - default: - R600_ERR("unsupported colorswap format %d\n", format); - return ~0; - } - return ~0; -} - -static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) -{ - switch (format) { - case PIPE_FORMAT_L4A4_UNORM: - return V_0280A0_COLOR_4_4; - - /* 8-bit buffers. */ - case PIPE_FORMAT_A8_UNORM: - case PIPE_FORMAT_I8_UNORM: - case PIPE_FORMAT_L8_UNORM: - case PIPE_FORMAT_L8_SRGB: - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R8_SNORM: - return V_0280A0_COLOR_8; - - /* 16-bit buffers. */ - case PIPE_FORMAT_B5G6R5_UNORM: - return V_0280A0_COLOR_5_6_5; - - case PIPE_FORMAT_B5G5R5A1_UNORM: - case PIPE_FORMAT_B5G5R5X1_UNORM: - return V_0280A0_COLOR_1_5_5_5; - - case PIPE_FORMAT_B4G4R4A4_UNORM: - case PIPE_FORMAT_B4G4R4X4_UNORM: - return V_0280A0_COLOR_4_4_4_4; - - case PIPE_FORMAT_Z16_UNORM: - return V_0280A0_COLOR_16; - - case PIPE_FORMAT_L8A8_UNORM: - case PIPE_FORMAT_L8A8_SRGB: - case PIPE_FORMAT_R8G8_UNORM: - return V_0280A0_COLOR_8_8; - - case PIPE_FORMAT_R16_UNORM: - return V_0280A0_COLOR_16; - - /* 32-bit buffers. */ - case PIPE_FORMAT_A8B8G8R8_SRGB: - case PIPE_FORMAT_A8B8G8R8_UNORM: - case PIPE_FORMAT_A8R8G8B8_UNORM: - case PIPE_FORMAT_B8G8R8A8_SRGB: - case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_R8G8B8A8_SNORM: - case PIPE_FORMAT_R8G8B8A8_UNORM: - case PIPE_FORMAT_R8G8B8X8_UNORM: - case PIPE_FORMAT_R8SG8SB8UX8U_NORM: - case PIPE_FORMAT_X8B8G8R8_UNORM: - case PIPE_FORMAT_X8R8G8B8_UNORM: - case PIPE_FORMAT_R8G8B8_UNORM: - return V_0280A0_COLOR_8_8_8_8; - - case PIPE_FORMAT_R10G10B10A2_UNORM: - case PIPE_FORMAT_R10G10B10X2_SNORM: - case PIPE_FORMAT_B10G10R10A2_UNORM: - case PIPE_FORMAT_R10SG10SB10SA2U_NORM: - return V_0280A0_COLOR_2_10_10_10; - - case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: - return V_0280A0_COLOR_8_24; - - case PIPE_FORMAT_X8Z24_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - return V_0280A0_COLOR_24_8; - - case PIPE_FORMAT_R32_FLOAT: - return V_0280A0_COLOR_32_FLOAT; - - case PIPE_FORMAT_R16G16_FLOAT: - return V_0280A0_COLOR_16_16_FLOAT; - - case PIPE_FORMAT_R16G16_SSCALED: - case PIPE_FORMAT_R16G16_UNORM: - return V_0280A0_COLOR_16_16; - - case PIPE_FORMAT_R11G11B10_FLOAT: - return V_0280A0_COLOR_10_11_11_FLOAT; - - /* 64-bit buffers. */ - case PIPE_FORMAT_R16G16B16_USCALED: - case PIPE_FORMAT_R16G16B16A16_USCALED: - case PIPE_FORMAT_R16G16B16_SSCALED: - case PIPE_FORMAT_R16G16B16A16_SSCALED: - case PIPE_FORMAT_R16G16B16A16_UNORM: - case PIPE_FORMAT_R16G16B16A16_SNORM: - return V_0280A0_COLOR_16_16_16_16; - - case PIPE_FORMAT_R16G16B16_FLOAT: - case PIPE_FORMAT_R16G16B16A16_FLOAT: - return V_0280A0_COLOR_16_16_16_16_FLOAT; - - case PIPE_FORMAT_R32G32_FLOAT: - return V_0280A0_COLOR_32_32_FLOAT; - - case PIPE_FORMAT_R32G32_USCALED: - case PIPE_FORMAT_R32G32_SSCALED: - return V_0280A0_COLOR_32_32; - - /* 96-bit buffers. */ - case PIPE_FORMAT_R32G32B32_FLOAT: - return V_0280A0_COLOR_32_32_32_FLOAT; - - /* 128-bit buffers. */ - case PIPE_FORMAT_R32G32B32A32_FLOAT: - return V_0280A0_COLOR_32_32_32_32_FLOAT; - case PIPE_FORMAT_R32G32B32A32_SNORM: - case PIPE_FORMAT_R32G32B32A32_UNORM: - return V_0280A0_COLOR_32_32_32_32; - - /* YUV buffers. */ - case PIPE_FORMAT_UYVY: - case PIPE_FORMAT_YUYV: - default: - return ~0; /* Unsupported. */ - } -} - -static INLINE uint32_t r600_colorformat_endian_swap(uint32_t colorformat) -{ - if (R600_BIG_ENDIAN) { - switch(colorformat) { - case V_0280A0_COLOR_4_4: - return(ENDIAN_NONE); - - /* 8-bit buffers. */ - case V_0280A0_COLOR_8: - return(ENDIAN_NONE); - - /* 16-bit buffers. */ - case V_0280A0_COLOR_5_6_5: - case V_0280A0_COLOR_1_5_5_5: - case V_0280A0_COLOR_4_4_4_4: - case V_0280A0_COLOR_16: - case V_0280A0_COLOR_8_8: - return(ENDIAN_8IN16); - - /* 32-bit buffers. */ - case V_0280A0_COLOR_8_8_8_8: - case V_0280A0_COLOR_2_10_10_10: - case V_0280A0_COLOR_8_24: - case V_0280A0_COLOR_24_8: - case V_0280A0_COLOR_32_FLOAT: - case V_0280A0_COLOR_16_16_FLOAT: - case V_0280A0_COLOR_16_16: - return(ENDIAN_8IN32); - - /* 64-bit buffers. */ - case V_0280A0_COLOR_16_16_16_16: - case V_0280A0_COLOR_16_16_16_16_FLOAT: - return(ENDIAN_8IN16); - - case V_0280A0_COLOR_32_32_FLOAT: - case V_0280A0_COLOR_32_32: - return(ENDIAN_8IN32); - - /* 128-bit buffers. */ - case V_0280A0_COLOR_32_32_32_FLOAT: - case V_0280A0_COLOR_32_32_32_32_FLOAT: - case V_0280A0_COLOR_32_32_32_32: - return(ENDIAN_8IN32); - default: - return ENDIAN_NONE; /* Unsupported. */ - } - } else { - return ENDIAN_NONE; - } -} - -static INLINE boolean r600_is_sampler_format_supported(struct pipe_screen *screen, enum pipe_format format) -{ - return r600_translate_texformat(screen, format, NULL, NULL, NULL) != ~0; -} - -static INLINE boolean r600_is_colorbuffer_format_supported(enum pipe_format format) -{ - return r600_translate_colorformat(format) != ~0 && - r600_translate_colorswap(format) != ~0; -} - -static INLINE boolean r600_is_zs_format_supported(enum pipe_format format) -{ - return r600_translate_dbformat(format) != ~0; -} - -static INLINE boolean r600_is_vertex_format_supported(enum pipe_format format, - enum radeon_family family) -{ - unsigned i; - const struct util_format_description *desc = util_format_description(format); - if (!desc) - return FALSE; - - /* Find the first non-VOID channel. */ - for (i = 0; i < 4; i++) { - if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { - break; - } - } - if (i == 4) - return FALSE; - - /* No fixed, no double. */ - if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || - desc->channel[i].type == UTIL_FORMAT_TYPE_FIXED || - (desc->channel[i].size == 64 && - desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT)) - return FALSE; - - /* No scaled/norm formats with 32 bits per channel. */ - if (desc->channel[i].size == 32 && - (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED || - desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED)) - return FALSE; - - return TRUE; -} - -#endif diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c index 470d26e2c9f..927eb5dafc9 100644 --- a/src/gallium/drivers/r600/r600_texture.c +++ b/src/gallium/drivers/r600/r600_texture.c @@ -35,7 +35,6 @@ #include "pipebuffer/pb_buffer.h" #include "r600_pipe.h" #include "r600_resource.h" -#include "r600_state_inlines.h" #include "r600d.h" #include "r600_formats.h" @@ -243,10 +242,11 @@ static void r600_setup_miptree(struct pipe_screen *screen, struct radeon *radeon = (struct radeon *)screen->winsys; enum chip_class chipc = r600_get_family_class(radeon); unsigned size, layer_size, i, offset; - unsigned nblocksx, nblocksy; + unsigned nblocksx, nblocksy, extra_size = 0; for (i = 0, offset = 0; i <= ptex->last_level; i++) { unsigned blocksize = util_format_get_blocksize(ptex->format); + unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode); r600_texture_set_array_mode(screen, rtex, i, array_mode); @@ -265,9 +265,13 @@ static void r600_setup_miptree(struct pipe_screen *screen, else size = layer_size * ptex->array_size; + /* evergreen stores depth and stencil separately */ + if ((chipc >= EVERGREEN) && util_format_is_depth_or_stencil(ptex->format)) + extra_size = align(extra_size + (nblocksx * nblocksy * 1), base_align); + /* align base image and start of miptree */ if ((i == 0) || (i == 1)) - offset = align(offset, r600_get_base_alignment(screen, ptex->format, array_mode)); + offset = align(offset, base_align); rtex->offset[i] = offset; rtex->layer_size[i] = layer_size; rtex->pitch_in_blocks[i] = nblocksx; /* CB talks in elements */ @@ -275,7 +279,7 @@ static void r600_setup_miptree(struct pipe_screen *screen, offset += size; } - rtex->size = offset; + rtex->size = offset + extra_size; } /* Figure out whether u_blitter will fallback to a transfer operation. @@ -309,7 +313,14 @@ static boolean permit_hardware_blit(struct pipe_screen *screen, PIPE_BIND_SAMPLER_VIEW)) return FALSE; - return TRUE; + switch (res->usage) { + case PIPE_USAGE_STREAM: + case PIPE_USAGE_STAGING: + return FALSE; + + default: + return TRUE; + } } static boolean r600_texture_get_handle(struct pipe_screen* screen, @@ -678,7 +689,6 @@ void* r600_texture_transfer_map(struct pipe_context *ctx, enum pipe_format format = transfer->resource->format; struct radeon *radeon = (struct radeon *)ctx->screen->winsys; unsigned offset = 0; - unsigned usage = 0; char *map; if (rtransfer->staging_texture) { @@ -696,30 +706,7 @@ void* r600_texture_transfer_map(struct pipe_context *ctx, transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); } - if (transfer->usage & PIPE_TRANSFER_WRITE) { - usage |= PB_USAGE_CPU_WRITE; - - if (transfer->usage & PIPE_TRANSFER_DISCARD) { - } - - if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) { - } - } - - if (transfer->usage & PIPE_TRANSFER_READ) { - usage |= PB_USAGE_CPU_READ; - } - - if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) { - usage |= PB_USAGE_DONTBLOCK; - } - - if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { - usage |= PB_USAGE_UNSYNCHRONIZED; - } - - map = r600_bo_map(radeon, bo, usage, ctx); - if (!map) { + if (!(map = r600_bo_map(radeon, bo, transfer->usage, ctx))) { return NULL; } @@ -767,11 +754,7 @@ static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, }; if (swizzle_view) { - /* Combine two sets of swizzles. */ - for (i = 0; i < 4; i++) { - swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ? - swizzle_format[swizzle_view[i]] : swizzle_view[i]; - } + util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle); } else { memcpy(swizzle, swizzle_format, 4); } @@ -847,6 +830,12 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, result = FMT_8; word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); goto out_word4; + case PIPE_FORMAT_Z32_FLOAT: + result = FMT_32_FLOAT; + goto out_word4; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + result = FMT_X24_8_32_FLOAT; + goto out_word4; default: goto out_unknown; } diff --git a/src/gallium/drivers/r600/r600d.h b/src/gallium/drivers/r600/r600d.h index 6373572b65f..f6eec24cc05 100644 --- a/src/gallium/drivers/r600/r600d.h +++ b/src/gallium/drivers/r600/r600d.h @@ -2556,6 +2556,9 @@ #define S_009508_DISABLE_CUBE_WRAP(x) (((x) & 0x1) << 0) #define G_009508_DISABLE_CUBE_WRAP(x) (((x) >> 0) & 0x1) #define C_009508_DISABLE_CUBE_WRAP 0xFFFFFFFE +#define S_009508_DISABLE_CUBE_ANISO(x) (((x) & 0x1) << 1) +#define G_009508_DISABLE_CUBE_ANISO(x) (((x) >> 1) & 0x1) +#define C_009508_DISABLE_CUBE_ANISO (~(1 << 1)) #define S_009508_SYNC_GRADIENT(x) (((x) & 0x1) << 24) #define G_009508_SYNC_GRADIENT(x) (((x) >> 24) & 0x1) #define C_009508_SYNC_GRADIENT 0xFEFFFFFF diff --git a/src/gallium/drivers/softpipe/Makefile b/src/gallium/drivers/softpipe/Makefile index 28953582f0a..9403e6cf0b8 100644 --- a/src/gallium/drivers/softpipe/Makefile +++ b/src/gallium/drivers/softpipe/Makefile @@ -19,7 +19,7 @@ C_SOURCES = \ sp_quad_fs.c \ sp_quad_blend.c \ sp_screen.c \ - sp_setup.c \ + sp_setup.c \ sp_state_blend.c \ sp_state_clip.c \ sp_state_derived.c \ diff --git a/src/gallium/drivers/softpipe/sp_clear.c b/src/gallium/drivers/softpipe/sp_clear.c index ae3f00f3387..22e8a2e5817 100644 --- a/src/gallium/drivers/softpipe/sp_clear.c +++ b/src/gallium/drivers/softpipe/sp_clear.c @@ -60,7 +60,7 @@ softpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, return; #if 0 - softpipe_update_derived(softpipe); /* not needed?? */ + softpipe_update_derived(softpipe, PIPE_PRIM_TRIANGLES); /* not needed?? */ #endif if (buffers & PIPE_CLEAR_COLOR) { diff --git a/src/gallium/drivers/softpipe/sp_context.c b/src/gallium/drivers/softpipe/sp_context.c index ce22f646228..c97b0333035 100644 --- a/src/gallium/drivers/softpipe/sp_context.c +++ b/src/gallium/drivers/softpipe/sp_context.c @@ -35,8 +35,11 @@ #include "pipe/p_defines.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_pstipple.h" #include "util/u_inlines.h" #include "tgsi/tgsi_exec.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "sp_clear.h" #include "sp_context.h" #include "sp_flush.h" @@ -88,6 +91,14 @@ softpipe_destroy( struct pipe_context *pipe ) struct softpipe_context *softpipe = softpipe_context( pipe ); uint i; +#if DO_PSTIPPLE_IN_HELPER_MODULE + if (softpipe->pstipple.sampler) + pipe->delete_sampler_state(pipe, softpipe->pstipple.sampler); + + pipe_resource_reference(&softpipe->pstipple.texture, NULL); + pipe_sampler_view_reference(&softpipe->pstipple.sampler_view, NULL); +#endif + if (softpipe->draw) draw_destroy( softpipe->draw ); @@ -258,6 +269,9 @@ softpipe_create_context( struct pipe_screen *screen, softpipe->pipe.flush = softpipe_flush_wrapped; softpipe->pipe.render_condition = softpipe_render_condition; + + softpipe->pipe.create_video_decoder = vl_create_decoder; + softpipe->pipe.create_video_buffer = vl_video_buffer_create; /* * Alloc caches for accessing drawing surfaces and textures. @@ -341,6 +355,11 @@ softpipe_create_context( struct pipe_screen *screen, sp_init_surface_functions(softpipe); +#if DO_PSTIPPLE_IN_HELPER_MODULE + /* create the polgon stipple sampler */ + softpipe->pstipple.sampler = util_pstipple_create_sampler(&softpipe->pipe); +#endif + return &softpipe->pipe; fail: diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h index a572ee8cf00..410b0a65792 100644 --- a/src/gallium/drivers/softpipe/sp_context.h +++ b/src/gallium/drivers/softpipe/sp_context.h @@ -38,8 +38,11 @@ #include "sp_quad_pipe.h" -/** Do polygon stipple in the driver here, or in the draw module? */ -#define DO_PSTIPPLE_IN_DRAW_MODULE 1 +/** Do polygon stipple in the draw module? */ +#define DO_PSTIPPLE_IN_DRAW_MODULE 0 + +/** Do polygon stipple with the util module? */ +#define DO_PSTIPPLE_IN_HELPER_MODULE 1 struct softpipe_vbuf_render; @@ -64,6 +67,7 @@ struct softpipe_context { struct pipe_depth_stencil_alpha_state *depth_stencil; struct pipe_rasterizer_state *rasterizer; struct sp_fragment_shader *fs; + struct sp_fragment_shader_variant *fs_variant; struct sp_vertex_shader *vs; struct sp_geometry_shader *gs; struct sp_velems_state *velems; @@ -143,6 +147,13 @@ struct softpipe_context { struct pipe_query *render_cond_query; uint render_cond_mode; + /** Polygon stipple items */ + struct { + struct pipe_resource *texture; + struct pipe_sampler_state *sampler; + struct pipe_sampler_view *sampler_view; + } pstipple; + /** Software quad rendering pipeline */ struct { struct quad_stage *shade; diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c index 01b4ca985d0..69b5b96b4fd 100644 --- a/src/gallium/drivers/softpipe/sp_draw_arrays.c +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c @@ -64,7 +64,7 @@ softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode) sp->reduced_api_prim = u_reduced_prim(mode); if (sp->dirty) { - softpipe_update_derived(sp); + softpipe_update_derived(sp, sp->reduced_api_prim); } softpipe_map_transfers(sp); @@ -122,7 +122,7 @@ softpipe_draw_vbo(struct pipe_context *pipe, sp->reduced_api_prim = u_reduced_prim(info->mode); if (sp->dirty) { - softpipe_update_derived(sp); + softpipe_update_derived(sp, sp->reduced_api_prim); } softpipe_map_transfers(sp); diff --git a/src/gallium/drivers/softpipe/sp_fs.h b/src/gallium/drivers/softpipe/sp_fs.h index 4792ace3a33..d46d7d5a657 100644 --- a/src/gallium/drivers/softpipe/sp_fs.h +++ b/src/gallium/drivers/softpipe/sp_fs.h @@ -31,17 +31,15 @@ #ifndef SP_FS_H #define SP_FS_H -struct sp_fragment_shader * -softpipe_create_fs_exec(struct softpipe_context *softpipe, - const struct pipe_shader_state *templ); -struct sp_fragment_shader * -softpipe_create_fs_sse(struct softpipe_context *softpipe, - const struct pipe_shader_state *templ); +struct sp_fragment_shader_variant * +softpipe_create_fs_variant_exec(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct sp_fragment_shader_variant * +softpipe_create_fs_variant_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); -struct sp_fragment_shader * -softpipe_create_fs_llvm(struct softpipe_context *softpipe, - const struct pipe_shader_state *templ); struct tgsi_interp_coef; struct tgsi_exec_vector; diff --git a/src/gallium/drivers/softpipe/sp_fs_exec.c b/src/gallium/drivers/softpipe/sp_fs_exec.c index 346e1b402ba..779b8c4995c 100644 --- a/src/gallium/drivers/softpipe/sp_fs_exec.c +++ b/src/gallium/drivers/softpipe/sp_fs_exec.c @@ -42,25 +42,25 @@ /** - * Subclass of sp_fragment_shader + * Subclass of sp_fragment_shader_variant */ struct sp_exec_fragment_shader { - struct sp_fragment_shader base; + struct sp_fragment_shader_variant base; /* No other members for now */ }; /** cast wrapper */ static INLINE struct sp_exec_fragment_shader * -sp_exec_fragment_shader(const struct sp_fragment_shader *base) +sp_exec_fragment_shader(const struct sp_fragment_shader_variant *var) { - return (struct sp_exec_fragment_shader *) base; + return (struct sp_exec_fragment_shader *) var; } static void -exec_prepare( const struct sp_fragment_shader *base, +exec_prepare( const struct sp_fragment_shader_variant *var, struct tgsi_exec_machine *machine, struct tgsi_sampler **samplers ) { @@ -68,9 +68,9 @@ exec_prepare( const struct sp_fragment_shader *base, * Bind tokens/shader to the interpreter's machine state. * Avoid redundant binding. */ - if (machine->Tokens != base->shader.tokens) { + if (machine->Tokens != var->tokens) { tgsi_exec_machine_bind_shader( machine, - base->shader.tokens, + var->tokens, PIPE_MAX_SAMPLERS, samplers ); } @@ -118,7 +118,7 @@ setup_pos_vector(const struct tgsi_interp_coef *coef, * interface: */ static unsigned -exec_run( const struct sp_fragment_shader *base, +exec_run( const struct sp_fragment_shader_variant *var, struct tgsi_exec_machine *machine, struct quad_header *quad ) { @@ -136,9 +136,9 @@ exec_run( const struct sp_fragment_shader *base, /* store outputs */ { - const ubyte *sem_name = base->info.output_semantic_name; - const ubyte *sem_index = base->info.output_semantic_index; - const uint n = base->info.num_outputs; + const ubyte *sem_name = var->info.output_semantic_name; + const ubyte *sem_index = var->info.output_semantic_index; + const uint n = var->info.num_outputs; uint i; for (i = 0; i < n; i++) { switch (sem_name[i]) { @@ -180,29 +180,23 @@ exec_run( const struct sp_fragment_shader *base, static void -exec_delete( struct sp_fragment_shader *base ) +exec_delete( struct sp_fragment_shader_variant *var ) { - FREE((void *) base->shader.tokens); - FREE(base); + FREE( (void *) var->tokens ); + FREE(var); } -struct sp_fragment_shader * -softpipe_create_fs_exec(struct softpipe_context *softpipe, - const struct pipe_shader_state *templ) +struct sp_fragment_shader_variant * +softpipe_create_fs_variant_exec(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) { struct sp_exec_fragment_shader *shader; - /* Decide whether we'll be codegenerating this shader and if so do - * that now. - */ - shader = CALLOC_STRUCT(sp_exec_fragment_shader); if (!shader) return NULL; - /* we need to keep a local copy of the tokens */ - shader->base.shader.tokens = tgsi_dup_tokens(templ->tokens); shader->base.prepare = exec_prepare; shader->base.run = exec_run; shader->base.delete = exec_delete; diff --git a/src/gallium/drivers/softpipe/sp_fs_sse.c b/src/gallium/drivers/softpipe/sp_fs_sse.c index 5b18cd035e3..c873af125bd 100644 --- a/src/gallium/drivers/softpipe/sp_fs_sse.c +++ b/src/gallium/drivers/softpipe/sp_fs_sse.c @@ -48,11 +48,11 @@ /** - * Subclass of sp_fragment_shader + * Subclass of sp_fragment_shader_variant */ struct sp_sse_fragment_shader { - struct sp_fragment_shader base; + struct sp_fragment_shader_variant base; struct x86_function sse2_program; tgsi_sse2_fs_function func; float immediates[TGSI_EXEC_NUM_IMMEDIATES][4]; @@ -61,14 +61,14 @@ struct sp_sse_fragment_shader /** cast wrapper */ static INLINE struct sp_sse_fragment_shader * -sp_sse_fragment_shader(const struct sp_fragment_shader *base) +sp_sse_fragment_shader(const struct sp_fragment_shader_variant *base) { return (struct sp_sse_fragment_shader *) base; } static void -fs_sse_prepare( const struct sp_fragment_shader *base, +fs_sse_prepare( const struct sp_fragment_shader_variant *base, struct tgsi_exec_machine *machine, struct tgsi_sampler **samplers ) { @@ -119,7 +119,7 @@ setup_pos_vector(const struct tgsi_interp_coef *coef, * TODO: process >1 quad at a time */ static unsigned -fs_sse_run( const struct sp_fragment_shader *base, +fs_sse_run( const struct sp_fragment_shader_variant *base, struct tgsi_exec_machine *machine, struct quad_header *quad ) { @@ -189,7 +189,7 @@ fs_sse_run( const struct sp_fragment_shader *base, static void -fs_sse_delete( struct sp_fragment_shader *base ) +fs_sse_delete( struct sp_fragment_shader_variant *base ) { struct sp_sse_fragment_shader *shader = sp_sse_fragment_shader(base); @@ -198,9 +198,9 @@ fs_sse_delete( struct sp_fragment_shader *base ) } -struct sp_fragment_shader * -softpipe_create_fs_sse(struct softpipe_context *softpipe, - const struct pipe_shader_state *templ) +struct sp_fragment_shader_variant * +softpipe_create_fs_variant_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) { struct sp_sse_fragment_shader *shader; @@ -226,7 +226,6 @@ softpipe_create_fs_sse(struct softpipe_context *softpipe, return NULL; } - shader->base.shader.tokens = NULL; /* don't hold reference to templ->tokens */ shader->base.prepare = fs_sse_prepare; shader->base.run = fs_sse_run; shader->base.delete = fs_sse_delete; @@ -239,9 +238,9 @@ softpipe_create_fs_sse(struct softpipe_context *softpipe, /* Maybe put this variant in the header file. */ -struct sp_fragment_shader * -softpipe_create_fs_sse(struct softpipe_context *softpipe, - const struct pipe_shader_state *templ) +struct sp_fragment_shader_variant * +softpipe_create_fs_variant_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) { return NULL; } diff --git a/src/gallium/drivers/softpipe/sp_quad_blend.c b/src/gallium/drivers/softpipe/sp_quad_blend.c index 76cfc0bf51c..c881194768a 100644 --- a/src/gallium/drivers/softpipe/sp_quad_blend.c +++ b/src/gallium/drivers/softpipe/sp_quad_blend.c @@ -240,6 +240,7 @@ blend_quad(struct quad_stage *qs, static const float one[4] = { 1, 1, 1, 1 }; struct softpipe_context *softpipe = qs->softpipe; float source[4][QUAD_SIZE] = { { 0 } }; + float blend_dest[4][QUAD_SIZE]; /* * Compute src/first term RGB @@ -480,79 +481,85 @@ blend_quad(struct quad_stage *qs, assert(0 && "invalid alpha src factor"); } + /* Save the original dest for use in masking */ + VEC4_COPY(blend_dest[0], dest[0]); + VEC4_COPY(blend_dest[1], dest[1]); + VEC4_COPY(blend_dest[2], dest[2]); + VEC4_COPY(blend_dest[3], dest[3]); + /* - * Compute dest/second term RGB + * Compute blend_dest/second term RGB */ switch (softpipe->blend->rt[blend_index].rgb_dst_factor) { case PIPE_BLENDFACTOR_ONE: - /* dest = dest * 1 NO-OP, leave dest as-is */ + /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ break; case PIPE_BLENDFACTOR_SRC_COLOR: - VEC4_MUL(dest[0], dest[0], quadColor[0]); /* R */ - VEC4_MUL(dest[1], dest[1], quadColor[1]); /* G */ - VEC4_MUL(dest[2], dest[2], quadColor[2]); /* B */ + VEC4_MUL(blend_dest[0], blend_dest[0], quadColor[0]); /* R */ + VEC4_MUL(blend_dest[1], blend_dest[1], quadColor[1]); /* G */ + VEC4_MUL(blend_dest[2], blend_dest[2], quadColor[2]); /* B */ break; case PIPE_BLENDFACTOR_SRC_ALPHA: - VEC4_MUL(dest[0], dest[0], quadColor[3]); /* R * A */ - VEC4_MUL(dest[1], dest[1], quadColor[3]); /* G * A */ - VEC4_MUL(dest[2], dest[2], quadColor[3]); /* B * A */ + VEC4_MUL(blend_dest[0], blend_dest[0], quadColor[3]); /* R * A */ + VEC4_MUL(blend_dest[1], blend_dest[1], quadColor[3]); /* G * A */ + VEC4_MUL(blend_dest[2], blend_dest[2], quadColor[3]); /* B * A */ break; case PIPE_BLENDFACTOR_DST_ALPHA: if (has_dst_alpha) { - VEC4_MUL(dest[0], dest[0], dest[3]); /* R * A */ - VEC4_MUL(dest[1], dest[1], dest[3]); /* G * A */ - VEC4_MUL(dest[2], dest[2], dest[3]); /* B * A */ + VEC4_MUL(blend_dest[0], blend_dest[0], blend_dest[3]); /* R * A */ + VEC4_MUL(blend_dest[1], blend_dest[1], blend_dest[3]); /* G * A */ + VEC4_MUL(blend_dest[2], blend_dest[2], blend_dest[3]); /* B * A */ } else { - /* dest = dest * 1 NO-OP, leave dest as-is */ + /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ } break; case PIPE_BLENDFACTOR_DST_COLOR: - VEC4_MUL(dest[0], dest[0], dest[0]); /* R */ - VEC4_MUL(dest[1], dest[1], dest[1]); /* G */ - VEC4_MUL(dest[2], dest[2], dest[2]); /* B */ + VEC4_MUL(blend_dest[0], blend_dest[0], blend_dest[0]); /* R */ + VEC4_MUL(blend_dest[1], blend_dest[1], blend_dest[1]); /* G */ + VEC4_MUL(blend_dest[2], blend_dest[2], blend_dest[2]); /* B */ break; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: if (has_dst_alpha) { const float *alpha = quadColor[3]; float diff[4], temp[4]; - VEC4_SUB(diff, one, dest[3]); + VEC4_SUB(diff, one, blend_dest[3]); VEC4_MIN(temp, alpha, diff); - VEC4_MUL(dest[0], quadColor[0], temp); /* R */ - VEC4_MUL(dest[1], quadColor[1], temp); /* G */ - VEC4_MUL(dest[2], quadColor[2], temp); /* B */ + VEC4_MUL(blend_dest[0], quadColor[0], temp); /* R */ + VEC4_MUL(blend_dest[1], quadColor[1], temp); /* G */ + VEC4_MUL(blend_dest[2], quadColor[2], temp); /* B */ } else { - VEC4_COPY(dest[0], zero); /* R */ - VEC4_COPY(dest[1], zero); /* G */ - VEC4_COPY(dest[2], zero); /* B */ + VEC4_COPY(blend_dest[0], zero); /* R */ + VEC4_COPY(blend_dest[1], zero); /* G */ + VEC4_COPY(blend_dest[2], zero); /* B */ } break; case PIPE_BLENDFACTOR_CONST_COLOR: { float comp[4]; VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */ - VEC4_MUL(dest[0], dest[0], comp); /* R */ + VEC4_MUL(blend_dest[0], blend_dest[0], comp); /* R */ VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */ - VEC4_MUL(dest[1], dest[1], comp); /* G */ + VEC4_MUL(blend_dest[1], blend_dest[1], comp); /* G */ VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */ - VEC4_MUL(dest[2], dest[2], comp); /* B */ + VEC4_MUL(blend_dest[2], blend_dest[2], comp); /* B */ } break; case PIPE_BLENDFACTOR_CONST_ALPHA: { float comp[4]; VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ - VEC4_MUL(dest[0], dest[0], comp); /* R */ - VEC4_MUL(dest[1], dest[1], comp); /* G */ - VEC4_MUL(dest[2], dest[2], comp); /* B */ + VEC4_MUL(blend_dest[0], blend_dest[0], comp); /* R */ + VEC4_MUL(blend_dest[1], blend_dest[1], comp); /* G */ + VEC4_MUL(blend_dest[2], blend_dest[2], comp); /* B */ } break; case PIPE_BLENDFACTOR_ZERO: - VEC4_COPY(dest[0], zero); /* R */ - VEC4_COPY(dest[1], zero); /* G */ - VEC4_COPY(dest[2], zero); /* B */ + VEC4_COPY(blend_dest[0], zero); /* R */ + VEC4_COPY(blend_dest[1], zero); /* G */ + VEC4_COPY(blend_dest[2], zero); /* B */ break; case PIPE_BLENDFACTOR_SRC1_COLOR: case PIPE_BLENDFACTOR_SRC1_ALPHA: @@ -563,45 +570,45 @@ blend_quad(struct quad_stage *qs, { float inv_comp[4]; VEC4_SUB(inv_comp, one, quadColor[0]); /* R */ - VEC4_MUL(dest[0], inv_comp, dest[0]); /* R */ + VEC4_MUL(blend_dest[0], inv_comp, blend_dest[0]); /* R */ VEC4_SUB(inv_comp, one, quadColor[1]); /* G */ - VEC4_MUL(dest[1], inv_comp, dest[1]); /* G */ + VEC4_MUL(blend_dest[1], inv_comp, blend_dest[1]); /* G */ VEC4_SUB(inv_comp, one, quadColor[2]); /* B */ - VEC4_MUL(dest[2], inv_comp, dest[2]); /* B */ + VEC4_MUL(blend_dest[2], inv_comp, blend_dest[2]); /* B */ } break; case PIPE_BLENDFACTOR_INV_SRC_ALPHA: { float one_minus_alpha[QUAD_SIZE]; VEC4_SUB(one_minus_alpha, one, quadColor[3]); - VEC4_MUL(dest[0], dest[0], one_minus_alpha); /* R */ - VEC4_MUL(dest[1], dest[1], one_minus_alpha); /* G */ - VEC4_MUL(dest[2], dest[2], one_minus_alpha); /* B */ + VEC4_MUL(blend_dest[0], blend_dest[0], one_minus_alpha); /* R */ + VEC4_MUL(blend_dest[1], blend_dest[1], one_minus_alpha); /* G */ + VEC4_MUL(blend_dest[2], blend_dest[2], one_minus_alpha); /* B */ } break; case PIPE_BLENDFACTOR_INV_DST_ALPHA: if (has_dst_alpha) { float inv_comp[4]; - VEC4_SUB(inv_comp, one, dest[3]); /* A */ - VEC4_MUL(dest[0], inv_comp, dest[0]); /* R */ - VEC4_MUL(dest[1], inv_comp, dest[1]); /* G */ - VEC4_MUL(dest[2], inv_comp, dest[2]); /* B */ + VEC4_SUB(inv_comp, one, blend_dest[3]); /* A */ + VEC4_MUL(blend_dest[0], inv_comp, blend_dest[0]); /* R */ + VEC4_MUL(blend_dest[1], inv_comp, blend_dest[1]); /* G */ + VEC4_MUL(blend_dest[2], inv_comp, blend_dest[2]); /* B */ } else { - VEC4_COPY(dest[0], zero); /* R */ - VEC4_COPY(dest[1], zero); /* G */ - VEC4_COPY(dest[2], zero); /* B */ + VEC4_COPY(blend_dest[0], zero); /* R */ + VEC4_COPY(blend_dest[1], zero); /* G */ + VEC4_COPY(blend_dest[2], zero); /* B */ } break; case PIPE_BLENDFACTOR_INV_DST_COLOR: { float inv_comp[4]; - VEC4_SUB(inv_comp, one, dest[0]); /* R */ - VEC4_MUL(dest[0], dest[0], inv_comp); /* R */ - VEC4_SUB(inv_comp, one, dest[1]); /* G */ - VEC4_MUL(dest[1], dest[1], inv_comp); /* G */ - VEC4_SUB(inv_comp, one, dest[2]); /* B */ - VEC4_MUL(dest[2], dest[2], inv_comp); /* B */ + VEC4_SUB(inv_comp, one, blend_dest[0]); /* R */ + VEC4_MUL(blend_dest[0], blend_dest[0], inv_comp); /* R */ + VEC4_SUB(inv_comp, one, blend_dest[1]); /* G */ + VEC4_MUL(blend_dest[1], blend_dest[1], inv_comp); /* G */ + VEC4_SUB(inv_comp, one, blend_dest[2]); /* B */ + VEC4_MUL(blend_dest[2], blend_dest[2], inv_comp); /* B */ } break; case PIPE_BLENDFACTOR_INV_CONST_COLOR: @@ -609,22 +616,22 @@ blend_quad(struct quad_stage *qs, float inv_comp[4]; /* R */ VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]); - VEC4_MUL(dest[0], dest[0], inv_comp); + VEC4_MUL(blend_dest[0], blend_dest[0], inv_comp); /* G */ VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]); - VEC4_MUL(dest[1], dest[1], inv_comp); + VEC4_MUL(blend_dest[1], blend_dest[1], inv_comp); /* B */ VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]); - VEC4_MUL(dest[2], dest[2], inv_comp); + VEC4_MUL(blend_dest[2], blend_dest[2], inv_comp); } break; case PIPE_BLENDFACTOR_INV_CONST_ALPHA: { float inv_comp[4]; VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); - VEC4_MUL(dest[0], dest[0], inv_comp); - VEC4_MUL(dest[1], dest[1], inv_comp); - VEC4_MUL(dest[2], dest[2], inv_comp); + VEC4_MUL(blend_dest[0], blend_dest[0], inv_comp); + VEC4_MUL(blend_dest[1], blend_dest[1], inv_comp); + VEC4_MUL(blend_dest[2], blend_dest[2], inv_comp); } break; case PIPE_BLENDFACTOR_INV_SRC1_COLOR: @@ -637,29 +644,29 @@ blend_quad(struct quad_stage *qs, } /* - * Compute dest/second term A + * Compute blend_dest/second term A */ switch (softpipe->blend->rt[blend_index].alpha_dst_factor) { case PIPE_BLENDFACTOR_ONE: - /* dest = dest * 1 NO-OP, leave dest as-is */ + /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ break; case PIPE_BLENDFACTOR_SRC_COLOR: /* fall-through */ case PIPE_BLENDFACTOR_SRC_ALPHA: - VEC4_MUL(dest[3], dest[3], quadColor[3]); /* A * A */ + VEC4_MUL(blend_dest[3], blend_dest[3], quadColor[3]); /* A * A */ break; case PIPE_BLENDFACTOR_DST_COLOR: /* fall-through */ case PIPE_BLENDFACTOR_DST_ALPHA: if (has_dst_alpha) { - VEC4_MUL(dest[3], dest[3], dest[3]); /* A */ + VEC4_MUL(blend_dest[3], blend_dest[3], blend_dest[3]); /* A */ } else { - /* dest = dest * 1 NO-OP, leave dest as-is */ + /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ } break; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - /* dest = dest * 1 NO-OP, leave dest as-is */ + /* blend_dest = blend_dest * 1 NO-OP, leave blend_dest as-is */ break; case PIPE_BLENDFACTOR_CONST_COLOR: /* fall-through */ @@ -667,11 +674,11 @@ blend_quad(struct quad_stage *qs, { float comp[4]; VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ - VEC4_MUL(dest[3], dest[3], comp); /* A */ + VEC4_MUL(blend_dest[3], blend_dest[3], comp); /* A */ } break; case PIPE_BLENDFACTOR_ZERO: - VEC4_COPY(dest[3], zero); /* A */ + VEC4_COPY(blend_dest[3], zero); /* A */ break; case PIPE_BLENDFACTOR_INV_SRC_COLOR: /* fall-through */ @@ -679,7 +686,7 @@ blend_quad(struct quad_stage *qs, { float one_minus_alpha[QUAD_SIZE]; VEC4_SUB(one_minus_alpha, one, quadColor[3]); - VEC4_MUL(dest[3], dest[3], one_minus_alpha); /* A */ + VEC4_MUL(blend_dest[3], blend_dest[3], one_minus_alpha); /* A */ } break; case PIPE_BLENDFACTOR_INV_DST_COLOR: @@ -687,11 +694,11 @@ blend_quad(struct quad_stage *qs, case PIPE_BLENDFACTOR_INV_DST_ALPHA: if (has_dst_alpha) { float inv_comp[4]; - VEC4_SUB(inv_comp, one, dest[3]); /* A */ - VEC4_MUL(dest[3], inv_comp, dest[3]); /* A */ + VEC4_SUB(inv_comp, one, blend_dest[3]); /* A */ + VEC4_MUL(blend_dest[3], inv_comp, blend_dest[3]); /* A */ } else { - VEC4_COPY(dest[3], zero); /* A */ + VEC4_COPY(blend_dest[3], zero); /* A */ } break; case PIPE_BLENDFACTOR_INV_CONST_COLOR: @@ -700,7 +707,7 @@ blend_quad(struct quad_stage *qs, { float inv_comp[4]; VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); - VEC4_MUL(dest[3], dest[3], inv_comp); + VEC4_MUL(blend_dest[3], blend_dest[3], inv_comp); } break; default: @@ -712,29 +719,29 @@ blend_quad(struct quad_stage *qs, */ switch (softpipe->blend->rt[blend_index].rgb_func) { case PIPE_BLEND_ADD: - VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */ - VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */ - VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */ + VEC4_ADD_SAT(quadColor[0], source[0], blend_dest[0]); /* R */ + VEC4_ADD_SAT(quadColor[1], source[1], blend_dest[1]); /* G */ + VEC4_ADD_SAT(quadColor[2], source[2], blend_dest[2]); /* B */ break; case PIPE_BLEND_SUBTRACT: - VEC4_SUB_SAT(quadColor[0], source[0], dest[0]); /* R */ - VEC4_SUB_SAT(quadColor[1], source[1], dest[1]); /* G */ - VEC4_SUB_SAT(quadColor[2], source[2], dest[2]); /* B */ + VEC4_SUB_SAT(quadColor[0], source[0], blend_dest[0]); /* R */ + VEC4_SUB_SAT(quadColor[1], source[1], blend_dest[1]); /* G */ + VEC4_SUB_SAT(quadColor[2], source[2], blend_dest[2]); /* B */ break; case PIPE_BLEND_REVERSE_SUBTRACT: - VEC4_SUB_SAT(quadColor[0], dest[0], source[0]); /* R */ - VEC4_SUB_SAT(quadColor[1], dest[1], source[1]); /* G */ - VEC4_SUB_SAT(quadColor[2], dest[2], source[2]); /* B */ + VEC4_SUB_SAT(quadColor[0], blend_dest[0], source[0]); /* R */ + VEC4_SUB_SAT(quadColor[1], blend_dest[1], source[1]); /* G */ + VEC4_SUB_SAT(quadColor[2], blend_dest[2], source[2]); /* B */ break; case PIPE_BLEND_MIN: - VEC4_MIN(quadColor[0], source[0], dest[0]); /* R */ - VEC4_MIN(quadColor[1], source[1], dest[1]); /* G */ - VEC4_MIN(quadColor[2], source[2], dest[2]); /* B */ + VEC4_MIN(quadColor[0], source[0], blend_dest[0]); /* R */ + VEC4_MIN(quadColor[1], source[1], blend_dest[1]); /* G */ + VEC4_MIN(quadColor[2], source[2], blend_dest[2]); /* B */ break; case PIPE_BLEND_MAX: - VEC4_MAX(quadColor[0], source[0], dest[0]); /* R */ - VEC4_MAX(quadColor[1], source[1], dest[1]); /* G */ - VEC4_MAX(quadColor[2], source[2], dest[2]); /* B */ + VEC4_MAX(quadColor[0], source[0], blend_dest[0]); /* R */ + VEC4_MAX(quadColor[1], source[1], blend_dest[1]); /* G */ + VEC4_MAX(quadColor[2], source[2], blend_dest[2]); /* B */ break; default: assert(0 && "invalid rgb blend func"); @@ -745,19 +752,19 @@ blend_quad(struct quad_stage *qs, */ switch (softpipe->blend->rt[blend_index].alpha_func) { case PIPE_BLEND_ADD: - VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */ + VEC4_ADD_SAT(quadColor[3], source[3], blend_dest[3]); /* A */ break; case PIPE_BLEND_SUBTRACT: - VEC4_SUB_SAT(quadColor[3], source[3], dest[3]); /* A */ + VEC4_SUB_SAT(quadColor[3], source[3], blend_dest[3]); /* A */ break; case PIPE_BLEND_REVERSE_SUBTRACT: - VEC4_SUB_SAT(quadColor[3], dest[3], source[3]); /* A */ + VEC4_SUB_SAT(quadColor[3], blend_dest[3], source[3]); /* A */ break; case PIPE_BLEND_MIN: - VEC4_MIN(quadColor[3], source[3], dest[3]); /* A */ + VEC4_MIN(quadColor[3], source[3], blend_dest[3]); /* A */ break; case PIPE_BLEND_MAX: - VEC4_MAX(quadColor[3], source[3], dest[3]); /* A */ + VEC4_MAX(quadColor[3], source[3], blend_dest[3]); /* A */ break; default: assert(0 && "invalid alpha blend func"); @@ -797,7 +804,7 @@ blend_fallback(struct quad_stage *qs, unsigned cbuf; boolean write_all; - write_all = softpipe->fs->color0_writes_all_cbufs; + write_all = softpipe->fs_variant->info.color0_writes_all_cbufs; for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++) { @@ -810,17 +817,25 @@ blend_fallback(struct quad_stage *qs, quads[0]->input.y0); boolean has_dst_alpha = util_format_has_alpha(softpipe->framebuffer.cbufs[cbuf]->format); - uint q, i, j, qbuf; - - qbuf = write_all ? 0 : cbuf; + uint q, i, j; for (q = 0; q < nr; q++) { struct quad_header *quad = quads[q]; float (*quadColor)[4]; + float temp_quad_color[QUAD_SIZE][4]; const int itx = (quad->input.x0 & (TILE_SIZE-1)); const int ity = (quad->input.y0 & (TILE_SIZE-1)); - quadColor = quad->output.color[qbuf]; + if (write_all) { + for (j = 0; j < QUAD_SIZE; j++) { + for (i = 0; i < 4; i++) { + temp_quad_color[i][j] = quad->output.color[0][i][j]; + } + } + quadColor = temp_quad_color; + } else { + quadColor = quad->output.color[cbuf]; + } /* get/swizzle dest colors */ diff --git a/src/gallium/drivers/softpipe/sp_quad_depth_test.c b/src/gallium/drivers/softpipe/sp_quad_depth_test.c index 89b2a91fc1f..a349f0d1f3c 100644 --- a/src/gallium/drivers/softpipe/sp_quad_depth_test.c +++ b/src/gallium/drivers/softpipe/sp_quad_depth_test.c @@ -189,7 +189,8 @@ convert_quad_depth( struct depth_data *data, /** - * Compute the depth_data::shader_stencil_refs[] values from the float fragment stencil values. + * Compute the depth_data::shader_stencil_refs[] values from the float + * fragment stencil values. */ static void convert_quad_stencil( struct depth_data *data, @@ -205,10 +206,9 @@ convert_quad_stencil( struct depth_data *data, case PIPE_FORMAT_Z24_UNORM_S8_USCALED: case PIPE_FORMAT_X8Z24_UNORM: case PIPE_FORMAT_S8_USCALED_Z24_UNORM: - { - for (j = 0; j < QUAD_SIZE; j++) { - data->shader_stencil_refs[j] = ((unsigned)(quad->output.stencil[j])); - } + case PIPE_FORMAT_S8_USCALED: + for (j = 0; j < QUAD_SIZE; j++) { + data->shader_stencil_refs[j] = ((unsigned)(quad->output.stencil[j])); } break; default: @@ -216,6 +216,7 @@ convert_quad_stencil( struct depth_data *data, } } + /** * Write data->bzzzz[] values and data->stencilVals into the Z/stencil buffer. */ @@ -726,9 +727,9 @@ depth_test_quads_fallback(struct quad_stage *qs, unsigned nr) { unsigned i, pass = 0; - const struct sp_fragment_shader *fs = qs->softpipe->fs; - boolean interp_depth = !fs->info.writes_z; - boolean shader_stencil_ref = fs->info.writes_stencil; + const struct tgsi_shader_info *fsInfo = &qs->softpipe->fs_variant->info; + boolean interp_depth = !fsInfo->writes_z; + boolean shader_stencil_ref = fsInfo->writes_stencil; struct depth_data data; data.use_shader_stencil_refs = FALSE; @@ -837,7 +838,9 @@ choose_depth_test(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) { - boolean interp_depth = !qs->softpipe->fs->info.writes_z; + const struct tgsi_shader_info *fsInfo = &qs->softpipe->fs_variant->info; + + boolean interp_depth = !fsInfo->writes_z; boolean alpha = qs->softpipe->depth_stencil->alpha.enabled; diff --git a/src/gallium/drivers/softpipe/sp_quad_fs.c b/src/gallium/drivers/softpipe/sp_quad_fs.c index 90f4787d599..d74d6d4914e 100644 --- a/src/gallium/drivers/softpipe/sp_quad_fs.c +++ b/src/gallium/drivers/softpipe/sp_quad_fs.c @@ -74,7 +74,7 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad) struct tgsi_exec_machine *machine = softpipe->fs_machine; /* run shader */ - return softpipe->fs->run( softpipe->fs, machine, quad ); + return softpipe->fs_variant->run( softpipe->fs_variant, machine, quad ); } @@ -140,10 +140,10 @@ shade_begin(struct quad_stage *qs) { struct softpipe_context *softpipe = qs->softpipe; - softpipe->fs->prepare( softpipe->fs, - softpipe->fs_machine, - (struct tgsi_sampler **) - softpipe->tgsi.frag_samplers_list ); + softpipe->fs_variant->prepare( softpipe->fs_variant, + softpipe->fs_machine, + (struct tgsi_sampler **) + softpipe->tgsi.frag_samplers_list ); qs->next->begin(qs->next); } diff --git a/src/gallium/drivers/softpipe/sp_quad_pipe.c b/src/gallium/drivers/softpipe/sp_quad_pipe.c index 2cfd02a22c6..0c4506ae8f4 100644 --- a/src/gallium/drivers/softpipe/sp_quad_pipe.c +++ b/src/gallium/drivers/softpipe/sp_quad_pipe.c @@ -30,9 +30,9 @@ #include "sp_state.h" #include "pipe/p_shader_tokens.h" + static void -sp_push_quad_first( struct softpipe_context *sp, - struct quad_stage *quad ) +insert_stage_at_head(struct softpipe_context *sp, struct quad_stage *quad) { quad->next = sp->quad.first; sp->quad.first = quad; @@ -46,24 +46,24 @@ sp_build_quad_pipeline(struct softpipe_context *sp) sp->depth_stencil->depth.enabled && sp->framebuffer.zsbuf && !sp->depth_stencil->alpha.enabled && - !sp->fs->info.uses_kill && - !sp->fs->info.writes_z && - !sp->fs->info.writes_stencil; + !sp->fs_variant->info.uses_kill && + !sp->fs_variant->info.writes_z && + !sp->fs_variant->info.writes_stencil; sp->quad.first = sp->quad.blend; if (early_depth_test) { - sp_push_quad_first( sp, sp->quad.shade ); - sp_push_quad_first( sp, sp->quad.depth_test ); + insert_stage_at_head( sp, sp->quad.shade ); + insert_stage_at_head( sp, sp->quad.depth_test ); } else { - sp_push_quad_first( sp, sp->quad.depth_test ); - sp_push_quad_first( sp, sp->quad.shade ); + insert_stage_at_head( sp, sp->quad.depth_test ); + insert_stage_at_head( sp, sp->quad.shade ); } -#if !DO_PSTIPPLE_IN_DRAW_MODULE +#if !DO_PSTIPPLE_IN_DRAW_MODULE && !DO_PSTIPPLE_IN_HELPER_MODULE if (sp->rasterizer->poly_stipple_enable) - sp_push_quad_first( sp, sp->quad.pstipple ); + insert_stage_at_head( sp, sp->quad.pstipple ); #endif } diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c index 30f53a9e674..1e58d27be88 100644 --- a/src/gallium/drivers/softpipe/sp_screen.c +++ b/src/gallium/drivers/softpipe/sp_screen.c @@ -1,8 +1,8 @@ /************************************************************************** - * + * * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. * 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 @@ -10,11 +10,11 @@ * 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. @@ -22,16 +22,19 @@ * 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. - * + * **************************************************************************/ #include "util/u_memory.h" #include "util/u_format.h" #include "util/u_format_s3tc.h" +#include "util/u_video.h" #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "draw/draw_context.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "state_tracker/sw_winsys.h" #include "tgsi/tgsi_exec.h" @@ -169,6 +172,23 @@ softpipe_get_paramf(struct pipe_screen *screen, enum pipe_cap param) } } +static int +softpipe_get_video_param(struct pipe_screen *screen, + enum pipe_video_profile profile, + enum pipe_video_cap param) +{ + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vl_profile_supported(screen, profile); + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 0; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vl_video_buffer_max_size(screen); + default: + return 0; + } +} /** * Query format support for creating a texture, drawing surface, etc. @@ -307,7 +327,9 @@ softpipe_create_screen(struct sw_winsys *winsys) screen->base.get_param = softpipe_get_param; screen->base.get_shader_param = softpipe_get_shader_param; screen->base.get_paramf = softpipe_get_paramf; + screen->base.get_video_param = softpipe_get_video_param; screen->base.is_format_supported = softpipe_is_format_supported; + screen->base.is_video_format_supported = vl_video_buffer_is_format_supported; screen->base.context_create = softpipe_create_context; screen->base.flush_frontbuffer = softpipe_flush_frontbuffer; diff --git a/src/gallium/drivers/softpipe/sp_setup.c b/src/gallium/drivers/softpipe/sp_setup.c index 0ce28f4c6ee..656d001809f 100644 --- a/src/gallium/drivers/softpipe/sp_setup.c +++ b/src/gallium/drivers/softpipe/sp_setup.c @@ -568,17 +568,18 @@ tri_persp_coeff(struct setup_context *setup, static void setup_fragcoord_coeff(struct setup_context *setup, uint slot) { - struct sp_fragment_shader* spfs = setup->softpipe->fs; + const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info; + /*X*/ - setup->coef[slot].a0[0] = spfs->pixel_center_integer ? 0.0 : 0.5; + setup->coef[slot].a0[0] = fsInfo->pixel_center_integer ? 0.0 : 0.5; setup->coef[slot].dadx[0] = 1.0; setup->coef[slot].dady[0] = 0.0; /*Y*/ setup->coef[slot].a0[1] = - (spfs->origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0) - + (spfs->pixel_center_integer ? 0.0 : 0.5); + (fsInfo->origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0) + + (fsInfo->pixel_center_integer ? 0.0 : 0.5); setup->coef[slot].dadx[1] = 0.0; - setup->coef[slot].dady[1] = spfs->origin_lower_left ? -1.0 : 1.0; + setup->coef[slot].dady[1] = fsInfo->origin_lower_left ? -1.0 : 1.0; /*Z*/ setup->coef[slot].a0[2] = setup->posCoef.a0[2]; setup->coef[slot].dadx[2] = setup->posCoef.dadx[2]; @@ -599,7 +600,7 @@ static void setup_tri_coefficients(struct setup_context *setup) { struct softpipe_context *softpipe = setup->softpipe; - const struct sp_fragment_shader *spfs = softpipe->fs; + const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info; const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe); uint fragSlot; float v[3]; @@ -618,7 +619,7 @@ setup_tri_coefficients(struct setup_context *setup) /* setup interpolation for all the remaining attributes: */ - for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) { + for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) { const uint vertSlot = vinfo->attrib[fragSlot].src_index; uint j; @@ -632,7 +633,7 @@ setup_tri_coefficients(struct setup_context *setup) tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j], setup->vmid[vertSlot][j], setup->vmax[vertSlot][j], - spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j), v); tri_linear_coeff(setup, &setup->coef[fragSlot], j, v); } @@ -642,7 +643,7 @@ setup_tri_coefficients(struct setup_context *setup) tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j], setup->vmid[vertSlot][j], setup->vmax[vertSlot][j], - spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j), v); tri_persp_coeff(setup, &setup->coef[fragSlot], j, v); } @@ -654,7 +655,7 @@ setup_tri_coefficients(struct setup_context *setup) assert(0); } - if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { + if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { /* convert 0 to 1.0 and 1 to -1.0 */ setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f; setup->coef[fragSlot].dadx[0] = 0.0; @@ -939,7 +940,7 @@ setup_line_coefficients(struct setup_context *setup, const float (*v1)[4]) { struct softpipe_context *softpipe = setup->softpipe; - const struct sp_fragment_shader *spfs = softpipe->fs; + const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info; const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe); uint fragSlot; float area; @@ -974,7 +975,7 @@ setup_line_coefficients(struct setup_context *setup, /* setup interpolation for all the remaining attributes: */ - for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) { + for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) { const uint vertSlot = vinfo->attrib[fragSlot].src_index; uint j; @@ -987,7 +988,7 @@ setup_line_coefficients(struct setup_context *setup, for (j = 0; j < NUM_CHANNELS; j++) { line_apply_cylindrical_wrap(setup->vmin[vertSlot][j], setup->vmax[vertSlot][j], - spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j), v); line_linear_coeff(setup, &setup->coef[fragSlot], j, v); } @@ -996,7 +997,7 @@ setup_line_coefficients(struct setup_context *setup, for (j = 0; j < NUM_CHANNELS; j++) { line_apply_cylindrical_wrap(setup->vmin[vertSlot][j], setup->vmax[vertSlot][j], - spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j), v); line_persp_coeff(setup, &setup->coef[fragSlot], j, v); } @@ -1008,7 +1009,7 @@ setup_line_coefficients(struct setup_context *setup, assert(0); } - if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { + if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { /* convert 0 to 1.0 and 1 to -1.0 */ setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f; setup->coef[fragSlot].dadx[0] = 0.0; @@ -1188,7 +1189,7 @@ sp_setup_point(struct setup_context *setup, const float (*v0)[4]) { struct softpipe_context *softpipe = setup->softpipe; - const struct sp_fragment_shader *spfs = softpipe->fs; + const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info; const int sizeAttr = setup->softpipe->psize_slot; const float size = sizeAttr > 0 ? v0[sizeAttr][0] @@ -1232,7 +1233,7 @@ sp_setup_point(struct setup_context *setup, const_coeff(setup, &setup->posCoef, 0, 2); const_coeff(setup, &setup->posCoef, 0, 3); - for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) { + for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) { const uint vertSlot = vinfo->attrib[fragSlot].src_index; uint j; @@ -1255,7 +1256,7 @@ sp_setup_point(struct setup_context *setup, assert(0); } - if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { + if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { /* convert 0 to 1.0 and 1 to -1.0 */ setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f; setup->coef[fragSlot].dadx[0] = 0.0; @@ -1396,7 +1397,7 @@ sp_setup_prepare(struct setup_context *setup) struct softpipe_context *sp = setup->softpipe; if (sp->dirty) { - softpipe_update_derived(sp); + softpipe_update_derived(sp, sp->reduced_api_prim); } /* Note: nr_attrs is only used for debugging (vertex printing) */ diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h index bb19f8cff20..ec4c8cf5e4d 100644 --- a/src/gallium/drivers/softpipe/sp_state.h +++ b/src/gallium/drivers/softpipe/sp_state.h @@ -60,34 +60,45 @@ struct tgsi_exec_machine; struct vertex_info; -/** - * Subclass of pipe_shader_state (though it doesn't really need to be). - * - * This is starting to look an awful lot like a quad pipeline stage... - */ -struct sp_fragment_shader { - struct pipe_shader_state shader; +struct sp_fragment_shader_variant_key +{ + boolean polygon_stipple; +}; + +struct sp_fragment_shader_variant +{ + const struct tgsi_token *tokens; + struct sp_fragment_shader_variant_key key; struct tgsi_shader_info info; + unsigned stipple_sampler_unit; + + /* See comments about this elsewhere */ +#if 0 struct draw_fragment_shader *draw_shader; +#endif - boolean origin_lower_left; /**< fragment shader uses lower left position origin? */ - boolean pixel_center_integer; /**< fragment shader uses integer pixel center? */ - boolean color0_writes_all_cbufs; /**< fragment shader writes color0 to all bound cbufs */ - void (*prepare)( const struct sp_fragment_shader *shader, - struct tgsi_exec_machine *machine, - struct tgsi_sampler **samplers); + void (*prepare)(const struct sp_fragment_shader_variant *shader, + struct tgsi_exec_machine *machine, + struct tgsi_sampler **samplers); - /* Run the shader - this interface will get cleaned up in the - * future: - */ - unsigned (*run)( const struct sp_fragment_shader *shader, - struct tgsi_exec_machine *machine, - struct quad_header *quad ); + unsigned (*run)(const struct sp_fragment_shader_variant *shader, + struct tgsi_exec_machine *machine, + struct quad_header *quad); + /* Deletes this instance of the object */ + void (*delete)(struct sp_fragment_shader_variant *shader); - void (*delete)( struct sp_fragment_shader * ); + struct sp_fragment_shader_variant *next; +}; + + +/** Subclass of pipe_shader_state */ +struct sp_fragment_shader { + struct pipe_shader_state shader; + struct sp_fragment_shader_variant *variants; + struct draw_fragment_shader *draw_shader; }; @@ -141,7 +152,7 @@ softpipe_set_framebuffer_state(struct pipe_context *, const struct pipe_framebuffer_state *); void -softpipe_update_derived( struct softpipe_context *softpipe ); +softpipe_update_derived(struct softpipe_context *softpipe, unsigned prim); void softpipe_draw_vbo(struct pipe_context *pipe, @@ -170,4 +181,16 @@ struct vertex_info * softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe); +struct sp_fragment_shader_variant * +softpipe_find_fs_variant(struct softpipe_context *softpipe, + struct sp_fragment_shader *fs, + const struct sp_fragment_shader_variant_key *key); + + +struct sp_fragment_shader_variant * +softpipe_find_fs_variant(struct softpipe_context *softpipe, + struct sp_fragment_shader *fs, + const struct sp_fragment_shader_variant_key *key); + + #endif diff --git a/src/gallium/drivers/softpipe/sp_state_derived.c b/src/gallium/drivers/softpipe/sp_state_derived.c index f9590eb0b24..fd688089a3e 100644 --- a/src/gallium/drivers/softpipe/sp_state_derived.c +++ b/src/gallium/drivers/softpipe/sp_state_derived.c @@ -25,8 +25,10 @@ * **************************************************************************/ +#include "util/u_inlines.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_pstipple.h" #include "pipe/p_shader_tokens.h" #include "draw/draw_context.h" #include "draw/draw_vertex.h" @@ -64,7 +66,7 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe) if (vinfo->num_attribs == 0) { /* compute vertex layout now */ - const struct sp_fragment_shader *spfs = softpipe->fs; + const struct tgsi_shader_info *fsInfo = &softpipe->fs_variant->info; struct vertex_info *vinfo_vbuf = &softpipe->vertex_info_vbuf; const uint num = draw_num_shader_outputs(softpipe->draw); uint i; @@ -84,11 +86,11 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe) * from the vertex shader. */ vinfo->num_attribs = 0; - for (i = 0; i < spfs->info.num_inputs; i++) { + for (i = 0; i < fsInfo->num_inputs; i++) { int src; enum interp_mode interp; - switch (spfs->info.input_interpolate[i]) { + switch (fsInfo->input_interpolate[i]) { case TGSI_INTERPOLATE_CONSTANT: interp = INTERP_CONSTANT; break; @@ -103,7 +105,7 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe) interp = INTERP_LINEAR; } - switch (spfs->info.input_semantic_name[i]) { + switch (fsInfo->input_semantic_name[i]) { case TGSI_SEMANTIC_POSITION: interp = INTERP_POS; break; @@ -117,8 +119,8 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe) /* this includes texcoords and varying vars */ src = draw_find_shader_output(softpipe->draw, - spfs->info.input_semantic_name[i], - spfs->info.input_semantic_index[i]); + fsInfo->input_semantic_name[i], + fsInfo->input_semantic_index[i]); draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src); } @@ -241,10 +243,101 @@ update_tgsi_samplers( struct softpipe_context *softpipe ) } +static void +update_fragment_shader(struct softpipe_context *softpipe, unsigned prim) +{ + struct sp_fragment_shader_variant_key key; + + memset(&key, 0, sizeof(key)); + + if (prim == PIPE_PRIM_TRIANGLES) + key.polygon_stipple = softpipe->rasterizer->poly_stipple_enable; + + if (softpipe->fs) { + softpipe->fs_variant = softpipe_find_fs_variant(softpipe, + softpipe->fs, &key); + } + else { + softpipe->fs_variant = NULL; + } + + /* This would be the logical place to pass the fragment shader + * to the draw module. However, doing this here, during state + * validation, causes problems with the 'draw' module helpers for + * wide/AA/stippled lines. + * In principle, the draw's fragment shader should be per-variant + * but that doesn't work. So we use a single draw fragment shader + * per fragment shader, not per variant. + */ +#if 0 + if (softpipe->fs_variant) { + draw_bind_fragment_shader(softpipe->draw, + softpipe->fs_variant->draw_shader); + } + else { + draw_bind_fragment_shader(softpipe->draw, NULL); + } +#endif +} + + +/** + * This should be called when the polygon stipple pattern changes. + * We create a new texture from the stipple pattern and create a new + * sampler view. + */ +static void +update_polygon_stipple_pattern(struct softpipe_context *softpipe) +{ + struct pipe_resource *tex; + struct pipe_sampler_view *view; + + tex = util_pstipple_create_stipple_texture(&softpipe->pipe, + softpipe->poly_stipple.stipple); + pipe_resource_reference(&softpipe->pstipple.texture, tex); + + view = util_pstipple_create_sampler_view(&softpipe->pipe, tex); + pipe_sampler_view_reference(&softpipe->pstipple.sampler_view, view); +} + + +/** + * Should be called when polygon stipple is enabled/disabled or when + * the fragment shader changes. + * We add/update the fragment sampler and sampler views to sample from + * the polygon stipple texture. The texture unit that we use depends on + * the fragment shader (we need to use a unit not otherwise used by the + * shader). + */ +static void +update_polygon_stipple_enable(struct softpipe_context *softpipe, unsigned prim) +{ + if (prim == PIPE_PRIM_TRIANGLES && + softpipe->fs_variant->key.polygon_stipple) { + const unsigned unit = softpipe->fs_variant->stipple_sampler_unit; + + assert(unit >= softpipe->num_fragment_samplers); + + /* sampler state */ + softpipe->fragment_samplers[unit] = softpipe->pstipple.sampler; + + /* sampler view */ + pipe_sampler_view_reference(&softpipe->fragment_sampler_views[unit], + softpipe->pstipple.sampler_view); + + sp_tex_tile_cache_set_sampler_view(softpipe->fragment_tex_cache[unit], + softpipe->pstipple.sampler_view); + + softpipe->dirty |= SP_NEW_SAMPLER; + } +} + + /* Hopefully this will remain quite simple, otherwise need to pull in * something like the state tracker mechanism. */ -void softpipe_update_derived( struct softpipe_context *softpipe ) +void +softpipe_update_derived(struct softpipe_context *softpipe, unsigned prim) { struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen); @@ -254,7 +347,24 @@ void softpipe_update_derived( struct softpipe_context *softpipe ) softpipe->tex_timestamp = sp_screen->timestamp; softpipe->dirty |= SP_NEW_TEXTURE; } - + +#if DO_PSTIPPLE_IN_HELPER_MODULE + if (softpipe->dirty & SP_NEW_STIPPLE) + /* before updating samplers! */ + update_polygon_stipple_pattern(softpipe); +#endif + + if (softpipe->dirty & (SP_NEW_RASTERIZER | + SP_NEW_FS)) + update_fragment_shader(softpipe, prim); + +#if DO_PSTIPPLE_IN_HELPER_MODULE + if (softpipe->dirty & (SP_NEW_RASTERIZER | + SP_NEW_STIPPLE | + SP_NEW_FS)) + update_polygon_stipple_enable(softpipe, prim); +#endif + if (softpipe->dirty & (SP_NEW_SAMPLER | SP_NEW_TEXTURE | SP_NEW_FS | diff --git a/src/gallium/drivers/softpipe/sp_state_sampler.c b/src/gallium/drivers/softpipe/sp_state_sampler.c index 60331bc4976..16023c990a7 100644 --- a/src/gallium/drivers/softpipe/sp_state_sampler.c +++ b/src/gallium/drivers/softpipe/sp_state_sampler.c @@ -373,8 +373,9 @@ softpipe_reset_sampler_variants(struct softpipe_context *softpipe) } } - for (i = 0; i <= softpipe->fs->info.file_max[TGSI_FILE_SAMPLER]; i++) { + for (i = 0; i <= softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]; i++) { if (softpipe->fragment_samplers[i]) { + assert(softpipe->fragment_sampler_views[i]->texture); softpipe->tgsi.frag_samplers_list[i] = get_sampler_variant( i, sp_sampler(softpipe->fragment_samplers[i]), diff --git a/src/gallium/drivers/softpipe/sp_state_shader.c b/src/gallium/drivers/softpipe/sp_state_shader.c index 3dec5de3cc4..da895270aa9 100644 --- a/src/gallium/drivers/softpipe/sp_state_shader.c +++ b/src/gallium/drivers/softpipe/sp_state_shader.c @@ -33,6 +33,7 @@ #include "pipe/p_defines.h" #include "util/u_memory.h" #include "util/u_inlines.h" +#include "util/u_pstipple.h" #include "draw/draw_context.h" #include "draw/draw_vs.h" #include "draw/draw_gs.h" @@ -42,46 +43,105 @@ #include "tgsi/tgsi_parse.h" +/** + * Create a new fragment shader variant. + */ +static struct sp_fragment_shader_variant * +create_fs_variant(struct softpipe_context *softpipe, + struct sp_fragment_shader *fs, + const struct sp_fragment_shader_variant_key *key) +{ + struct sp_fragment_shader_variant *var; + struct pipe_shader_state *stipple_fs = NULL, *curfs = &fs->shader; + unsigned unit = 0; + + if (key->polygon_stipple) { + /* get new shader that implements polygon stippling */ + stipple_fs = util_pstipple_create_fragment_shader(&softpipe->pipe, + curfs, &unit); + curfs = stipple_fs; + } + + /* codegen, create variant object */ + var = softpipe_create_fs_variant_sse(softpipe, curfs); + if (!var) { + var = softpipe_create_fs_variant_exec(softpipe, curfs); + } + + if (var) { + var->key = *key; + var->tokens = tgsi_dup_tokens(curfs->tokens); + var->stipple_sampler_unit = unit; + + tgsi_scan_shader(var->tokens, &var->info); + + /* See comments elsewhere about draw fragment shaders */ +#if 0 + /* draw's fs state */ + var->draw_shader = draw_create_fragment_shader(softpipe->draw, + &fs->shader); + if (!var->draw_shader) { + var->delete(var); + FREE((void *) var->tokens); + return NULL; + } +#endif + + /* insert variant into linked list */ + var->next = fs->variants; + fs->variants = var; + } + + if (stipple_fs) { + free((void *) stipple_fs->tokens); + free(stipple_fs); + } + + return var; +} + + +struct sp_fragment_shader_variant * +softpipe_find_fs_variant(struct softpipe_context *sp, + struct sp_fragment_shader *fs, + const struct sp_fragment_shader_variant_key *key) +{ + struct sp_fragment_shader_variant *var; + + for (var = fs->variants; var; var = var->next) { + if (memcmp(&var->key, key, sizeof(*key)) == 0) { + /* found it */ + return var; + } + } + + return create_fs_variant(sp, fs, key); +} + + static void * softpipe_create_fs_state(struct pipe_context *pipe, const struct pipe_shader_state *templ) { struct softpipe_context *softpipe = softpipe_context(pipe); - struct sp_fragment_shader *state; - unsigned i; + struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader); /* debug */ if (softpipe->dump_fs) tgsi_dump(templ->tokens, 0); - /* codegen */ - state = softpipe_create_fs_sse( softpipe, templ ); - if (!state) { - state = softpipe_create_fs_exec( softpipe, templ ); - } - - if (!state) - return NULL; + /* we need to keep a local copy of the tokens */ + state->shader.tokens = tgsi_dup_tokens(templ->tokens); /* draw's fs state */ - state->draw_shader = draw_create_fragment_shader(softpipe->draw, templ); + state->draw_shader = draw_create_fragment_shader(softpipe->draw, + &state->shader); if (!state->draw_shader) { - state->delete( state ); + FREE((void *) state->shader.tokens); + FREE(state); return NULL; } - /* get/save the summary info for this shader */ - tgsi_scan_shader(templ->tokens, &state->info); - - for (i = 0; i < state->info.num_properties; ++i) { - if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN) - state->origin_lower_left = state->info.properties[i].data[0]; - else if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_PIXEL_CENTER) - state->pixel_center_integer = state->info.properties[i].data[0]; - else if (state->info.properties[i].name == TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS) - state->color0_writes_all_cbufs = state->info.properties[i].data[0]; - } - return state; } @@ -90,6 +150,7 @@ static void softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) { struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs; if (softpipe->fs == fs) return; @@ -98,8 +159,14 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) softpipe->fs = fs; - draw_bind_fragment_shader(softpipe->draw, - (softpipe->fs ? softpipe->fs->draw_shader : NULL)); + if (fs == NULL) + softpipe->fs_variant = NULL; + + if (state) + draw_bind_fragment_shader(softpipe->draw, + state->draw_shader); + else + draw_bind_fragment_shader(softpipe->draw, NULL); softpipe->dirty |= SP_NEW_FS; } @@ -110,8 +177,9 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs) { struct softpipe_context *softpipe = softpipe_context(pipe); struct sp_fragment_shader *state = fs; + struct sp_fragment_shader_variant *var, *next_var; - assert(fs != softpipe_context(pipe)->fs); + assert(fs != softpipe->fs); if (softpipe->fs_machine->Tokens == state->shader.tokens) { /* unbind the shader from the tgsi executor if we're @@ -120,9 +188,23 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs) tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL); } + /* delete variants */ + for (var = state->variants; var; var = next_var) { + next_var = var->next; + + assert(var != softpipe->fs_variant); + + /* See comments elsewhere about draw fragment shaders */ +#if 0 + draw_delete_fragment_shader(softpipe->draw, var->draw_shader); +#endif + + var->delete(var); + } + draw_delete_fragment_shader(softpipe->draw, state->draw_shader); - state->delete( state ); + FREE((void *) state->shader.tokens); } diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c index 90766f4119c..f7309480bb9 100644 --- a/src/gallium/drivers/softpipe/sp_tex_sample.c +++ b/src/gallium/drivers/softpipe/sp_tex_sample.c @@ -1662,7 +1662,7 @@ mip_filter_nearest(struct tgsi_sampler *tgsi_sampler, samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); } else { - samp->level = samp->view->u.tex.first_level + (int)(lambda + 0.5) ; + samp->level = samp->view->u.tex.first_level + (int)(lambda + 0.5F) ; samp->level = MIN2(samp->level, (int)texture->last_level); samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); } @@ -1815,13 +1815,13 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, * and incrementally update the value of Ax^2+Bxy*Cy^2; when this * value, q, is less than F, we're inside the ellipse */ - float tex_u=-0.5 + s[j] * texture->width0 * scaling; - float tex_v=-0.5 + t[j] * texture->height0 * scaling; + float tex_u = -0.5F + s[j] * texture->width0 * scaling; + float tex_v = -0.5F + t[j] * texture->height0 * scaling; - int u0 = floor(tex_u - box_u); - int u1 = ceil (tex_u + box_u); - int v0 = floor(tex_v - box_v); - int v1 = ceil (tex_v + box_v); + int u0 = (int) floorf(tex_u - box_u); + int u1 = (int) ceilf(tex_u + box_u); + int v0 = (int) floorf(tex_v - box_v); + int v1 = (int) ceilf(tex_v + box_v); float num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; buffer_next = 0; @@ -1849,7 +1849,7 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, buffer_next++; if (buffer_next == QUAD_SIZE) { /* 4 texel coords are in the buffer -> read it now */ - int jj; + unsigned jj; /* it is assumed that samp->min_img_filter is set to * img_filter_2d_nearest or one of the * accelerated img_filter_2d_nearest_XXX functions. @@ -1879,7 +1879,7 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, * parameter, we need to read the whole quad and ignore the unused values */ if (buffer_next > 0) { - int jj; + unsigned jj; /* it is assumed that samp->min_img_filter is set to * img_filter_2d_nearest or one of the * accelerated img_filter_2d_nearest_XXX functions. @@ -1984,7 +1984,7 @@ mip_filter_linear_aniso(struct tgsi_sampler *tgsi_sampler, /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid * this since 0.5*log(x) = log(sqrt(x)) */ - lambda = 0.5 * util_fast_log2(Pmin2) + samp->sampler->lod_bias; + lambda = 0.5F * util_fast_log2(Pmin2) + samp->sampler->lod_bias; compute_lod(samp->sampler, lambda, c0, lod); } else { @@ -2001,7 +2001,7 @@ mip_filter_linear_aniso(struct tgsi_sampler *tgsi_sampler, /* If the ellipse covers the whole image, we can * simply return the average of the whole image. */ - if (level0 >= texture->last_level) { + if (level0 >= (int) texture->last_level) { samp->level = texture->last_level; samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); } @@ -2226,9 +2226,9 @@ sample_cube(struct tgsi_sampler *tgsi_sampler, */ { /* use the average of the four pixel's texcoords to choose the face */ - const float rx = 0.25 * (s[0] + s[1] + s[2] + s[3]); - const float ry = 0.25 * (t[0] + t[1] + t[2] + t[3]); - const float rz = 0.25 * (p[0] + p[1] + p[2] + p[3]); + const float rx = 0.25F * (s[0] + s[1] + s[2] + s[3]); + const float ry = 0.25F * (t[0] + t[1] + t[2] + t[3]); + const float rz = 0.25F * (p[0] + p[1] + p[2] + p[3]); const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz); if (arx >= ary && arx >= arz) { @@ -2255,7 +2255,7 @@ sample_cube(struct tgsi_sampler *tgsi_sampler, float sign = (rz >= 0.0F) ? 1.0F : -1.0F; uint face = (rz >= 0.0F) ? PIPE_TEX_FACE_POS_Z : PIPE_TEX_FACE_NEG_Z; for (j = 0; j < QUAD_SIZE; j++) { - const float ima = -0.5 / fabsf(p[j]); + const float ima = -0.5F / fabsf(p[j]); ssss[j] = sign * -s[j] * ima + 0.5F; tttt[j] = t[j] * ima + 0.5F; samp->faces[j] = face; diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h index 5603110eeb3..533d6252e25 100644 --- a/src/gallium/drivers/softpipe/sp_texture.h +++ b/src/gallium/drivers/softpipe/sp_texture.h @@ -79,7 +79,6 @@ struct softpipe_transfer }; - /** cast wrappers */ static INLINE struct softpipe_resource * softpipe_resource(struct pipe_resource *pt) diff --git a/src/gallium/drivers/svga/svga_context.c b/src/gallium/drivers/svga/svga_context.c index dbbc249258d..cfb1b9d8d0d 100644 --- a/src/gallium/drivers/svga/svga_context.c +++ b/src/gallium/drivers/svga/svga_context.c @@ -207,6 +207,14 @@ void svga_context_flush( struct svga_context *svga, svga->curr.nr_fbs = 0; + /* Flush the upload managers to ensure recycling of upload buffers + * without throttling. This should really be conditioned on + * pipe_buffer_map_range not supporting PIPE_TRANSFER_UNSYNCHRONIZED. + */ + + u_upload_flush(svga->upload_vb); + u_upload_flush(svga->upload_ib); + /* Ensure that texture dma uploads are processed * before submitting commands. */ diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h index eca529d262e..34b9e85c1a3 100644 --- a/src/gallium/drivers/svga/svga_context.h +++ b/src/gallium/drivers/svga/svga_context.h @@ -372,9 +372,6 @@ struct svga_context /** List of buffers with queued transfers */ struct list_head dirty_buffers; - - /** Was the previous draw done with the SW path? */ - boolean prev_draw_swtnl; }; /* A flag for each state_tracker state object: diff --git a/src/gallium/drivers/svga/svga_draw.c b/src/gallium/drivers/svga/svga_draw.c index d8af615ede1..aa096692888 100644 --- a/src/gallium/drivers/svga/svga_draw.c +++ b/src/gallium/drivers/svga/svga_draw.c @@ -145,7 +145,7 @@ svga_hwtnl_flush( struct svga_hwtnl *hwtnl ) unsigned i; /* Unmap upload manager vertex buffers */ - u_upload_flush(svga->upload_vb); + u_upload_unmap(svga->upload_vb); for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { handle = svga_buffer_handle(svga, hwtnl->cmd.vdecl_vb[i]); @@ -156,7 +156,7 @@ svga_hwtnl_flush( struct svga_hwtnl *hwtnl ) } /* Unmap upload manager index buffers */ - u_upload_flush(svga->upload_ib); + u_upload_unmap(svga->upload_ib); for (i = 0; i < hwtnl->cmd.prim_count; i++) { if (hwtnl->cmd.prim_ib[i]) { @@ -242,6 +242,11 @@ svga_hwtnl_flush( struct svga_hwtnl *hwtnl ) } +void svga_hwtnl_set_index_bias( struct svga_hwtnl *hwtnl, + int index_bias) +{ + hwtnl->index_bias = index_bias; +} @@ -265,15 +270,16 @@ enum pipe_error svga_hwtnl_prim( struct svga_hwtnl *hwtnl, unsigned size = vb ? vb->width0 : 0; unsigned offset = hwtnl->cmd.vdecl[i].array.offset; unsigned stride = hwtnl->cmd.vdecl[i].array.stride; - unsigned index_bias = range->indexBias; + int index_bias = (int) range->indexBias + hwtnl->index_bias; unsigned width; assert(vb); assert(size); assert(offset < size); - assert(index_bias >= 0); assert(min_index <= max_index); - assert(offset + index_bias*stride < size); + if (index_bias >= 0) { + assert(offset + index_bias*stride < size); + } if (min_index != ~0) { assert(offset + (index_bias + min_index) * stride < size); } @@ -394,6 +400,7 @@ enum pipe_error svga_hwtnl_prim( struct svga_hwtnl *hwtnl, hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index; hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range; + hwtnl->cmd.prim[hwtnl->cmd.prim_count].indexBias += hwtnl->index_bias; pipe_resource_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib); hwtnl->cmd.prim_count++; diff --git a/src/gallium/drivers/svga/svga_draw.h b/src/gallium/drivers/svga/svga_draw.h index a2403d802be..1dac17421e1 100644 --- a/src/gallium/drivers/svga/svga_draw.h +++ b/src/gallium/drivers/svga/svga_draw.h @@ -79,5 +79,8 @@ svga_hwtnl_draw_range_elements( struct svga_hwtnl *hwtnl, enum pipe_error svga_hwtnl_flush( struct svga_hwtnl *hwtnl ); +void svga_hwtnl_set_index_bias( struct svga_hwtnl *hwtnl, + int index_bias); + #endif /* SVGA_DRAW_H_ */ diff --git a/src/gallium/drivers/svga/svga_draw_private.h b/src/gallium/drivers/svga/svga_draw_private.h index ca658ac6745..8126f7ee23c 100644 --- a/src/gallium/drivers/svga/svga_draw_private.h +++ b/src/gallium/drivers/svga/svga_draw_private.h @@ -116,6 +116,13 @@ struct draw_cmd { struct svga_hwtnl { struct svga_context *svga; struct u_upload_mgr *upload_ib; + + /* Additional negative index bias due to partial buffer uploads + * This is compensated for in the offset associated with all + * vertex buffers. + */ + + int index_bias; /* Flatshade information: */ diff --git a/src/gallium/drivers/svga/svga_pipe_draw.c b/src/gallium/drivers/svga/svga_pipe_draw.c index 2093bcae101..d53edcb23c5 100644 --- a/src/gallium/drivers/svga/svga_pipe_draw.c +++ b/src/gallium/drivers/svga/svga_pipe_draw.c @@ -25,6 +25,7 @@ #include "svga_cmd.h" +#include "util/u_format.h" #include "util/u_inlines.h" #include "util/u_prim.h" #include "util/u_time.h" @@ -37,6 +38,178 @@ #include "svga_state.h" #include "svga_swtnl.h" #include "svga_debug.h" +#include "svga_resource_buffer.h" +#include "util/u_upload_mgr.h" + +/** + * Determine the ranges to upload for the user-buffers referenced + * by the next draw command. + * + * TODO: It might be beneficial to support multiple ranges. In that case, + * the struct svga_buffer::uploaded member should be made an array or a + * list, since we need to account for the possibility that different ranges + * may be uploaded to different hardware buffers chosen by the utility + * upload manager. + */ + +static void +svga_user_buffer_range(struct svga_context *svga, + unsigned start, + unsigned count, + unsigned instance_count) +{ + const struct pipe_vertex_element *ve = svga->curr.velems->velem; + int i; + + /* + * Release old uploaded range (if not done already) and + * initialize new ranges. + */ + + for (i=0; i < svga->curr.velems->count; i++) { + struct pipe_vertex_buffer *vb = + &svga->curr.vb[ve[i].vertex_buffer_index]; + + if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { + struct svga_buffer *buffer = svga_buffer(vb->buffer); + + pipe_resource_reference(&buffer->uploaded.buffer, NULL); + buffer->uploaded.start = ~0; + buffer->uploaded.end = 0; + } + } + + for (i=0; i < svga->curr.velems->count; i++) { + struct pipe_vertex_buffer *vb = + &svga->curr.vb[ve[i].vertex_buffer_index]; + + if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { + struct svga_buffer *buffer = svga_buffer(vb->buffer); + unsigned first, size; + unsigned instance_div = ve[i].instance_divisor; + unsigned elemSize = util_format_get_blocksize(ve[i].src_format); + + svga->dirty |= SVGA_NEW_VBUFFER; + + if (instance_div) { + first = ve[i].src_offset; + count = (instance_count + instance_div - 1) / instance_div; + size = vb->stride * (count - 1) + elemSize; + } else if (vb->stride) { + first = vb->stride * start + ve[i].src_offset; + size = vb->stride * (count - 1) + elemSize; + } else { + /* Only a single vertex! + * Upload with the largest vertex size the hw supports, + * if possible. + */ + first = ve[i].src_offset; + size = MIN2(16, vb->buffer->width0); + } + + buffer->uploaded.start = MIN2(buffer->uploaded.start, first); + buffer->uploaded.end = MAX2(buffer->uploaded.end, first + size); + } + } +} + +/** + * svga_upload_user_buffers - upload parts of user buffers + * + * This function streams a part of a user buffer to hw and fills + * svga_buffer::uploaded with information on the upload. + */ + +static int +svga_upload_user_buffers(struct svga_context *svga, + unsigned start, + unsigned count, + unsigned instance_count) +{ + const struct pipe_vertex_element *ve = svga->curr.velems->velem; + unsigned i; + int ret; + + svga_user_buffer_range(svga, start, count, instance_count); + + for (i=0; i < svga->curr.velems->count; i++) { + struct pipe_vertex_buffer *vb = + &svga->curr.vb[ve[i].vertex_buffer_index]; + + if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { + struct svga_buffer *buffer = svga_buffer(vb->buffer); + boolean flushed; + + /* + * Check if already uploaded. Otherwise go ahead and upload. + */ + + if (buffer->uploaded.buffer) + continue; + + ret = u_upload_buffer( svga->upload_vb, + 0, + buffer->uploaded.start, + buffer->uploaded.end - buffer->uploaded.start, + &buffer->b.b, + &buffer->uploaded.offset, + &buffer->uploaded.buffer, + &flushed); + + if (ret) + return ret; + + if (0) + debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sofs %d" + " sz %d\n", + __FUNCTION__, + i, + buffer, + buffer->uploaded.buffer, + buffer->uploaded.offset, + buffer->uploaded.start, + buffer->uploaded.end - buffer->uploaded.start); + + vb->buffer_offset = buffer->uploaded.offset; + } + } + + return PIPE_OK; +} + +/** + * svga_release_user_upl_buffers - release uploaded parts of user buffers + * + * This function releases the hw copy of the uploaded fraction of the + * user-buffer. It's important to do this as soon as all draw calls + * affecting the uploaded fraction are issued, as this allows for + * efficient reuse of the hardware surface backing the uploaded fraction. + * + * svga_buffer::source_offset is set to 0, and svga_buffer::uploaded::buffer + * is set to 0. + */ + +static void +svga_release_user_upl_buffers(struct svga_context *svga) +{ + unsigned i; + unsigned nr; + + nr = svga->curr.num_vertex_buffers; + + for (i = 0; i < nr; ++i) { + struct pipe_vertex_buffer *vb = &svga->curr.vb[i]; + + if (vb->buffer && svga_buffer_is_user_buffer(vb->buffer)) { + struct svga_buffer *buffer = svga_buffer(vb->buffer); + + buffer->uploaded.start = ~0; + buffer->uploaded.end = 0; + if (buffer->uploaded.buffer) + pipe_resource_reference(&buffer->uploaded.buffer, NULL); + } + } +} @@ -50,6 +223,7 @@ retry_draw_range_elements( struct svga_context *svga, unsigned prim, unsigned start, unsigned count, + unsigned instance_count, boolean do_retry ) { enum pipe_error ret = 0; @@ -61,6 +235,10 @@ retry_draw_range_elements( struct svga_context *svga, svga->curr.rast->templ.flatshade, svga->curr.rast->templ.flatshade_first ); + ret = svga_upload_user_buffers( svga, min_index + index_bias, + max_index - min_index + 1, instance_count ); + if (ret != PIPE_OK) + goto retry; ret = svga_update_state( svga, SVGA_STATE_HW_DRAW ); if (ret) @@ -84,7 +262,7 @@ retry: index_buffer, index_size, index_bias, min_index, max_index, prim, start, count, - FALSE ); + instance_count, FALSE ); } return ret; @@ -96,6 +274,7 @@ retry_draw_arrays( struct svga_context *svga, unsigned prim, unsigned start, unsigned count, + unsigned instance_count, boolean do_retry ) { enum pipe_error ret; @@ -107,6 +286,11 @@ retry_draw_arrays( struct svga_context *svga, svga->curr.rast->templ.flatshade, svga->curr.rast->templ.flatshade_first ); + ret = svga_upload_user_buffers( svga, start, count, instance_count ); + + if (ret != PIPE_OK) + goto retry; + ret = svga_update_state( svga, SVGA_STATE_HW_DRAW ); if (ret) goto retry; @@ -127,6 +311,7 @@ retry: prim, start, count, + instance_count, FALSE ); } @@ -141,18 +326,11 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) unsigned reduced_prim = u_reduced_prim( info->mode ); unsigned count = info->count; enum pipe_error ret = 0; + boolean needed_swtnl; if (!u_trim_pipe_prim( info->mode, &count )) return; - if (svga->state.sw.need_swtnl != svga->prev_draw_swtnl) { - /* We're switching between SW and HW drawing. Do a flush to avoid - * mixing HW and SW rendering with the same vertex buffer. - */ - pipe->flush(pipe, NULL); - svga->prev_draw_swtnl = svga->state.sw.need_swtnl; - } - /* * Mark currently bound target surfaces as dirty * doesn't really matter if it is done before drawing. @@ -167,6 +345,8 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE; } + needed_swtnl = svga->state.sw.need_swtnl; + svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL ); #ifdef DEBUG @@ -176,6 +356,20 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) #endif if (svga->state.sw.need_swtnl) { + if (!needed_swtnl) { + /* + * We're switching from HW to SW TNL. SW TNL will require mapping all + * currently bound vertex buffers, some of which may already be + * referenced in the current command buffer as result of previous HW + * TNL. So flush now, to prevent the context to flush while a referred + * vertex buffer is mapped. + */ + + svga_context_flush(svga, NULL); + } + + /* Avoid leaking the previous hwtnl bias to swtnl */ + svga_hwtnl_set_index_bias( svga->hwtnl, 0 ); ret = svga_swtnl_draw_vbo( svga, info ); } else { @@ -194,6 +388,7 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) info->mode, info->start + offset, info->count, + info->instance_count, TRUE ); } else { @@ -201,10 +396,13 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) info->mode, info->start, info->count, + info->instance_count, TRUE ); } } + svga_release_user_upl_buffers( svga ); + if (SVGA_DEBUG & DEBUG_FLUSH) { svga_hwtnl_flush_retry( svga ); svga_context_flush(svga, NULL); diff --git a/src/gallium/drivers/svga/svga_resource_buffer.h b/src/gallium/drivers/svga/svga_resource_buffer.h index 95032213fa5..ca8c8d1f5ea 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer.h +++ b/src/gallium/drivers/svga/svga_resource_buffer.h @@ -129,6 +129,12 @@ struct svga_buffer * is the relative offset within that buffer. */ unsigned offset; + + /** + * Range of user buffer that is uploaded in @buffer at @offset. + */ + unsigned start; + unsigned end; } uploaded; /** @@ -193,7 +199,11 @@ svga_buffer(struct pipe_resource *buffer) static INLINE boolean svga_buffer_is_user_buffer( struct pipe_resource *buffer ) { - return svga_buffer(buffer)->user; + if (buffer) { + return svga_buffer(buffer)->user; + } else { + return FALSE; + } } diff --git a/src/gallium/drivers/svga/svga_resource_buffer_upload.c b/src/gallium/drivers/svga/svga_resource_buffer_upload.c index 923958674b4..a657a8bc224 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer_upload.c +++ b/src/gallium/drivers/svga/svga_resource_buffer_upload.c @@ -651,8 +651,6 @@ svga_redefine_user_buffer(struct pipe_context *pipe, unsigned offset, unsigned size) { - struct svga_screen *ss = svga_screen(pipe->screen); - struct svga_context *svga = svga_context(pipe); struct svga_buffer *sbuf = svga_buffer(resource); assert(sbuf->user); @@ -661,19 +659,8 @@ svga_redefine_user_buffer(struct pipe_context *pipe, assert(!sbuf->hwbuf); /* - * Release any uploaded user buffer. - * - * TODO: As an optimization, we could try to update the uploaded buffer - * instead. + * We always treat the contents of user-buffers as volatile, + * so no particular action needed here. */ - pipe_resource_reference(&sbuf->uploaded.buffer, NULL); - - pipe_mutex_lock(ss->swc_mutex); - - sbuf->key.size.width = sbuf->b.b.width0 = offset + size; - - pipe_mutex_unlock(ss->swc_mutex); - - svga->dirty |= SVGA_NEW_VBUFFER | SVGA_NEW_VELEMENT; } diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c index 7c393a1da8d..47eab1a9739 100644 --- a/src/gallium/drivers/svga/svga_state_vdecl.c +++ b/src/gallium/drivers/svga/svga_state_vdecl.c @@ -38,57 +38,6 @@ #include "svga_hw_reg.h" -static int -upload_user_buffers( struct svga_context *svga ) -{ - enum pipe_error ret = PIPE_OK; - int i; - int nr; - - if (0) - debug_printf("%s: %d\n", __FUNCTION__, svga->curr.num_vertex_buffers); - - nr = svga->curr.num_vertex_buffers; - - for (i = 0; i < nr; i++) - { - if (svga_buffer_is_user_buffer(svga->curr.vb[i].buffer)) - { - struct svga_buffer *buffer = svga_buffer(svga->curr.vb[i].buffer); - - if (!buffer->uploaded.buffer) { - boolean flushed; - ret = u_upload_buffer( svga->upload_vb, - 0, 0, - buffer->b.b.width0, - &buffer->b.b, - &buffer->uploaded.offset, - &buffer->uploaded.buffer, - &flushed); - if (ret) - return ret; - - if (0) - debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sz %d\n", - __FUNCTION__, - i, - buffer, - buffer->uploaded.buffer, - buffer->uploaded.offset, - buffer->b.b.width0); - } - - svga->curr.vb[i].buffer_offset = buffer->uploaded.offset; - } - } - - if (0) - debug_printf("%s: DONE\n", __FUNCTION__); - - return ret; -} - - /*********************************************************************** */ @@ -99,6 +48,7 @@ static int emit_hw_vs_vdecl( struct svga_context *svga, const struct pipe_vertex_element *ve = svga->curr.velems->velem; SVGA3dVertexDecl decl; unsigned i; + unsigned neg_bias = 0; assert(svga->curr.velems->count >= svga->curr.vs->base.info.file_count[TGSI_FILE_INPUT]); @@ -106,12 +56,50 @@ static int emit_hw_vs_vdecl( struct svga_context *svga, svga_hwtnl_reset_vdecl( svga->hwtnl, svga->curr.velems->count ); + /** + * We can't set the VDECL offset to something negative, so we + * must calculate a common negative additional index bias, and modify + * the VDECL offsets accordingly so they *all* end up positive. + * + * Note that the exact value of the negative index bias is not that + * important, since we compensate for it when we calculate the vertex + * buffer offset below. The important thing is that all vertex buffer + * offsets remain positive. + * + * Note that we use a negative bias variable in order to make the + * rounding maths more easy to follow, and to avoid int / unsigned + * confusion. + */ + for (i = 0; i < svga->curr.velems->count; i++) { - const struct pipe_vertex_buffer *vb = &svga->curr.vb[ve[i].vertex_buffer_index]; + const struct pipe_vertex_buffer *vb = + &svga->curr.vb[ve[i].vertex_buffer_index]; + struct svga_buffer *buffer; + unsigned int offset = vb->buffer_offset + ve[i].src_offset; + unsigned tmp_neg_bias = 0; + + if (!vb->buffer) + continue; + + buffer = svga_buffer(vb->buffer); + if (buffer->uploaded.start > offset) { + tmp_neg_bias = buffer->uploaded.start - offset; + if (vb->stride) + tmp_neg_bias = (tmp_neg_bias + vb->stride - 1) / vb->stride; + neg_bias = MAX2(neg_bias, tmp_neg_bias); + } + } + + for (i = 0; i < svga->curr.velems->count; i++) { + const struct pipe_vertex_buffer *vb = + &svga->curr.vb[ve[i].vertex_buffer_index]; unsigned usage, index; - struct svga_buffer *buffer = svga_buffer(vb->buffer); + struct svga_buffer *buffer; + if (!vb->buffer) + continue; + buffer= svga_buffer(vb->buffer); svga_generate_vdecl_semantics( i, &usage, &index ); /* SVGA_NEW_VELEMENT @@ -121,8 +109,16 @@ static int emit_hw_vs_vdecl( struct svga_context *svga, decl.identity.usage = usage; decl.identity.usageIndex = index; decl.array.stride = vb->stride; - decl.array.offset = (vb->buffer_offset + - ve[i].src_offset); + + /* Compensate for partially uploaded vbo, and + * for the negative index bias. + */ + decl.array.offset = (vb->buffer_offset + + ve[i].src_offset + + neg_bias * vb->stride + - buffer->uploaded.start); + + assert(decl.array.offset >= 0); svga_hwtnl_vdecl( svga->hwtnl, i, @@ -131,6 +127,7 @@ static int emit_hw_vs_vdecl( struct svga_context *svga, vb->buffer ); } + svga_hwtnl_set_index_bias( svga->hwtnl, -neg_bias ); return 0; } @@ -138,23 +135,11 @@ static int emit_hw_vs_vdecl( struct svga_context *svga, static int emit_hw_vdecl( struct svga_context *svga, unsigned dirty ) { - int ret = 0; - /* SVGA_NEW_NEED_SWTNL */ if (svga->state.sw.need_swtnl) return 0; /* Do not emit during swtnl */ - /* If we get to here, we know that we're going to draw. Upload - * userbuffers now and try to combine multiple userbuffers from - * multiple draw calls into a single host buffer for performance. - */ - if (svga->curr.any_user_vertex_buffers) { - ret = upload_user_buffers( svga ); - if (ret) - return ret; - } - return emit_hw_vs_vdecl( svga, dirty ); } diff --git a/src/gallium/include/pipe/p_config.h b/src/gallium/include/pipe/p_config.h index 40f6f2bcb5f..8a5d892c884 100644 --- a/src/gallium/include/pipe/p_config.h +++ b/src/gallium/include/pipe/p_config.h @@ -99,9 +99,9 @@ #endif #endif -#if defined(__PPC__) +#if defined(__ppc__) || defined(__ppc64__) || defined(__PPC__) #define PIPE_ARCH_PPC -#if defined(__PPC64__) +#if defined(__ppc64__) || defined(__PPC64__) #define PIPE_ARCH_PPC_64 #endif #endif @@ -120,6 +120,15 @@ # define PIPE_ARCH_BIG_ENDIAN #endif +#elif defined(__APPLE__) +#include <machine/endian.h> + +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN +# define PIPE_ARCH_LITTLE_ENDIAN +#elif __DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN +# define PIPE_ARCH_BIG_ENDIAN +#endif + #else #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) @@ -134,8 +143,6 @@ #error Unknown Endianness #endif -#if !defined(PIPE_OS_EMBEDDED) - /* * Auto-detect the operating system family. * @@ -222,7 +229,5 @@ #endif #endif /* PIPE_OS_WINDOWS */ -#endif /* !PIPE_OS_EMBEDDED */ - #endif /* P_CONFIG_H_ */ diff --git a/src/gallium/include/pipe/p_context.h b/src/gallium/include/pipe/p_context.h index d8de3bac0ec..da3ee87515f 100644 --- a/src/gallium/include/pipe/p_context.h +++ b/src/gallium/include/pipe/p_context.h @@ -29,6 +29,8 @@ #define PIPE_CONTEXT_H #include "p_compiler.h" +#include "p_format.h" +#include "p_video_enums.h" #ifdef __cplusplus extern "C" { @@ -47,6 +49,7 @@ struct pipe_index_buffer; struct pipe_query; struct pipe_poly_stipple; struct pipe_rasterizer_state; +struct pipe_resolve_info; struct pipe_resource; struct pipe_sampler_state; struct pipe_sampler_view; @@ -57,8 +60,11 @@ struct pipe_stream_output_state; struct pipe_surface; struct pipe_vertex_buffer; struct pipe_vertex_element; +struct pipe_video_buffer; +struct pipe_video_decoder; struct pipe_viewport_state; + /** * Gallium rendering context. Basically: * - state setting functions @@ -263,13 +269,10 @@ struct pipe_context { /** * Resolve a multisampled resource into a non-multisampled one. - * Source and destination must have the same size and same format. + * Source and destination must be of the same format. */ void (*resource_resolve)(struct pipe_context *pipe, - struct pipe_resource *dst, - unsigned dst_layer, - struct pipe_resource *src, - unsigned src_layer); + const struct pipe_resolve_info *info); /*@}*/ @@ -395,6 +398,23 @@ struct pipe_context { * Flush any pending framebuffer writes and invalidate texture caches. */ void (*texture_barrier)(struct pipe_context *); + + /** + * Creates a video decoder for a specific video codec/profile + */ + struct pipe_video_decoder *(*create_video_decoder)( struct pipe_context *context, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height ); + + /** + * Creates a video buffer as decoding target + */ + struct pipe_video_buffer *(*create_video_buffer)( struct pipe_context *context, + enum pipe_format buffer_format, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height ); }; diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h index 2c95c204e5b..1ef3ae71e76 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -99,6 +99,9 @@ enum pipe_error { #define PIPE_MASK_B 0x4 #define PIPE_MASK_A 0x8 #define PIPE_MASK_RGBA 0xf +#define PIPE_MASK_Z 0x10 +#define PIPE_MASK_S 0x20 +#define PIPE_MASK_ZS 0x30 /** @@ -468,6 +471,7 @@ enum pipe_cap { PIPE_CAP_MIXED_COLORBUFFER_FORMATS = 46, PIPE_CAP_SEAMLESS_CUBE_MAP = 47, PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE = 48, + PIPE_CAP_SCALED_RESOLVE = 49 }; /* Shader caps not specific to any single stage */ @@ -509,6 +513,7 @@ struct pipe_query_data_timestamp_disjoint boolean disjoint; }; + #ifdef __cplusplus } #endif diff --git a/src/gallium/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h index 690e9344334..c9f75c019ef 100644 --- a/src/gallium/include/pipe/p_format.h +++ b/src/gallium/include/pipe/p_format.h @@ -229,9 +229,27 @@ enum pipe_format { PIPE_FORMAT_L32A32_FLOAT = 161, PIPE_FORMAT_I32_FLOAT = 162, + PIPE_FORMAT_YV12 = 163, + PIPE_FORMAT_YV16 = 164, + PIPE_FORMAT_IYUV = 165, /**< aka I420 */ + PIPE_FORMAT_NV12 = 166, + PIPE_FORMAT_NV21 = 167, + PIPE_FORMAT_AYUV = PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_VUYA = PIPE_FORMAT_B8G8R8A8_UNORM, + PIPE_FORMAT_XYUV = PIPE_FORMAT_X8R8G8B8_UNORM, + PIPE_FORMAT_VUYX = PIPE_FORMAT_B8G8R8X8_UNORM, + PIPE_FORMAT_IA44 = 168, + PIPE_FORMAT_AI44 = 169, + PIPE_FORMAT_COUNT }; +enum pipe_video_chroma_format +{ + PIPE_VIDEO_CHROMA_FORMAT_420, + PIPE_VIDEO_CHROMA_FORMAT_422, + PIPE_VIDEO_CHROMA_FORMAT_444 +}; #ifdef __cplusplus } diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h index a7845dd24d9..6821edd4a56 100644 --- a/src/gallium/include/pipe/p_screen.h +++ b/src/gallium/include/pipe/p_screen.h @@ -41,6 +41,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_format.h" #include "pipe/p_defines.h" +#include "pipe/p_video_enums.h" @@ -92,6 +93,14 @@ struct pipe_screen { */ int (*get_shader_param)( struct pipe_screen *, unsigned shader, enum pipe_shader_cap param ); + /** + * Query an integer-valued capability/parameter/limit for a codec/profile + * \param param one of PIPE_VIDEO_CAP_x + */ + int (*get_video_param)( struct pipe_screen *, + enum pipe_video_profile profile, + enum pipe_video_cap param ); + struct pipe_context * (*context_create)( struct pipe_screen *, void *priv ); @@ -107,6 +116,14 @@ struct pipe_screen { unsigned bindings ); /** + * Check if the given pipe_format is supported as output for this codec/profile. + * \param profile profile to check, may also be PIPE_VIDEO_PROFILE_UNKNOWN + */ + boolean (*is_video_format_supported)( struct pipe_screen *, + enum pipe_format format, + enum pipe_video_profile profile ); + + /** * Create a new texture object, using the given template info. */ struct pipe_resource * (*resource_create)(struct pipe_screen *, diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index d442c15c02a..840b3ee0e37 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -483,6 +483,34 @@ struct pipe_draw_info }; +/** + * Information to describe a resource_resolve call. + */ +struct pipe_resolve_info +{ + struct { + struct pipe_resource *res; + unsigned level; + unsigned layer; + int x0; /**< always left */ + int y0; /**< always top */ + int x1; /**< determines scale if PIPE_CAP_SCALED_RESOLVE is supported */ + int y1; /**< determines scale if PIPE_CAP_SCALED_RESOLVE is supported */ + } dst; + + struct { + struct pipe_resource *res; + unsigned layer; + int x0; + int y0; + int x1; /**< may be < x0 only if PIPE_CAP_SCALED_RESOLVE is supported */ + int y1; /**< may be < y1 even if PIPE_CAP_SCALED_RESOLVE not supported */ + } src; + + unsigned mask; /**< PIPE_MASK_RGBA, Z, S or ZS */ +}; + + #ifdef __cplusplus } #endif diff --git a/src/gallium/include/pipe/p_video_decoder.h b/src/gallium/include/pipe/p_video_decoder.h new file mode 100644 index 00000000000..f063d8f3a1b --- /dev/null +++ b/src/gallium/include/pipe/p_video_decoder.h @@ -0,0 +1,170 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef PIPE_VIDEO_CONTEXT_H +#define PIPE_VIDEO_CONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <pipe/p_video_state.h> + +struct pipe_screen; +struct pipe_surface; +struct pipe_macroblock; +struct pipe_picture_desc; +struct pipe_fence_handle; + +/** + * Gallium video decoder for a specific codec/profile + */ +struct pipe_video_decoder +{ + struct pipe_context *context; + + enum pipe_video_profile profile; + enum pipe_video_entrypoint entrypoint; + enum pipe_video_chroma_format chroma_format; + unsigned width; + unsigned height; + + /** + * destroy this video decoder + */ + void (*destroy)(struct pipe_video_decoder *decoder); + + /** + * Creates a buffer as decoding input + */ + struct pipe_video_decode_buffer *(*create_buffer)(struct pipe_video_decoder *decoder); + + /** + * flush decoder buffer to video hardware + */ + void (*flush_buffer)(struct pipe_video_decode_buffer *decbuf, + unsigned num_ycbcr_blocks[3], + struct pipe_video_buffer *ref_frames[2], + struct pipe_video_buffer *dst); +}; + +/** + * input buffer for a decoder + */ +struct pipe_video_decode_buffer +{ + struct pipe_video_decoder *decoder; + + /** + * destroy this decode buffer + */ + void (*destroy)(struct pipe_video_decode_buffer *decbuf); + + /** + * map the input buffer into memory before starting decoding + */ + void (*begin_frame)(struct pipe_video_decode_buffer *decbuf); + + /** + * set the quantification matrixes + */ + void (*set_quant_matrix)(struct pipe_video_decode_buffer *decbuf, + const uint8_t intra_matrix[64], + const uint8_t non_intra_matrix[64]); + + /** + * get the pointer where to put the ycbcr blocks of a component + */ + struct pipe_ycbcr_block *(*get_ycbcr_stream)(struct pipe_video_decode_buffer *, int component); + + /** + * get the pointer where to put the ycbcr dct block data of a component + */ + short *(*get_ycbcr_buffer)(struct pipe_video_decode_buffer *, int component); + + /** + * get the stride of the mv buffer + */ + unsigned (*get_mv_stream_stride)(struct pipe_video_decode_buffer *decbuf); + + /** + * get the pointer where to put the motion vectors of a ref frame + */ + struct pipe_motionvector *(*get_mv_stream)(struct pipe_video_decode_buffer *decbuf, int ref_frame); + + /** + * decode a bitstream + */ + void (*decode_bitstream)(struct pipe_video_decode_buffer *decbuf, + unsigned num_bytes, const void *data, + struct pipe_picture_desc *picture, + unsigned num_ycbcr_blocks[3]); + + /** + * unmap decoder buffer before flushing + */ + void (*end_frame)(struct pipe_video_decode_buffer *decbuf); +}; + +/** + * output for decoding / input for displaying + */ +struct pipe_video_buffer +{ + struct pipe_context *context; + + enum pipe_format buffer_format; + enum pipe_video_chroma_format chroma_format; + unsigned width; + unsigned height; + + /** + * destroy this video buffer + */ + void (*destroy)(struct pipe_video_buffer *buffer); + + /** + * get a individual sampler view for each plane + */ + struct pipe_sampler_view **(*get_sampler_view_planes)(struct pipe_video_buffer *buffer); + + /** + * get a individual sampler view for each component + */ + struct pipe_sampler_view **(*get_sampler_view_components)(struct pipe_video_buffer *buffer); + + /** + * get a individual surfaces for each plane + */ + struct pipe_surface **(*get_surfaces)(struct pipe_video_buffer *buffer); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* PIPE_VIDEO_CONTEXT_H */ diff --git a/src/gallium/include/pipe/p_video_enums.h b/src/gallium/include/pipe/p_video_enums.h new file mode 100644 index 00000000000..492ab84e33f --- /dev/null +++ b/src/gallium/include/pipe/p_video_enums.h @@ -0,0 +1,74 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef PIPE_VIDEO_ENUMS_H +#define PIPE_VIDEO_ENUMS_H + +enum pipe_video_profile +{ + PIPE_VIDEO_PROFILE_UNKNOWN, + PIPE_VIDEO_PROFILE_MPEG1, + PIPE_VIDEO_PROFILE_MPEG2_SIMPLE, + PIPE_VIDEO_PROFILE_MPEG2_MAIN, + PIPE_VIDEO_PROFILE_MPEG4_SIMPLE, + PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE, + PIPE_VIDEO_PROFILE_VC1_SIMPLE, + PIPE_VIDEO_PROFILE_VC1_MAIN, + PIPE_VIDEO_PROFILE_VC1_ADVANCED, + PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE, + PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN, + PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH +}; + +/* Video caps, can be different for each codec/profile */ +enum pipe_video_cap +{ + PIPE_VIDEO_CAP_SUPPORTED = 0, + PIPE_VIDEO_CAP_NPOT_TEXTURES = 1, + PIPE_VIDEO_CAP_MAX_WIDTH = 2, + PIPE_VIDEO_CAP_MAX_HEIGHT = 3, +}; + +enum pipe_video_codec +{ + PIPE_VIDEO_CODEC_UNKNOWN = 0, + PIPE_VIDEO_CODEC_MPEG12, /**< MPEG1, MPEG2 */ + PIPE_VIDEO_CODEC_MPEG4, /**< DIVX, XVID */ + PIPE_VIDEO_CODEC_VC1, /**< WMV */ + PIPE_VIDEO_CODEC_MPEG4_AVC /**< H.264 */ +}; + +enum pipe_video_entrypoint +{ + PIPE_VIDEO_ENTRYPOINT_UNKNOWN, + PIPE_VIDEO_ENTRYPOINT_BITSTREAM, + PIPE_VIDEO_ENTRYPOINT_IDCT, + PIPE_VIDEO_ENTRYPOINT_MC +}; + + +#endif /* PIPE_VIDEO_ENUMS_H */ diff --git a/src/gallium/include/pipe/p_video_state.h b/src/gallium/include/pipe/p_video_state.h new file mode 100644 index 00000000000..2a64ffb5601 --- /dev/null +++ b/src/gallium/include/pipe/p_video_state.h @@ -0,0 +1,125 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef PIPE_VIDEO_STATE_H +#define PIPE_VIDEO_STATE_H + +#include <pipe/p_defines.h> +#include <pipe/p_format.h> +#include <pipe/p_state.h> +#include <pipe/p_screen.h> +#include <util/u_inlines.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct pipe_video_rect +{ + unsigned x, y, w, h; +}; + +enum pipe_mpeg12_picture_type +{ + PIPE_MPEG12_PICTURE_TYPE_FIELD_TOP, + PIPE_MPEG12_PICTURE_TYPE_FIELD_BOTTOM, + PIPE_MPEG12_PICTURE_TYPE_FRAME +}; + +enum pipe_mpeg12_dct_intra +{ + PIPE_MPEG12_DCT_DELTA = 0, + PIPE_MPEG12_DCT_INTRA = 1 +}; + +enum pipe_mpeg12_dct_type +{ + PIPE_MPEG12_DCT_TYPE_FRAME = 0, + PIPE_MPEG12_DCT_TYPE_FIELD = 1 +}; + +enum pipe_video_field_select +{ + PIPE_VIDEO_FRAME = 0, + PIPE_VIDEO_TOP_FIELD = 1, + PIPE_VIDEO_BOTTOM_FIELD = 3, + + /* TODO + PIPE_VIDEO_DUALPRIME + PIPE_VIDEO_16x8 + */ +}; + +enum pipe_video_mv_weight +{ + PIPE_VIDEO_MV_WEIGHT_MIN = 0, + PIPE_VIDEO_MV_WEIGHT_HALF = 128, + PIPE_VIDEO_MV_WEIGHT_MAX = 256 +}; + +/* bitfields because this is used as a vertex buffer element */ +struct pipe_motionvector +{ + struct { + short x, y; + ushort field_select; /**< enum pipe_video_field_select */ + ushort weight; /**< enum pipe_video_mv_weight */ + } top, bottom; +}; + +/* bitfields because this is used as a vertex buffer element */ +struct pipe_ycbcr_block +{ + ubyte x, y; + ubyte intra; /**< enum pipe_mpeg12_dct_intra */ + ubyte coding; /**< enum pipe_mpeg12_dct_type */ +}; + +struct pipe_picture_desc +{ + enum pipe_video_profile profile; +}; + +struct pipe_mpeg12_picture_desc +{ + struct pipe_picture_desc base; + + unsigned picture_coding_type; + unsigned picture_structure; + unsigned frame_pred_frame_dct; + unsigned q_scale_type; + unsigned alternate_scan; + unsigned intra_vlc_format; + unsigned concealment_motion_vectors; + unsigned f_code[2][2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* PIPE_VIDEO_STATE_H */ diff --git a/src/gallium/include/state_tracker/st_api.h b/src/gallium/include/state_tracker/st_api.h index 04fc7c6c5de..f7cc2437747 100644 --- a/src/gallium/include/state_tracker/st_api.h +++ b/src/gallium/include/state_tracker/st_api.h @@ -253,6 +253,12 @@ struct st_context_attribs struct st_framebuffer_iface { /** + * Atomic stamp which changes when framebuffers need to be updated. + */ + + int32_t stamp; + + /** * Available for the state tracker manager to use. */ void *st_manager_private; @@ -315,25 +321,6 @@ struct st_context_iface void (*destroy)(struct st_context_iface *stctxi); /** - * Invalidate the current textures that was taken from a framebuffer. - * - * The state tracker manager calls this function to let the rendering - * context know that it should update the textures it got from - * st_framebuffer_iface::validate. It should do so at the latest time possible. - * Possible right before sending triangles to the pipe context. - * - * For certain platforms this function might be called from a thread other - * than the thread that the context is currently bound in, and must - * therefore be thread safe. But it is the state tracker manager's - * responsibility to make sure that the framebuffer is bound to the context - * and the API context is current for the duration of this call. - * - * Thus reducing the sync primitive needed to a single atomic flag. - */ - void (*notify_invalid_framebuffer)(struct st_context_iface *stctxi, - struct st_framebuffer_iface *stfbi); - - /** * Flush all drawing from context to the pipe also flushes the pipe. */ void (*flush)(struct st_context_iface *stctxi, unsigned flags, diff --git a/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp b/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp index 741a97f897d..0bb9d852f84 100644 --- a/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp +++ b/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp @@ -250,21 +250,21 @@ struct GalliumDXGIAdapter DXGI_ADAPTER_DESC1 desc; std::vector<ComPtr<IDXGIOutput> > outputs; int num_outputs; - struct native_event_handler handler; GalliumDXGIAdapter(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy) { this->parent = factory; - /* FIXME handler should be static */ - handler.invalid_surface = handle_invalid_surface; - handler.new_drm_screen = dxgi_loader_create_drm_screen; - handler.new_sw_screen = dxgi_loader_create_sw_screen; - platform->set_event_handler(&handler); - - display = platform->create_display(dpy, FALSE, this); + display = platform->create_display(dpy, FALSE); if(!display) - display = platform->create_display(dpy, TRUE, this); + display = platform->create_display(dpy, TRUE); + if (display) { + display->user_data = this; + if (!display->init_screen(display)) { + display->destroy(display); + display = NULL; + } + } if(!display) throw E_FAIL; memset(&desc, 0, sizeof(desc)); @@ -1413,6 +1413,11 @@ struct dxgi_binding static dxgi_binding dxgi_default_binding; static __thread dxgi_binding dxgi_thread_binding; +static const struct native_event_handler dxgi_event_handler = { + GalliumDXGIAdapter::handle_invalid_surface, + dxgi_loader_create_drm_screen, + dxgi_loader_create_sw_screen +}; void STDMETHODCALLTYPE GalliumDXGIUseNothing() { @@ -1427,7 +1432,7 @@ void STDMETHODCALLTYPE GalliumDXGIUseNothing() void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, IGalliumDXGIBackend* backend) { GalliumDXGIUseNothing(); - dxgi_thread_binding.platform = native_get_x11_platform(); + dxgi_thread_binding.platform = native_get_x11_platform(&dxgi_event_handler); dxgi_thread_binding.display = dpy; if(backend) @@ -1443,7 +1448,7 @@ void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, IGalliumDXGIBacken void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd) { GalliumDXGIUseNothing(); - dxgi_thread_binding.platform = native_get_drm_platform(); + dxgi_thread_binding.platform = native_get_drm_platform(&dxgi_event_handler); dxgi_thread_binding.display = (void*)fd; dxgi_thread_binding.backend = 0; } @@ -1453,7 +1458,7 @@ void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd) void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd) { GalliumDXGIUseNothing(); - dxgi_thread_binding.platform = native_get_fbdev_platform(); + dxgi_thread_binding.platform = native_get_fbdev_platform(&dxgi_event_handler); dxgi_thread_binding.display = (void*)fd; dxgi_thread_binding.backend = 0; } @@ -1463,7 +1468,7 @@ void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd) void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie) { GalliumDXGIUseNothing(); - dxgi_thread_binding.platform = native_get_gdi_platform(); + dxgi_thread_binding.platform = native_get_gdi_platform(&dxgi_event_handler); dxgi_thread_binding.display = (void*)hdc; dxgi_thread_binding.backend = 0; } @@ -1493,7 +1498,7 @@ void STDMETHODCALLTYPE GalliumDXGIMakeDefault() else if(dxgi_default_binding.platform) factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.backend); else - factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL); + factory = new GalliumDXGIFactory(native_get_x11_platform(&dxgi_event_handler), NULL, NULL); HRESULT hres = factory->QueryInterface(riid, out_factory); factory->Release(); return hres; diff --git a/src/gallium/state_trackers/dri/common/dri_context.c b/src/gallium/state_trackers/dri/common/dri_context.c index e23c1bcafaf..e6612b1911d 100644 --- a/src/gallium/state_trackers/dri/common/dri_context.c +++ b/src/gallium/state_trackers/dri/common/dri_context.c @@ -143,16 +143,12 @@ dri_unbind_context(__DRIcontext * cPriv) /* dri_util.c ensures cPriv is not null */ struct dri_screen *screen = dri_screen(cPriv->driScreenPriv); struct dri_context *ctx = dri_context(cPriv); - struct dri_drawable *draw = dri_drawable(ctx->dPriv); - struct dri_drawable *read = dri_drawable(ctx->rPriv); struct st_api *stapi = screen->st_api; if (--ctx->bind_count == 0) { if (ctx->st == ctx->stapi->get_current(ctx->stapi)) { ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL); stapi->make_current(stapi, NULL, NULL, NULL); - draw->context = NULL; - read->context = NULL; } } @@ -180,12 +176,10 @@ dri_make_current(__DRIcontext * cPriv, else if (!driDrawPriv || !driReadPriv) return GL_FALSE; - draw->context = ctx; if (ctx->dPriv != driDrawPriv) { ctx->dPriv = driDrawPriv; draw->texture_stamp = driDrawPriv->lastStamp - 1; } - read->context = ctx; if (ctx->rPriv != driReadPriv) { ctx->rPriv = driReadPriv; read->texture_stamp = driReadPriv->lastStamp - 1; diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.c b/src/gallium/state_trackers/dri/common/dri_drawable.c index 28a33ac7d07..7b8de3174be 100644 --- a/src/gallium/state_trackers/dri/common/dri_drawable.c +++ b/src/gallium/state_trackers/dri/common/dri_drawable.c @@ -136,6 +136,7 @@ dri_create_buffer(__DRIscreen * sPriv, drawable->sPriv = sPriv; drawable->dPriv = dPriv; dPriv->driverPrivate = (void *)drawable; + p_atomic_set(&drawable->base.stamp, 1); return GL_TRUE; fail: diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.h b/src/gallium/state_trackers/dri/common/dri_drawable.h index 7f1aa512ca1..fd3460dd30b 100644 --- a/src/gallium/state_trackers/dri/common/dri_drawable.h +++ b/src/gallium/state_trackers/dri/common/dri_drawable.h @@ -42,7 +42,6 @@ struct dri_drawable struct st_visual stvis; struct dri_screen *screen; - struct dri_context *context; /* dri */ __DRIdrawable *dPriv; diff --git a/src/gallium/state_trackers/dri/drm/SConscript b/src/gallium/state_trackers/dri/drm/SConscript index b188f76f910..c63918a0e18 100644 --- a/src/gallium/state_trackers/dri/drm/SConscript +++ b/src/gallium/state_trackers/dri/drm/SConscript @@ -5,7 +5,7 @@ Import('*') env = env.Clone() -env.ParseConfig('pkg-config --cflags --libs libdrm') +env.PkgUseModules(['DRM']) env.Append(CPPPATH = [ '#/src/mapi', diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c index e471e8e5be2..fe4ddb312be 100644 --- a/src/gallium/state_trackers/dri/drm/dri2.c +++ b/src/gallium/state_trackers/dri/drm/dri2.c @@ -52,13 +52,11 @@ static void dri2_invalidate_drawable(__DRIdrawable *dPriv) { struct dri_drawable *drawable = dri_drawable(dPriv); - struct dri_context *ctx = drawable->context; dri2InvalidateDrawable(dPriv); drawable->dPriv->lastStamp = *drawable->dPriv->pStamp; - if (ctx) - ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base); + p_atomic_inc(&drawable->base.stamp); } static const __DRI2flushExtension dri2FlushExtension = { @@ -564,6 +562,24 @@ dri2_query_image(__DRIimage *image, int attrib, int *value) } } +static __DRIimage * +dri2_dup_image(__DRIimage *image, void *loaderPrivate) +{ + __DRIimage *img; + + img = CALLOC_STRUCT(__DRIimageRec); + if (!img) + return NULL; + + img->texture = NULL; + pipe_resource_reference(&img->texture, image->texture); + img->level = image->level; + img->layer = image->layer; + img->loader_private = loaderPrivate; + + return img; +} + static void dri2_destroy_image(__DRIimage *img) { @@ -578,6 +594,7 @@ static struct __DRIimageExtensionRec dri2ImageExtension = { dri2_destroy_image, dri2_create_image, dri2_query_image, + dri2_dup_image, }; /* diff --git a/src/gallium/state_trackers/dri/sw/drisw.c b/src/gallium/state_trackers/dri/sw/drisw.c index ac11f7c47f6..a1879a8f46a 100644 --- a/src/gallium/state_trackers/dri/sw/drisw.c +++ b/src/gallium/state_trackers/dri/sw/drisw.c @@ -103,14 +103,11 @@ drisw_present_texture(__DRIdrawable *dPriv, static INLINE void drisw_invalidate_drawable(__DRIdrawable *dPriv) { - struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); struct dri_drawable *drawable = dri_drawable(dPriv); drawable->texture_stamp = dPriv->lastStamp - 1; - /* check if swapping currently bound buffer */ - if (ctx && ctx->dPriv == dPriv) - ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base); + p_atomic_inc(&drawable->base.stamp); } static INLINE void diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile index 763e7b58a49..1c970222c1f 100644 --- a/src/gallium/state_trackers/egl/Makefile +++ b/src/gallium/state_trackers/egl/Makefile @@ -33,7 +33,8 @@ wayland_INCLUDES = \ wayland_SOURCES = $(wildcard wayland/*.c) wayland_OBJECTS = $(wayland_SOURCES:.c=.o) -drm_INCLUDES = -I$(TOP)/src/gallium/winsys $(shell pkg-config --cflags-only-I libdrm) +drm_INCLUDES = -I$(TOP)/src/gallium/winsys $(shell pkg-config --cflags-only-I libdrm) \ + -I$(TOP)/src/gbm/main -I$(TOP)/src/gallium/state_trackers/gbm drm_SOURCES = $(wildcard drm/*.c) drm_OBJECTS = $(drm_SOURCES:.c=.o) diff --git a/src/gallium/state_trackers/egl/SConscript b/src/gallium/state_trackers/egl/SConscript index 9ade76ecbb2..c04fec637c1 100644 --- a/src/gallium/state_trackers/egl/SConscript +++ b/src/gallium/state_trackers/egl/SConscript @@ -40,7 +40,12 @@ else: env.Append(CPPDEFINES = ['GLX_DIRECT_RENDERING']) sources.append(['#/src/glx/dri2.c']) if env['drm']: + env.PkgUseModules('DRM') env.Append(CPPDEFINES = ['HAVE_DRM_BACKEND']) + env.Append(CPPPATH = [ + '#/src/gbm/main', + '#/src/gallium/state_trackers/gbm', + ]) sources.append(['drm/native_drm.c', 'drm/modeset.c']) st_egl = env.ConvenienceLibrary( diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c index 29dbbefbf48..6649f02b244 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d.c @@ -31,6 +31,7 @@ #include "util/u_memory.h" #include "util/u_format.h" #include "util/u_string.h" +#include "util/u_atomic.h" #include "egl_g3d.h" #include "egl_g3d_api.h" @@ -45,15 +46,9 @@ egl_g3d_invalid_surface(struct native_display *ndpy, { /* XXX not thread safe? */ struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); - struct egl_g3d_context *gctx; - - /* - * Some functions such as egl_g3d_copy_buffers create a temporary native - * surface. There is no gsurf associated with it. - */ - gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; - if (gctx) - gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); + + if (gsurf && gsurf->stfbi) + p_atomic_inc(&gsurf->stfbi->stamp); } static struct pipe_screen * @@ -72,10 +67,26 @@ egl_g3d_new_sw_screen(struct native_display *ndpy, struct sw_winsys *ws) return gdpy->loader->create_sw_screen(ws); } -static struct native_event_handler egl_g3d_native_event_handler = { +static struct pipe_resource * +egl_g3d_lookup_egl_image(struct native_display *ndpy, void *egl_image) +{ + _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct st_egl_image img; + struct pipe_resource *resource = NULL; + + memset(&img, 0, sizeof(img)); + if (gdpy->smapi->get_egl_image(gdpy->smapi, egl_image, &img)) + resource = img.texture; + + return resource; +} + +static const struct native_event_handler egl_g3d_native_event_handler = { egl_g3d_invalid_surface, egl_g3d_new_drm_screen, - egl_g3d_new_sw_screen + egl_g3d_new_sw_screen, + egl_g3d_lookup_egl_image }; /** @@ -94,40 +105,38 @@ egl_g3d_get_platform(_EGLDriver *drv, _EGLPlatformType plat) case _EGL_PLATFORM_WINDOWS: plat_name = "Windows"; #ifdef HAVE_GDI_BACKEND - nplat = native_get_gdi_platform(); + nplat = native_get_gdi_platform(&egl_g3d_native_event_handler); #endif break; case _EGL_PLATFORM_X11: plat_name = "X11"; #ifdef HAVE_X11_BACKEND - nplat = native_get_x11_platform(); + nplat = native_get_x11_platform(&egl_g3d_native_event_handler); #endif break; case _EGL_PLATFORM_WAYLAND: plat_name = "wayland"; #ifdef HAVE_WAYLAND_BACKEND - nplat = native_get_wayland_platform(); + nplat = native_get_wayland_platform(&egl_g3d_native_event_handler); #endif break; case _EGL_PLATFORM_DRM: plat_name = "DRM"; #ifdef HAVE_DRM_BACKEND - nplat = native_get_drm_platform(); + nplat = native_get_drm_platform(&egl_g3d_native_event_handler); #endif break; case _EGL_PLATFORM_FBDEV: plat_name = "FBDEV"; #ifdef HAVE_FBDEV_BACKEND - nplat = native_get_fbdev_platform(); + nplat = native_get_fbdev_platform(&egl_g3d_native_event_handler); #endif break; default: break; } - if (nplat) - nplat->set_event_handler(&egl_g3d_native_event_handler); - else + if (!nplat) _eglLog(_EGL_WARNING, "unsupported platform %s", plat_name); gdrv->platforms[plat] = nplat; @@ -504,13 +513,20 @@ egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy) gdpy->loader = gdrv->loader; dpy->DriverData = gdpy; - _eglLog(_EGL_INFO, "use %s for display %p", nplat->name, dpy->PlatformDisplay); - gdpy->native = nplat->create_display(dpy->PlatformDisplay, - dpy->Options.UseFallback, (void *) dpy); + _eglLog(_EGL_INFO, "use %s for display %p", + nplat->name, dpy->PlatformDisplay); + gdpy->native = + nplat->create_display(dpy->PlatformDisplay, dpy->Options.UseFallback); if (!gdpy->native) { _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); goto fail; } + gdpy->native->user_data = (void *) dpy; + if (!gdpy->native->init_screen(gdpy->native)) { + _eglError(EGL_NOT_INITIALIZED, + "eglInitialize(failed to initialize screen)"); + goto fail; + } if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_DEFAULT_MASK) dpy->ClientAPIs |= EGL_OPENGL_BIT; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.h b/src/gallium/state_trackers/egl/common/egl_g3d.h index 301db3128ff..5989a023573 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d.h @@ -126,4 +126,12 @@ _EGL_DRIVER_TYPECAST(egl_g3d_screen, _EGLScreen, obj) #endif /* EGL_MESA_screen_surface */ +static INLINE struct st_api * +egl_g3d_get_st_api(_EGLDriver *drv, enum st_api_type api) +{ + struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); + + return gdrv->loader->get_st_api(api); +} + #endif /* _EGL_G3D_H_ */ diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_api.c b/src/gallium/state_trackers/egl/common/egl_g3d_api.c index 8b1821e0055..f897054a540 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_api.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_api.c @@ -37,7 +37,6 @@ #include "egl_g3d_image.h" #include "egl_g3d_sync.h" #include "egl_g3d_st.h" -#include "egl_g3d_loader.h" #include "native.h" /** @@ -47,7 +46,6 @@ static struct st_api * egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx, enum st_profile_type *profile) { - struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); struct st_api *stapi; EGLint api = -1; @@ -81,96 +79,66 @@ egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx, break; } - switch (api) { - case ST_API_OPENGL: - stapi = gdrv->loader->guess_gl_api(*profile); - break; - case ST_API_OPENVG: - stapi = gdrv->loader->get_st_api(api); - break; - default: - stapi = NULL; - break; - } + stapi = egl_g3d_get_st_api(drv, api); if (stapi && !(stapi->profile_mask & (1 << *profile))) stapi = NULL; return stapi; } +struct egl_g3d_choose_config_data { + _EGLConfig criteria; + enum pipe_format format; +}; + static int egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2, void *priv_data) { - const _EGLConfig *criteria = (const _EGLConfig *) priv_data; + struct egl_g3d_choose_config_data *data = + (struct egl_g3d_choose_config_data *) priv_data; + const _EGLConfig *criteria = &data->criteria;; /* EGL_NATIVE_VISUAL_TYPE ignored? */ return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); } static EGLBoolean -egl_g3d_match_config(const _EGLConfig *conf, const _EGLConfig *criteria) +egl_g3d_match_config(const _EGLConfig *conf, void *priv_data) { - if (!_eglMatchConfig(conf, criteria)) - return EGL_FALSE; - - if (criteria->MatchNativePixmap != EGL_NONE && - criteria->MatchNativePixmap != EGL_DONT_CARE) { - struct egl_g3d_display *gdpy = egl_g3d_display(conf->Display); - struct egl_g3d_config *gconf = egl_g3d_config(conf); - EGLNativePixmapType pix = - (EGLNativePixmapType) criteria->MatchNativePixmap; + struct egl_g3d_choose_config_data *data = + (struct egl_g3d_choose_config_data *) priv_data; + struct egl_g3d_config *gconf = egl_g3d_config(conf); - if (!gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) - return EGL_FALSE; - } + if (data->format != PIPE_FORMAT_NONE && + data->format != gconf->native->color_format) + return EGL_FALSE; - return EGL_TRUE; + return _eglMatchConfig(conf, &data->criteria); } static EGLBoolean egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs, EGLConfig *configs, EGLint size, EGLint *num_configs) { - _EGLConfig **tmp_configs, criteria; - EGLint tmp_size, i; - - if (!num_configs) - return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); + struct egl_g3d_choose_config_data data; - if (!_eglParseConfigAttribList(&criteria, dpy, attribs)) + if (!_eglParseConfigAttribList(&data.criteria, dpy, attribs)) return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - /* get the number of matched configs */ - tmp_size = _eglFilterArray(dpy->Configs, NULL, 0, - (_EGLArrayForEach) egl_g3d_match_config, (void *) &criteria); - if (!tmp_size) { - *num_configs = tmp_size; - return EGL_TRUE; - } - - tmp_configs = MALLOC(sizeof(tmp_configs[0]) * tmp_size); - if (!tmp_configs) - return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); + data.format = PIPE_FORMAT_NONE; + if (data.criteria.MatchNativePixmap != EGL_NONE && + data.criteria.MatchNativePixmap != EGL_DONT_CARE) { + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - /* get the matched configs */ - _eglFilterArray(dpy->Configs, (void **) tmp_configs, tmp_size, - (_EGLArrayForEach) egl_g3d_match_config, (void *) &criteria); - - /* perform sorting of configs */ - if (configs && tmp_size) { - _eglSortConfigs((const _EGLConfig **) tmp_configs, tmp_size, - egl_g3d_compare_config, (void *) &criteria); - tmp_size = MIN2(tmp_size, size); - for (i = 0; i < tmp_size; i++) - configs[i] = _eglGetConfigHandle(tmp_configs[i]); + if (!gdpy->native->get_pixmap_format(gdpy->native, + (EGLNativePixmapType) data.criteria.MatchNativePixmap, + &data.format)) + return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglChooseConfig"); } - FREE(tmp_configs); - - *num_configs = tmp_size; - - return EGL_TRUE; + return _eglFilterConfigArray(dpy->Configs, configs, size, num_configs, + egl_g3d_match_config, egl_g3d_compare_config, &data); } static _EGLContext * @@ -536,19 +504,12 @@ egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); if (ok) { if (gdraw) { - gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, - gdraw->stfbi); - if (gdraw->base.Type == EGL_WINDOW_BIT) { gctx->base.WindowRenderBuffer = (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; } } - if (gread && gread != gdraw) { - gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, - gread->stfbi); - } } } else if (old_gctx) { @@ -614,21 +575,6 @@ egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) gsurf->base.SwapInterval); } -/** - * Get the pipe surface of the given attachment of the native surface. - */ -static struct pipe_resource * -get_pipe_resource(struct native_display *ndpy, struct native_surface *nsurf, - enum native_attachment natt) -{ - struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS]; - - textures[natt] = NULL; - nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL); - - return textures[natt]; -} - static EGLBoolean egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLNativePixmapType target) @@ -636,43 +582,18 @@ egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, struct egl_g3d_display *gdpy = egl_g3d_display(dpy); struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); _EGLContext *ctx = _eglGetCurrentContext(); - struct native_surface *nsurf; - struct pipe_resource *ptex; - struct pipe_context *pipe; if (!gsurf->render_texture) return EGL_TRUE; - nsurf = gdpy->native->create_pixmap_surface(gdpy->native, target, NULL); - if (!nsurf) - return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); - /* flush if the surface is current */ if (ctx && ctx->DrawSurface == &gsurf->base) { struct egl_g3d_context *gctx = egl_g3d_context(ctx); gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL); } - pipe = ndpy_get_copy_context(gdpy->native); - if (!pipe) - return EGL_FALSE; - - ptex = get_pipe_resource(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); - if (ptex) { - struct pipe_box src_box; - - u_box_origin_2d(ptex->width0, ptex->height0, &src_box); - pipe->resource_copy_region(pipe, ptex, 0, 0, 0, 0, - gsurf->render_texture, 0, &src_box); - pipe->flush(pipe, NULL); - nsurf->present(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT, FALSE, 0); - - pipe_resource_reference(&ptex, NULL); - } - - nsurf->destroy(nsurf); - - return EGL_TRUE; + return gdpy->native->copy_to_pixmap(gdpy->native, + target, gsurf->render_texture); } static EGLBoolean 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 ce72e27c3d5..7e9a29b0284 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_image.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.c @@ -37,9 +37,6 @@ #include "egl_g3d.h" #include "egl_g3d_image.h" -/* for struct winsys_handle */ -#include "state_tracker/drm_driver.h" - /** * Reference and return the front left buffer of the native pixmap. */ @@ -137,10 +134,9 @@ egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, _EGLImage *img, const EGLint *attribs) { struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct pipe_resource templ; - struct winsys_handle wsh; _EGLImageAttribs attrs; EGLint format; + struct native_buffer nbuf; if (!dpy->Extensions.MESA_drm_image) return NULL; @@ -166,21 +162,21 @@ egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, break; } - memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; - templ.format = format; - templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; - templ.width0 = attrs.Width; - templ.height0 = attrs.Height; - templ.depth0 = 1; - templ.array_size = 1; - - memset(&wsh, 0, sizeof(wsh)); - wsh.handle = (unsigned) name; - wsh.stride = - attrs.DRMBufferStrideMESA * util_format_get_blocksize(templ.format); - - return gdpy->native->buffer->import_buffer(gdpy->native, &templ, &wsh); + memset(&nbuf, 0, sizeof(nbuf)); + nbuf.type = NATIVE_BUFFER_DRM; + nbuf.u.drm.templ.target = PIPE_TEXTURE_2D; + nbuf.u.drm.templ.format = format; + nbuf.u.drm.templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + nbuf.u.drm.templ.width0 = attrs.Width; + nbuf.u.drm.templ.height0 = attrs.Height; + nbuf.u.drm.templ.depth0 = 1; + nbuf.u.drm.templ.array_size = 1; + + nbuf.u.drm.name = name; + nbuf.u.drm.stride = + attrs.DRMBufferStrideMESA * util_format_get_blocksize(format); + + return gdpy->native->buffer->import_buffer(gdpy->native, &nbuf); } #endif /* EGL_MESA_drm_image */ @@ -327,35 +323,26 @@ egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, { struct egl_g3d_display *gdpy = egl_g3d_display(dpy); struct egl_g3d_image *gimg = egl_g3d_image(img); - struct winsys_handle wsh; + struct native_buffer nbuf; if (!dpy->Extensions.MESA_drm_image) return EGL_FALSE; - /* get shared handle */ - if (name) { - memset(&handle, 0, sizeof(handle)); - wsh.type = DRM_API_HANDLE_TYPE_SHARED; - if (!gdpy->native->buffer->export_buffer(gdpy->native, - gimg->texture, &wsh)) - return EGL_FALSE; + memset(&nbuf, 0, sizeof(nbuf)); + nbuf.type = NATIVE_BUFFER_DRM; + if (name) + nbuf.u.drm.templ.bind |= PIPE_BIND_SHARED; - *name = wsh.handle; - } + if (!gdpy->native->buffer->export_buffer(gdpy->native, + gimg->texture, &nbuf)) + return EGL_FALSE; - /* get KMS handle */ - if (handle || stride) { - memset(&wsh, 0, sizeof(wsh)); - wsh.type = DRM_API_HANDLE_TYPE_KMS; - if (!gdpy->native->buffer->export_buffer(gdpy->native, - gimg->texture, &wsh)) - return EGL_FALSE; - - if (handle) - *handle = wsh.handle; - if (stride) - *stride = wsh.stride; - } + if (name) + *name = nbuf.u.drm.name; + if (handle) + *handle = nbuf.u.drm.handle; + if (stride) + *stride = nbuf.u.drm.stride; return EGL_TRUE; } diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_loader.h b/src/gallium/state_trackers/egl/common/egl_g3d_loader.h index 78bfe2131ef..e9403fa293b 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_loader.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d_loader.h @@ -39,7 +39,6 @@ struct sw_winsys; struct egl_g3d_loader { uint profile_masks[ST_API_COUNT]; struct st_api *(*get_st_api)(enum st_api_type api); - struct st_api *(*guess_gl_api)(enum st_profile_type profile); struct pipe_screen *(*create_drm_screen)(const char *name, int fd); struct pipe_screen *(*create_sw_screen)(struct sw_winsys *ws); 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 2b944b521a4..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); @@ -292,6 +293,8 @@ egl_g3d_create_st_framebuffer(_EGLSurface *surf) return NULL; stfbi->visual = &gsurf->stvis; + p_atomic_set(&stfbi->stamp, 1); + if (gsurf->base.Type != EGL_PBUFFER_BIT) { stfbi->flush_front = egl_g3d_st_framebuffer_flush_front; stfbi->validate = egl_g3d_st_framebuffer_validate; diff --git a/src/gallium/state_trackers/egl/common/native.h b/src/gallium/state_trackers/egl/common/native.h index 8646e52ed7c..fc50ee485fe 100644 --- a/src/gallium/state_trackers/egl/common/native.h +++ b/src/gallium/state_trackers/egl/common/native.h @@ -152,6 +152,11 @@ struct native_display { */ void *user_data; + /** + * Initialize and create the pipe screen. + */ + boolean (*init_screen)(struct native_display *ndpy); + void (*destroy)(struct native_display *ndpy); /** @@ -170,16 +175,21 @@ struct native_display { int *num_configs); /** - * Test if a pixmap is supported by the given config. Required unless no - * config has pixmap_bit set. - * - * This function is usually called to find a config that supports a given - * pixmap. Thus, it is usually called with the same pixmap in a row. + * Get the color format of the pixmap. Required unless no config has + * pixmap_bit set. */ - boolean (*is_pixmap_supported)(struct native_display *ndpy, - EGLNativePixmapType pix, - const struct native_config *nconf); + boolean (*get_pixmap_format)(struct native_display *ndpy, + EGLNativePixmapType pix, + enum pipe_format *format); + /** + * Copy the contents of the resource to the pixmap's front-left attachment. + * This is used to implement eglCopyBuffers. Required unless no config has + * pixmap_bit set. + */ + boolean (*copy_to_pixmap)(struct native_display *ndpy, + EGLNativePixmapType pix, + struct pipe_resource *src); /** * Create a window surface. Required unless no config has window_bit set. @@ -219,6 +229,9 @@ struct native_event_handler { const char *name, int fd); struct pipe_screen *(*new_sw_screen)(struct native_display *ndpy, struct sw_winsys *ws); + + struct pipe_resource *(*lookup_egl_image)(struct native_display *ndpy, + void *egl_image); }; /** @@ -256,26 +269,29 @@ ndpy_uninit(struct native_display *ndpy) struct native_platform { const char *name; - void (*set_event_handler)(struct native_event_handler *handler); - struct native_display *(*create_display)(void *dpy, - boolean use_sw, - void *user_data); + /** + * Create the native display and usually establish a connection to the + * display server. + * + * No event should be generated at this stage. + */ + struct native_display *(*create_display)(void *dpy, boolean use_sw); }; const struct native_platform * -native_get_gdi_platform(void); +native_get_gdi_platform(const struct native_event_handler *event_handler); const struct native_platform * -native_get_x11_platform(void); +native_get_x11_platform(const struct native_event_handler *event_handler); const struct native_platform * -native_get_wayland_platform(void); +native_get_wayland_platform(const struct native_event_handler *event_handler); const struct native_platform * -native_get_drm_platform(void); +native_get_drm_platform(const struct native_event_handler *event_handler); const struct native_platform * -native_get_fbdev_platform(void); +native_get_fbdev_platform(const struct native_event_handler *event_handler); #ifdef __cplusplus } diff --git a/src/gallium/state_trackers/egl/common/native_buffer.h b/src/gallium/state_trackers/egl/common/native_buffer.h index 5c29ab97411..b8a66d17e12 100644 --- a/src/gallium/state_trackers/egl/common/native_buffer.h +++ b/src/gallium/state_trackers/egl/common/native_buffer.h @@ -30,30 +30,43 @@ #define _NATIVE_BUFFER_H_ #include "pipe/p_compiler.h" +#include "pipe/p_state.h" struct native_display; -struct pipe_resource; + +enum native_buffer_type { + NATIVE_BUFFER_DRM, + + NUM_NATIVE_BUFFERS +}; + +struct native_buffer { + enum native_buffer_type type; + + union { + struct { + struct pipe_resource templ; + unsigned name; /**< the name of the GEM object */ + unsigned handle; /**< the handle of the GEM object */ + unsigned stride; + } drm; + } u; +}; /** * Buffer interface of the native display. It allows native buffers to be * imported and exported. - * - * Just like a native window or a native pixmap, a native buffer is another - * native type. Its definition depends on the native display. - * - * For DRM platform, the type of a native buffer is struct winsys_handle. */ struct native_display_buffer { struct pipe_resource *(*import_buffer)(struct native_display *ndpy, - const struct pipe_resource *templ, - void *buf); + struct native_buffer *buf); /** * The resource must be creatred with PIPE_BIND_SHARED. */ boolean (*export_buffer)(struct native_display *ndpy, struct pipe_resource *res, - void *buf); + struct native_buffer *nbuf); }; #endif /* _NATIVE_BUFFER_H_ */ diff --git a/src/gallium/state_trackers/egl/common/native_helper.c b/src/gallium/state_trackers/egl/common/native_helper.c index ee18cb2025b..cca1e1c6295 100644 --- a/src/gallium/state_trackers/egl/common/native_helper.c +++ b/src/gallium/state_trackers/egl/common/native_helper.c @@ -282,9 +282,9 @@ resource_surface_copy_swap(struct resource_surface *rsurf, btex, 0, &src_box); ret = TRUE; - out_no_ftex: - pipe_resource_reference(&btex, NULL); out_no_btex: + pipe_resource_reference(&btex, NULL); + out_no_ftex: pipe_resource_reference(&ftex, NULL); return ret; @@ -367,3 +367,116 @@ resource_surface_wait(struct resource_surface *rsurf) { while (resource_surface_throttle(rsurf)); } + +boolean +native_display_copy_to_pixmap(struct native_display *ndpy, + EGLNativePixmapType pix, + struct pipe_resource *src) +{ + struct pipe_context *pipe; + struct native_surface *nsurf; + struct pipe_resource *dst; + struct pipe_resource *tmp[NUM_NATIVE_ATTACHMENTS]; + const enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT; + + pipe = ndpy_get_copy_context(ndpy); + if (!pipe) + return FALSE; + + nsurf = ndpy->create_pixmap_surface(ndpy, pix, NULL); + if (!nsurf) + return FALSE; + + /* get the texutre */ + tmp[natt] = NULL; + nsurf->validate(nsurf, 1 << natt, NULL, tmp, NULL, NULL); + dst = tmp[natt]; + + if (dst && dst->format == src->format) { + struct pipe_box src_box; + + u_box_origin_2d(src->width0, src->height0, &src_box); + pipe->resource_copy_region(pipe, dst, 0, 0, 0, 0, src, 0, &src_box); + pipe->flush(pipe, NULL); + nsurf->present(nsurf, natt, FALSE, 0); + } + + if (dst) + pipe_resource_reference(&dst, NULL); + + nsurf->destroy(nsurf); + + return TRUE; +} + +#include "state_tracker/drm_driver.h" +struct pipe_resource * +drm_display_import_native_buffer(struct native_display *ndpy, + struct native_buffer *nbuf) +{ + struct pipe_screen *screen = ndpy->screen; + struct pipe_resource *res = NULL; + + switch (nbuf->type) { + case NATIVE_BUFFER_DRM: + { + struct winsys_handle wsh; + + memset(&wsh, 0, sizeof(wsh)); + wsh.handle = nbuf->u.drm.name; + wsh.stride = nbuf->u.drm.stride; + + res = screen->resource_from_handle(screen, &nbuf->u.drm.templ, &wsh); + } + break; + default: + break; + } + + return res; +} + +boolean +drm_display_export_native_buffer(struct native_display *ndpy, + struct pipe_resource *res, + struct native_buffer *nbuf) +{ + struct pipe_screen *screen = ndpy->screen; + boolean ret = FALSE; + + switch (nbuf->type) { + case NATIVE_BUFFER_DRM: + { + struct winsys_handle wsh; + + if ((nbuf->u.drm.templ.bind & res->bind) != nbuf->u.drm.templ.bind) + break; + + memset(&wsh, 0, sizeof(wsh)); + wsh.type = DRM_API_HANDLE_TYPE_KMS; + if (!screen->resource_get_handle(screen, res, &wsh)) + break; + + nbuf->u.drm.handle = wsh.handle; + nbuf->u.drm.stride = wsh.stride; + + /* get the name of the GEM object */ + if (nbuf->u.drm.templ.bind & PIPE_BIND_SHARED) { + memset(&wsh, 0, sizeof(wsh)); + wsh.type = DRM_API_HANDLE_TYPE_SHARED; + if (!screen->resource_get_handle(screen, res, &wsh)) + break; + + nbuf->u.drm.name = wsh.handle; + } + + nbuf->u.drm.templ = *res; + ret = TRUE; + } + break; + default: + break; + } + + return ret; +} diff --git a/src/gallium/state_trackers/egl/common/native_helper.h b/src/gallium/state_trackers/egl/common/native_helper.h index 39564a04365..e8d91ccb02a 100644 --- a/src/gallium/state_trackers/egl/common/native_helper.h +++ b/src/gallium/state_trackers/egl/common/native_helper.h @@ -105,3 +105,17 @@ resource_surface_flush(struct resource_surface *rsurf, */ void resource_surface_wait(struct resource_surface *rsurf); + +boolean +native_display_copy_to_pixmap(struct native_display *ndpy, + EGLNativePixmapType pix, + struct pipe_resource *src); + +struct pipe_resource * +drm_display_import_native_buffer(struct native_display *ndpy, + struct native_buffer *nbuf); + +boolean +drm_display_export_native_buffer(struct native_display *ndpy, + struct pipe_resource *res, + struct native_buffer *nbuf); diff --git a/src/gallium/state_trackers/egl/drm/modeset.c b/src/gallium/state_trackers/egl/drm/modeset.c index 3fff9540905..73968d1343b 100644 --- a/src/gallium/state_trackers/egl/drm/modeset.c +++ b/src/gallium/state_trackers/egl/drm/modeset.c @@ -290,6 +290,42 @@ drm_display_create_surface(struct native_display *ndpy, return drmsurf; } +struct native_surface * +drm_display_create_surface_from_resource(struct native_display *ndpy, + struct pipe_resource *resource) +{ + struct drm_display *drmdpy = drm_display(ndpy); + struct drm_surface *drmsurf; + enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT; + + drmsurf = CALLOC_STRUCT(drm_surface); + if (!drmsurf) + return NULL; + + drmsurf->drmdpy = drmdpy; + drmsurf->color_format = resource->format; + drmsurf->width = resource->width0; + drmsurf->height = resource->height0; + drmsurf->have_pageflip = FALSE; + + drmsurf->rsurf = resource_surface_create(drmdpy->base.screen, + drmsurf->color_format, + PIPE_BIND_RENDER_TARGET | + PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT); + + resource_surface_import_resource(drmsurf->rsurf, natt, resource); + + drmsurf->base.destroy = drm_surface_destroy; + drmsurf->base.present = drm_surface_present; + drmsurf->base.validate = drm_surface_validate; + drmsurf->base.wait = drm_surface_wait; + + return &drmsurf->base; +} + + /** * Choose a CRTC that supports all given connectors. */ diff --git a/src/gallium/state_trackers/egl/drm/native_drm.c b/src/gallium/state_trackers/egl/drm/native_drm.c index 725fe28e4e2..c013769e57d 100644 --- a/src/gallium/state_trackers/egl/drm/native_drm.c +++ b/src/gallium/state_trackers/egl/drm/native_drm.c @@ -33,6 +33,8 @@ #include "native_drm.h" +#include "gbm_gallium_drmint.h" + #ifdef HAVE_LIBUDEV #include <libudev.h> #endif @@ -125,65 +127,26 @@ drm_display_destroy(struct native_display *ndpy) drm_display_fini_modeset(&drmdpy->base); + /* gbm owns screen */ + ndpy->screen = NULL; ndpy_uninit(ndpy); if (drmdpy->device_name) FREE(drmdpy->device_name); - if (drmdpy->fd >= 0) - close(drmdpy->fd); - - FREE(drmdpy); -} - -/** - * Initialize KMS and pipe screen. - */ -static boolean -drm_display_init_screen(struct native_display *ndpy) -{ - struct drm_display *drmdpy = drm_display(ndpy); - drmVersionPtr version; - - version = drmGetVersion(drmdpy->fd); - if (!version) { - _eglLog(_EGL_WARNING, "invalid fd %d", drmdpy->fd); - return FALSE; - } - - drmdpy->base.screen = - drmdpy->event_handler->new_drm_screen(&drmdpy->base, NULL, drmdpy->fd); - drmFreeVersion(version); - - if (!drmdpy->base.screen) { - _eglLog(_EGL_DEBUG, "failed to create DRM screen"); - return FALSE; + if (drmdpy->own_gbm) { + gbm_device_destroy(&drmdpy->gbmdrm->base.base); + if (drmdpy->fd >= 0) + close(drmdpy->fd); } - return TRUE; -} - -static struct pipe_resource * -drm_display_import_buffer(struct native_display *ndpy, - const struct pipe_resource *templ, - void *buf) -{ - return ndpy->screen->resource_from_handle(ndpy->screen, - templ, (struct winsys_handle *) buf); -} - -static boolean -drm_display_export_buffer(struct native_display *ndpy, - struct pipe_resource *res, - void *buf) -{ - return ndpy->screen->resource_get_handle(ndpy->screen, - res, (struct winsys_handle *) buf); + FREE(drmdpy); } static struct native_display_buffer drm_display_buffer = { - drm_display_import_buffer, - drm_display_export_buffer + /* use the helpers */ + drm_display_import_native_buffer, + drm_display_export_native_buffer }; static int @@ -281,9 +244,25 @@ static struct native_display_wayland_bufmgr drm_display_wayland_bufmgr = { #endif /* HAVE_WAYLAND_BACKEND */ +static struct native_surface * +drm_create_pixmap_surface(struct native_display *ndpy, + EGLNativePixmapType pix, + const struct native_config *nconf) +{ + struct gbm_gallium_drm_bo *bo = (void *) pix; + + return drm_display_create_surface_from_resource(ndpy, bo->resource); +} + +static boolean +drm_display_init_screen(struct native_display *ndpy) +{ + return TRUE; +} + static struct native_display * -drm_create_display(int fd, struct native_event_handler *event_handler, - void *user_data) +drm_create_display(struct gbm_gallium_drm_device *gbmdrm, int own_gbm, + const struct native_event_handler *event_handler) { struct drm_display *drmdpy; @@ -291,20 +270,26 @@ drm_create_display(int fd, struct native_event_handler *event_handler, if (!drmdpy) return NULL; - drmdpy->fd = fd; - drmdpy->device_name = drm_get_device_name(fd); + drmdpy->gbmdrm = gbmdrm; + drmdpy->own_gbm = own_gbm; + drmdpy->fd = gbmdrm->base.base.fd; + drmdpy->device_name = drm_get_device_name(drmdpy->fd); + + gbmdrm->lookup_egl_image = (struct pipe_resource *(*)(void *, void *)) + event_handler->lookup_egl_image; + gbmdrm->lookup_egl_image_data = &drmdpy->base; + drmdpy->event_handler = event_handler; - drmdpy->base.user_data = user_data; - if (!drm_display_init_screen(&drmdpy->base)) { - drm_display_destroy(&drmdpy->base); - return NULL; - } + drmdpy->base.screen = gbmdrm->screen; + drmdpy->base.init_screen = drm_display_init_screen; drmdpy->base.destroy = drm_display_destroy; drmdpy->base.get_param = drm_display_get_param; drmdpy->base.get_configs = drm_display_get_configs; + drmdpy->base.create_pixmap_surface = drm_create_pixmap_surface; + drmdpy->base.buffer = &drm_display_buffer; #ifdef HAVE_WAYLAND_BACKEND if (drmdpy->device_name) @@ -315,39 +300,47 @@ drm_create_display(int fd, struct native_event_handler *event_handler, return &drmdpy->base; } -static struct native_event_handler *drm_event_handler; - -static void -native_set_event_handler(struct native_event_handler *event_handler) -{ - drm_event_handler = event_handler; -} +static const struct native_event_handler *drm_event_handler; static struct native_display * -native_create_display(void *dpy, boolean use_sw, void *user_data) +native_create_display(void *dpy, boolean use_sw) { + struct gbm_gallium_drm_device *gbm; int fd; + int own_gbm = 0; - if (dpy) { - fd = dup((int) pointer_to_intptr(dpy)); - } - else { + 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 (fd < 0) + + 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) { + if (own_gbm) + gbm_device_destroy(&gbm->base.base); return NULL; + } - return drm_create_display(fd, drm_event_handler, user_data); + return drm_create_display(gbm, own_gbm, drm_event_handler); } static const struct native_platform drm_platform = { "DRM", /* name */ - native_set_event_handler, native_create_display }; const struct native_platform * -native_get_drm_platform(void) +native_get_drm_platform(const struct native_event_handler *event_handler) { + drm_event_handler = event_handler; return &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 41cdc4f9d04..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; @@ -50,8 +52,10 @@ struct drm_surface; struct drm_display { struct native_display base; - struct native_event_handler *event_handler; + 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; @@ -154,4 +158,8 @@ drm_display_init_modeset(struct native_display *ndpy); void drm_display_fini_modeset(struct native_display *ndpy); +struct native_surface * +drm_display_create_surface_from_resource(struct native_display *ndpy, + struct pipe_resource *resource); + #endif /* _NATIVE_DRM_H_ */ diff --git a/src/gallium/state_trackers/egl/fbdev/native_fbdev.c b/src/gallium/state_trackers/egl/fbdev/native_fbdev.c index e2fde00e975..6772d379f73 100644 --- a/src/gallium/state_trackers/egl/fbdev/native_fbdev.c +++ b/src/gallium/state_trackers/egl/fbdev/native_fbdev.c @@ -26,6 +26,21 @@ * Chia-I Wu <[email protected]> */ +/** + * Considering fbdev as an in-kernel window system, + * + * - opening a device opens a connection + * - there is only one window: the framebuffer + * - fb_var_screeninfo decides window position, size, and even color format + * - there is no pixmap + * + * Now EGL is built on top of this window system. So we should have + * + * - the fd as the handle of the native display + * - reject all but one native window: NULL + * - no pixmap support + */ + #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> @@ -45,16 +60,13 @@ struct fbdev_display { struct native_display base; int fd; - struct native_event_handler *event_handler; + const struct native_event_handler *event_handler; struct fb_fix_screeninfo finfo; - struct fb_var_screeninfo vinfo; - + struct fb_var_screeninfo config_vinfo; struct native_config config; - struct native_connector connector; - struct native_mode mode; - struct fbdev_surface *current_surface; + boolean assume_fixed_vinfo; }; struct fbdev_surface { @@ -66,7 +78,7 @@ struct fbdev_surface { unsigned int sequence_number; - boolean is_current; + struct fbdev_sw_drawable drawable; }; static INLINE struct fbdev_display * @@ -103,38 +115,70 @@ fbdev_surface_validate(struct native_surface *nsurf, uint attachment_mask, return TRUE; } -static boolean -fbdev_surface_flush_frontbuffer(struct native_surface *nsurf) +static enum pipe_format +vinfo_to_format(const struct fb_var_screeninfo *vinfo) { - struct fbdev_surface *fbsurf = fbdev_surface(nsurf); + enum pipe_format format = PIPE_FORMAT_NONE; - if (!fbsurf->is_current) - return TRUE; + /* should also check channel offsets... */ + switch (vinfo->bits_per_pixel) { + case 32: + if (vinfo->red.length == 8 && + vinfo->green.length == 8 && + vinfo->blue.length == 8) { + format = (vinfo->transp.length == 8) ? + PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM; + } + break; + case 16: + if (vinfo->red.length == 5 && + vinfo->green.length == 6 && + vinfo->blue.length == 5 && + vinfo->transp.length == 0) + format = PIPE_FORMAT_B5G6R5_UNORM; + break; + default: + break; + } - return resource_surface_present(fbsurf->rsurf, - NATIVE_ATTACHMENT_FRONT_LEFT, NULL); + return format; } static boolean -fbdev_surface_swap_buffers(struct native_surface *nsurf) +fbdev_surface_update_drawable(struct native_surface *nsurf, + const struct fb_var_screeninfo *vinfo) { struct fbdev_surface *fbsurf = fbdev_surface(nsurf); - struct fbdev_display *fbdpy = fbsurf->fbdpy; - boolean ret = TRUE; - - if (fbsurf->is_current) { - ret = resource_surface_present(fbsurf->rsurf, - NATIVE_ATTACHMENT_BACK_LEFT, NULL); + unsigned x, y, width, height; + + x = vinfo->xoffset; + y = vinfo->yoffset; + width = MIN2(vinfo->xres, fbsurf->width); + height = MIN2(vinfo->yres, fbsurf->height); + + /* sanitize the values */ + if (x + width > vinfo->xres_virtual) { + if (x > vinfo->xres_virtual) + width = 0; + else + width = vinfo->xres_virtual - x; + } + if (y + height > vinfo->yres_virtual) { + if (y > vinfo->yres_virtual) + height = 0; + else + height = vinfo->yres_virtual - y; } - resource_surface_swap_buffers(fbsurf->rsurf, - NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE); - /* the front/back textures are swapped */ - fbsurf->sequence_number++; - fbdpy->event_handler->invalid_surface(&fbdpy->base, - &fbsurf->base, fbsurf->sequence_number); + fbsurf->drawable.format = vinfo_to_format(vinfo); + fbsurf->drawable.x = vinfo->xoffset; + fbsurf->drawable.y = vinfo->yoffset; + fbsurf->drawable.width = vinfo->xres; + fbsurf->drawable.height = vinfo->yres; - return ret; + return (fbsurf->drawable.format != PIPE_FORMAT_NONE && + fbsurf->drawable.width && + fbsurf->drawable.height); } static boolean @@ -143,21 +187,43 @@ fbdev_surface_present(struct native_surface *nsurf, boolean preserve, uint swap_interval) { - boolean ret; + struct fbdev_surface *fbsurf = fbdev_surface(nsurf); + struct fbdev_display *fbdpy = fbsurf->fbdpy; + boolean ret = FALSE; - if (preserve || swap_interval) + if (swap_interval) + return FALSE; + if (natt != NATIVE_ATTACHMENT_BACK_LEFT) return FALSE; - switch (natt) { - case NATIVE_ATTACHMENT_FRONT_LEFT: - ret = fbdev_surface_flush_frontbuffer(nsurf); - break; - case NATIVE_ATTACHMENT_BACK_LEFT: - ret = fbdev_surface_swap_buffers(nsurf); - break; - default: - ret = FALSE; - break; + if (!fbdpy->assume_fixed_vinfo) { + struct fb_var_screeninfo vinfo; + + memset(&vinfo, 0, sizeof(vinfo)); + if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo)) + return FALSE; + + /* present the surface */ + if (fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) { + ret = resource_surface_present(fbsurf->rsurf, + natt, (void *) &fbsurf->drawable); + } + + fbsurf->width = vinfo.xres; + fbsurf->height = vinfo.yres; + + if (resource_surface_set_size(fbsurf->rsurf, + fbsurf->width, fbsurf->height)) { + /* surface resized */ + fbsurf->sequence_number++; + fbdpy->event_handler->invalid_surface(&fbdpy->base, + &fbsurf->base, fbsurf->sequence_number); + } + } + else { + /* the drawable never changes */ + ret = resource_surface_present(fbsurf->rsurf, + natt, (void *) &fbsurf->drawable); } return ret; @@ -179,26 +245,48 @@ fbdev_surface_destroy(struct native_surface *nsurf) } static struct native_surface * -fbdev_display_create_scanout_surface(struct native_display *ndpy, - const struct native_config *nconf, - uint width, uint height) +fbdev_display_create_window_surface(struct native_display *ndpy, + EGLNativeWindowType win, + const struct native_config *nconf) { struct fbdev_display *fbdpy = fbdev_display(ndpy); struct fbdev_surface *fbsurf; + struct fb_var_screeninfo vinfo; + + /* there is only one native window: NULL */ + if (win) + return NULL; fbsurf = CALLOC_STRUCT(fbdev_surface); if (!fbsurf) return NULL; fbsurf->fbdpy = fbdpy; - fbsurf->width = width; - fbsurf->height = height; + + /* get current vinfo */ + if (fbdpy->assume_fixed_vinfo) { + vinfo = fbdpy->config_vinfo; + } + else { + memset(&vinfo, 0, sizeof(vinfo)); + if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo)) { + FREE(fbsurf); + return NULL; + } + } + + fbsurf->width = vinfo.xres; + fbsurf->height = vinfo.yres; + + if (!fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) { + FREE(fbsurf); + return NULL; + } fbsurf->rsurf = resource_surface_create(fbdpy->base.screen, nconf->color_format, PIPE_BIND_RENDER_TARGET | - PIPE_BIND_DISPLAY_TARGET | - PIPE_BIND_SCANOUT); + PIPE_BIND_DISPLAY_TARGET); if (!fbsurf->rsurf) { FREE(fbsurf); return NULL; @@ -214,42 +302,43 @@ fbdev_display_create_scanout_surface(struct native_display *ndpy, return &fbsurf->base; } +static struct native_surface * +fbdev_display_create_scanout_surface(struct native_display *ndpy, + const struct native_config *nconf, + uint width, uint height) +{ + return fbdev_display_create_window_surface(ndpy, + (EGLNativeWindowType) NULL, nconf); +} + static boolean fbdev_display_program(struct native_display *ndpy, int crtc_idx, struct native_surface *nsurf, uint x, uint y, const struct native_connector **nconns, int num_nconns, const struct native_mode *nmode) { - struct fbdev_display *fbdpy = fbdev_display(ndpy); - struct fbdev_surface *fbsurf = fbdev_surface(nsurf); - - if (x || y) - return FALSE; - - if (fbdpy->current_surface) { - if (fbdpy->current_surface == fbsurf) - return TRUE; - fbdpy->current_surface->is_current = FALSE; - } - - if (fbsurf) - fbsurf->is_current = TRUE; - fbdpy->current_surface = fbsurf; - return TRUE; } static const struct native_mode ** fbdev_display_get_modes(struct native_display *ndpy, - const struct native_connector *nconn, - int *num_modes) + const struct native_connector *nconn, + int *num_modes) { - struct fbdev_display *fbdpy = fbdev_display(ndpy); + static struct native_mode mode; const struct native_mode **modes; + if (!mode.desc) { + struct fbdev_display *fbdpy = fbdev_display(ndpy); + mode.desc = "Current Mode"; + mode.width = fbdpy->config_vinfo.xres; + mode.height = fbdpy->config_vinfo.yres; + mode.refresh_rate = 60 * 1000; /* dummy */ + } + modes = MALLOC(sizeof(*modes)); if (modes) { - modes[0] = &fbdpy->mode; + modes[0] = &mode; if (num_modes) *num_modes = 1; } @@ -261,12 +350,12 @@ static const struct native_connector ** fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors, int *num_crtc) { - struct fbdev_display *fbdpy = fbdev_display(ndpy); + static struct native_connector connector; const struct native_connector **connectors; connectors = MALLOC(sizeof(*connectors)); if (connectors) { - connectors[0] = &fbdpy->connector; + connectors[0] = &connector; if (num_connectors) *num_connectors = 1; } @@ -274,7 +363,8 @@ fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors, return connectors; } -static struct native_display_modeset fbdev_display_modeset = { +/* remove modeset support one day! */ +static const struct native_display_modeset fbdev_display_modeset = { .get_connectors = fbdev_display_get_connectors, .get_modes = fbdev_display_get_modes, .create_scanout_surface = fbdev_display_create_scanout_surface, @@ -304,8 +394,10 @@ fbdev_display_get_param(struct native_display *ndpy, int val; switch (param) { - case NATIVE_PARAM_USE_NATIVE_BUFFER: case NATIVE_PARAM_PRESERVE_BUFFER: + val = 1; + break; + case NATIVE_PARAM_USE_NATIVE_BUFFER: case NATIVE_PARAM_MAX_SWAP_INTERVAL: default: val = 0; @@ -326,114 +418,55 @@ fbdev_display_destroy(struct native_display *ndpy) } static boolean -fbdev_display_init_modes(struct native_display *ndpy) +fbdev_display_init_screen(struct native_display *ndpy) { struct fbdev_display *fbdpy = fbdev_display(ndpy); - struct native_mode *nmode = &fbdpy->mode; - - nmode->desc = "Current Mode"; - nmode->width = fbdpy->vinfo.xres; - nmode->height = fbdpy->vinfo.yres; - nmode->refresh_rate = 60 * 1000; /* dummy */ - - return TRUE; -} - -static boolean -fbdev_display_init_connectors(struct native_display *ndpy) -{ - return TRUE; -} + struct sw_winsys *ws; -static enum pipe_format -vinfo_to_format(const struct fb_var_screeninfo *vinfo) -{ - enum pipe_format format = PIPE_FORMAT_NONE; + ws = fbdev_create_sw_winsys(fbdpy->fd); + if (!ws) + return FALSE; - switch (vinfo->bits_per_pixel) { - case 32: - if (vinfo->red.length == 8 && - vinfo->green.length == 8 && - vinfo->blue.length == 8) { - format = (vinfo->transp.length == 8) ? - PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM; - } - break; - case 16: - if (vinfo->red.length == 5 && - vinfo->green.length == 6 && - vinfo->blue.length == 5 && - vinfo->transp.length == 0) - format = PIPE_FORMAT_B5G6R5_UNORM; - break; - default: - break; + fbdpy->base.screen = fbdpy->event_handler->new_sw_screen(&fbdpy->base, ws); + if (!fbdpy->base.screen) { + if (ws->destroy) + ws->destroy(ws); + return FALSE; } - return format; -} - -static boolean -fbdev_display_init_configs(struct native_display *ndpy) -{ - struct fbdev_display *fbdpy = fbdev_display(ndpy); - struct native_config *nconf = &fbdpy->config; - - nconf->color_format = vinfo_to_format(&fbdpy->vinfo); - if (nconf->color_format == PIPE_FORMAT_NONE) + if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen, + fbdpy->config.color_format, PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET)) { + fbdpy->base.screen->destroy(fbdpy->base.screen); + fbdpy->base.screen = NULL; return FALSE; - - nconf->buffer_mask = - (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | - (1 << NATIVE_ATTACHMENT_BACK_LEFT); - - nconf->scanout_bit = TRUE; + } return TRUE; } static boolean -fbdev_display_init(struct native_display *ndpy) +fbdev_display_init_config(struct native_display *ndpy) { struct fbdev_display *fbdpy = fbdev_display(ndpy); - struct sw_winsys *ws; - - if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo)) - return FALSE; + struct native_config *nconf = &fbdpy->config; - if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo)) + if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->config_vinfo)) return FALSE; - if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR || - fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS) + nconf->color_format = vinfo_to_format(&fbdpy->config_vinfo); + if (nconf->color_format == PIPE_FORMAT_NONE) return FALSE; - if (!fbdev_display_init_configs(&fbdpy->base) || - !fbdev_display_init_connectors(&fbdpy->base) || - !fbdev_display_init_modes(&fbdpy->base)) - return FALSE; + nconf->buffer_mask = (1 << NATIVE_ATTACHMENT_BACK_LEFT); - ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format); - if (ws) { - fbdpy->base.screen = - fbdpy->event_handler->new_sw_screen(&fbdpy->base, ws); - } + nconf->window_bit = TRUE; - if (fbdpy->base.screen) { - if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen, - fbdpy->config.color_format, PIPE_TEXTURE_2D, 0, - PIPE_BIND_RENDER_TARGET)) { - fbdpy->base.screen->destroy(fbdpy->base.screen); - fbdpy->base.screen = NULL; - } - } - - return (fbdpy->base.screen != NULL); + return TRUE; } static struct native_display * -fbdev_display_create(int fd, struct native_event_handler *event_handler, - void *user_data) +fbdev_display_create(int fd, const struct native_event_handler *event_handler) { struct fbdev_display *fbdpy; @@ -443,32 +476,41 @@ fbdev_display_create(int fd, struct native_event_handler *event_handler, fbdpy->fd = fd; fbdpy->event_handler = event_handler; - fbdpy->base.user_data = user_data; - if (!fbdev_display_init(&fbdpy->base)) { - FREE(fbdpy); - return NULL; - } + if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo)) + goto fail; + + if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR || + fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS) + goto fail; + + if (!fbdev_display_init_config(&fbdpy->base)) + goto fail; + fbdpy->assume_fixed_vinfo = TRUE; + + fbdpy->base.init_screen = fbdev_display_init_screen; fbdpy->base.destroy = fbdev_display_destroy; fbdpy->base.get_param = fbdev_display_get_param; fbdpy->base.get_configs = fbdev_display_get_configs; + fbdpy->base.create_window_surface = fbdev_display_create_window_surface; + + /* we'd like to remove modeset support one day */ + fbdpy->config.scanout_bit = TRUE; fbdpy->base.modeset = &fbdev_display_modeset; return &fbdpy->base; -} -static struct native_event_handler *fbdev_event_handler; - -static void -native_set_event_handler(struct native_event_handler *event_handler) -{ - fbdev_event_handler = event_handler; +fail: + FREE(fbdpy); + return NULL; } +static const struct native_event_handler *fbdev_event_handler; + static struct native_display * -native_create_display(void *dpy, boolean use_sw, void *user_data) +native_create_display(void *dpy, boolean use_sw) { struct native_display *ndpy; int fd; @@ -483,7 +525,7 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) if (fd < 0) return NULL; - ndpy = fbdev_display_create(fd, fbdev_event_handler, user_data); + ndpy = fbdev_display_create(fd, fbdev_event_handler); if (!ndpy) close(fd); @@ -492,12 +534,12 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) static const struct native_platform fbdev_platform = { "FBDEV", /* name */ - native_set_event_handler, native_create_display }; const struct native_platform * -native_get_fbdev_platform(void) +native_get_fbdev_platform(const struct native_event_handler *event_handler) { + fbdev_event_handler = event_handler; return &fbdev_platform; } diff --git a/src/gallium/state_trackers/egl/gdi/native_gdi.c b/src/gallium/state_trackers/egl/gdi/native_gdi.c index 5d0045f92ee..6bf0d4e4668 100644 --- a/src/gallium/state_trackers/egl/gdi/native_gdi.c +++ b/src/gallium/state_trackers/egl/gdi/native_gdi.c @@ -41,7 +41,7 @@ struct gdi_display { struct native_display base; HDC hDC; - struct native_event_handler *event_handler; + const struct native_event_handler *event_handler; struct native_config *configs; int num_configs; @@ -368,35 +368,39 @@ gdi_display_destroy(struct native_display *ndpy) FREE(gdpy); } -static struct native_display * -gdi_create_display(HDC hDC, struct native_event_handler *event_handler, - void *user_data) +static boolean +gdi_display_init_screen(struct native_display *ndpy) { - struct gdi_display *gdpy; + struct gdi_display *gdpy = gdi_display(ndpy); struct sw_winsys *winsys; - gdpy = CALLOC_STRUCT(gdi_display); - if (!gdpy) - return NULL; - - gdpy->hDC = hDC; - gdpy->event_handler = event_handler; - gdpy->base.user_data = user_data; - winsys = gdi_create_sw_winsys(); - if (!winsys) { - FREE(gdpy); - return NULL; - } + if (!winsys) + return FALSE; gdpy->base.screen = gdpy->event_handler->new_sw_screen(&gdpy->base, winsys); if (!gdpy->base.screen) { if (winsys->destroy) winsys->destroy(winsys); - FREE(gdpy); - return NULL; + return FALSE; } + return TRUE; +} + +static struct native_display * +gdi_create_display(HDC hDC, const struct native_event_handler *event_handler) +{ + struct gdi_display *gdpy; + + gdpy = CALLOC_STRUCT(gdi_display); + if (!gdpy) + return NULL; + + gdpy->hDC = hDC; + gdpy->event_handler = event_handler; + + gdpy->base.init_screen = gdi_display_init_screen; gdpy->base.destroy = gdi_display_destroy; gdpy->base.get_param = gdi_display_get_param; @@ -406,28 +410,22 @@ gdi_create_display(HDC hDC, struct native_event_handler *event_handler, return &gdpy->base; } -static struct native_event_handler *gdi_event_handler; - -static void -native_set_event_handler(struct native_event_handler *event_handler) -{ - gdi_event_handler = event_handler; -} +static const struct native_event_handler *gdi_event_handler; static struct native_display * -native_create_display(void *dpy, boolean use_sw, void *user_data) +native_create_display(void *dpy, boolean use_sw) { - return gdi_create_display((HDC) dpy, gdi_event_handler, user_data); + return gdi_create_display((HDC) dpy, gdi_event_handler); } static const struct native_platform gdi_platform = { "GDI", /* name */ - native_set_event_handler, native_create_display }; const struct native_platform * -native_get_gdi_platform(void) +native_get_gdi_platform(const struct native_event_handler *event_handler) { + gdi_event_handler = event_handler; return &gdi_platform; } diff --git a/src/gallium/state_trackers/egl/wayland/native_drm.c b/src/gallium/state_trackers/egl/wayland/native_drm.c index a9fd30319eb..e34b24b58b1 100644 --- a/src/gallium/state_trackers/egl/wayland/native_drm.c +++ b/src/gallium/state_trackers/egl/wayland/native_drm.c @@ -51,7 +51,7 @@ struct wayland_drm_display { struct wayland_display base; - struct native_event_handler *event_handler; + const struct native_event_handler *event_handler; struct wl_drm *wl_drm; struct wl_drm *wl_server_drm; /* for EGL_WL_bind_wayland_display */ @@ -212,27 +212,10 @@ wayland_drm_display_init_screen(struct native_display *ndpy) return TRUE; } -static struct pipe_resource * -wayland_drm_display_import_buffer(struct native_display *ndpy, - const struct pipe_resource *templ, - void *buf) -{ - return ndpy->screen->resource_from_handle(ndpy->screen, - templ, (struct winsys_handle *) buf); -} - -static boolean -wayland_drm_display_export_buffer(struct native_display *ndpy, - struct pipe_resource *res, - void *buf) -{ - return ndpy->screen->resource_get_handle(ndpy->screen, - res, (struct winsys_handle *) buf); -} - static struct native_display_buffer wayland_drm_display_buffer = { - wayland_drm_display_import_buffer, - wayland_drm_display_export_buffer + /* use the helpers */ + drm_display_import_native_buffer, + drm_display_export_native_buffer }; static int @@ -302,8 +285,7 @@ static struct native_display_wayland_bufmgr wayland_drm_display_wayland_bufmgr = struct wayland_display * wayland_create_drm_display(struct wl_display *dpy, - struct native_event_handler *event_handler, - void *user_data) + const struct native_event_handler *event_handler) { struct wayland_drm_display *drmdpy; @@ -312,7 +294,6 @@ wayland_create_drm_display(struct wl_display *dpy, return NULL; drmdpy->event_handler = event_handler; - drmdpy->base.base.user_data = user_data; drmdpy->base.dpy = dpy; if (!drmdpy->base.dpy) { @@ -320,10 +301,7 @@ wayland_create_drm_display(struct wl_display *dpy, return NULL; } - if (!wayland_drm_display_init_screen(&drmdpy->base.base)) { - wayland_drm_display_destroy(&drmdpy->base.base); - return NULL; - } + drmdpy->base.base.init_screen = wayland_drm_display_init_screen; drmdpy->base.base.destroy = wayland_drm_display_destroy; drmdpy->base.base.buffer = &wayland_drm_display_buffer; drmdpy->base.base.wayland_bufmgr = &wayland_drm_display_wayland_bufmgr; diff --git a/src/gallium/state_trackers/egl/wayland/native_shm.c b/src/gallium/state_trackers/egl/wayland/native_shm.c index 8614a761abf..1c0799528fe 100644 --- a/src/gallium/state_trackers/egl/wayland/native_shm.c +++ b/src/gallium/state_trackers/egl/wayland/native_shm.c @@ -47,7 +47,7 @@ struct wayland_shm_display { struct wayland_display base; - struct native_event_handler *event_handler; + const struct native_event_handler *event_handler; struct wl_shm *wl_shm; }; @@ -144,8 +144,7 @@ wayland_shm_display_init_screen(struct native_display *ndpy) struct wayland_display * wayland_create_shm_display(struct wl_display *dpy, - struct native_event_handler *event_handler, - void *user_data) + const struct native_event_handler *event_handler) { struct wayland_shm_display *shmdpy; @@ -154,7 +153,6 @@ wayland_create_shm_display(struct wl_display *dpy, return NULL; shmdpy->event_handler = event_handler; - shmdpy->base.base.user_data = user_data; shmdpy->base.dpy = dpy; if (!shmdpy->base.dpy) { @@ -162,11 +160,7 @@ wayland_create_shm_display(struct wl_display *dpy, return NULL; } - if (!wayland_shm_display_init_screen(&shmdpy->base.base)) { - wayland_shm_display_destroy(&shmdpy->base.base); - return NULL; - } - + shmdpy->base.base.init_screen = wayland_shm_display_init_screen; shmdpy->base.base.destroy = wayland_shm_display_destroy; shmdpy->base.create_buffer = wayland_create_shm_buffer; diff --git a/src/gallium/state_trackers/egl/wayland/native_wayland.c b/src/gallium/state_trackers/egl/wayland/native_wayland.c index 3d1bb6ff8b1..544d4be215a 100644 --- a/src/gallium/state_trackers/egl/wayland/native_wayland.c +++ b/src/gallium/state_trackers/egl/wayland/native_wayland.c @@ -35,7 +35,7 @@ #include "native_wayland.h" -static struct native_event_handler *wayland_event_handler; +static const struct native_event_handler *wayland_event_handler; static void sync_callback(void *data) @@ -114,11 +114,12 @@ wayland_display_get_param(struct native_display *ndpy, } static boolean -wayland_display_is_pixmap_supported(struct native_display *ndpy, - EGLNativePixmapType pix, - const struct native_config *nconf) +wayland_display_get_pixmap_format(struct native_display *ndpy, + EGLNativePixmapType pix, + enum pipe_format *format) { /* all wl_egl_pixmaps are supported */ + *format = PIPE_FORMAT_NONE; return TRUE; } @@ -195,13 +196,11 @@ wayland_window_surface_handle_resize(struct wayland_surface *surface) wl_buffer_destroy(surface->buffer[i]); surface->buffer[i] = NULL; } + + surface->dx = surface->win->dx; + surface->dy = surface->win->dy; } pipe_resource_reference(&front_resource, NULL); - - surface->dx = surface->win->dx; - surface->dy = surface->win->dy; - surface->win->dx = 0; - surface->win->dy = 0; } static boolean @@ -449,14 +448,8 @@ wayland_create_window_surface(struct native_display *ndpy, return &surface->base; } -static void -native_set_event_handler(struct native_event_handler *event_handler) -{ - wayland_event_handler = event_handler; -} - static struct native_display * -native_create_display(void *dpy, boolean use_sw, void *user_data) +native_create_display(void *dpy, boolean use_sw) { struct wayland_display *display = NULL; boolean own_dpy = FALSE; @@ -473,12 +466,10 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) if (use_sw) { _eglLog(_EGL_INFO, "use software fallback"); display = wayland_create_shm_display((struct wl_display *) dpy, - wayland_event_handler, - user_data); + wayland_event_handler); } else { display = wayland_create_drm_display((struct wl_display *) dpy, - wayland_event_handler, - user_data); + wayland_event_handler); } if (!display) @@ -486,7 +477,8 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) display->base.get_param = wayland_display_get_param; display->base.get_configs = wayland_display_get_configs; - display->base.is_pixmap_supported = wayland_display_is_pixmap_supported; + display->base.get_pixmap_format = wayland_display_get_pixmap_format; + display->base.copy_to_pixmap = native_display_copy_to_pixmap; display->base.create_window_surface = wayland_create_window_surface; display->base.create_pixmap_surface = wayland_create_pixmap_surface; @@ -497,13 +489,13 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) static const struct native_platform wayland_platform = { "wayland", /* name */ - native_set_event_handler, native_create_display }; const struct native_platform * -native_get_wayland_platform(void) +native_get_wayland_platform(const struct native_event_handler *event_handler) { + wayland_event_handler = event_handler; return &wayland_platform; } diff --git a/src/gallium/state_trackers/egl/wayland/native_wayland.h b/src/gallium/state_trackers/egl/wayland/native_wayland.h index 81c7a8b4840..5390f2f08c9 100644 --- a/src/gallium/state_trackers/egl/wayland/native_wayland.h +++ b/src/gallium/state_trackers/egl/wayland/native_wayland.h @@ -103,11 +103,10 @@ wayland_config(const struct native_config *nconf) struct wayland_display * wayland_create_shm_display(struct wl_display *display, - struct native_event_handler *event_handler, - void *user_data); + const struct native_event_handler *event_handler); + struct wayland_display * wayland_create_drm_display(struct wl_display *display, - struct native_event_handler *event_handler, - void *user_data); + const struct native_event_handler *event_handler); #endif /* _NATIVE_WAYLAND_H_ */ diff --git a/src/gallium/state_trackers/egl/x11/native_dri2.c b/src/gallium/state_trackers/egl/x11/native_dri2.c index a56d43428fc..4b8be7bc759 100644 --- a/src/gallium/state_trackers/egl/x11/native_dri2.c +++ b/src/gallium/state_trackers/egl/x11/native_dri2.c @@ -38,6 +38,7 @@ #include "native_x11.h" #include "x11_screen.h" +#include "common/native_helper.h" #ifdef HAVE_WAYLAND_BACKEND #include "common/native_wayland_drm_bufmgr_helper.h" #endif @@ -49,7 +50,7 @@ struct dri2_display { Display *dpy; boolean own_dpy; - struct native_event_handler *event_handler; + const struct native_event_handler *event_handler; struct x11_screen *xscr; int xscr_number; @@ -682,18 +683,30 @@ dri2_display_get_configs(struct native_display *ndpy, int *num_configs) } static boolean -dri2_display_is_pixmap_supported(struct native_display *ndpy, - EGLNativePixmapType pix, - const struct native_config *nconf) +dri2_display_get_pixmap_format(struct native_display *ndpy, + EGLNativePixmapType pix, + enum pipe_format *format) { struct dri2_display *dri2dpy = dri2_display(ndpy); - uint depth, nconf_depth; + boolean ret = EGL_TRUE; + uint depth; depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix); - nconf_depth = util_format_get_blocksizebits(nconf->color_format); + switch (depth) { + case 32: + case 24: + *format = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + case 16: + *format = PIPE_FORMAT_B5G6R5_UNORM; + break; + default: + *format = PIPE_FORMAT_NONE; + ret = EGL_FALSE; + break; + } - /* simple depth match for now */ - return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth)); + return ret; } static int @@ -870,8 +883,7 @@ static struct native_display_wayland_bufmgr dri2_display_wayland_bufmgr = { struct native_display * x11_create_dri2_display(Display *dpy, - struct native_event_handler *event_handler, - void *user_data) + const struct native_event_handler *event_handler) { struct dri2_display *dri2dpy; @@ -880,7 +892,6 @@ x11_create_dri2_display(Display *dpy, return NULL; dri2dpy->event_handler = event_handler; - dri2dpy->base.user_data = user_data; dri2dpy->dpy = dpy; if (!dri2dpy->dpy) { @@ -899,11 +910,6 @@ x11_create_dri2_display(Display *dpy, return NULL; } - if (!dri2_display_init_screen(&dri2dpy->base)) { - dri2_display_destroy(&dri2dpy->base); - return NULL; - } - dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash, dri2_display_hash_table_compare); if (!dri2dpy->surfaces) { @@ -911,10 +917,12 @@ x11_create_dri2_display(Display *dpy, return NULL; } + dri2dpy->base.init_screen = dri2_display_init_screen; dri2dpy->base.destroy = dri2_display_destroy; dri2dpy->base.get_param = dri2_display_get_param; dri2dpy->base.get_configs = dri2_display_get_configs; - dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported; + dri2dpy->base.get_pixmap_format = dri2_display_get_pixmap_format; + dri2dpy->base.copy_to_pixmap = native_display_copy_to_pixmap; dri2dpy->base.create_window_surface = dri2_display_create_window_surface; dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface; #ifdef HAVE_WAYLAND_BACKEND @@ -928,8 +936,7 @@ x11_create_dri2_display(Display *dpy, struct native_display * x11_create_dri2_display(Display *dpy, - struct native_event_handler *event_handler, - void *user_data) + const struct native_event_handler *event_handler) { return NULL; } diff --git a/src/gallium/state_trackers/egl/x11/native_x11.c b/src/gallium/state_trackers/egl/x11/native_x11.c index a0bcad4c734..ef038b52152 100644 --- a/src/gallium/state_trackers/egl/x11/native_x11.c +++ b/src/gallium/state_trackers/egl/x11/native_x11.c @@ -30,16 +30,10 @@ #include "native_x11.h" -static struct native_event_handler *x11_event_handler; - -static void -native_set_event_handler(struct native_event_handler *event_handler) -{ - x11_event_handler = event_handler; -} +static const struct native_event_handler *x11_event_handler; static struct native_display * -native_create_display(void *dpy, boolean use_sw, void *user_data) +native_create_display(void *dpy, boolean use_sw) { struct native_display *ndpy = NULL; boolean force_sw; @@ -48,12 +42,10 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) if (force_sw || use_sw) { _eglLog(_EGL_INFO, "use software fallback"); - ndpy = x11_create_ximage_display((Display *) dpy, - x11_event_handler, user_data); + ndpy = x11_create_ximage_display((Display *) dpy, x11_event_handler); } else { - ndpy = x11_create_dri2_display((Display *) dpy, - x11_event_handler, user_data); + ndpy = x11_create_dri2_display((Display *) dpy, x11_event_handler); } return ndpy; @@ -61,12 +53,12 @@ native_create_display(void *dpy, boolean use_sw, void *user_data) static const struct native_platform x11_platform = { "X11", /* name */ - native_set_event_handler, native_create_display }; const struct native_platform * -native_get_x11_platform(void) +native_get_x11_platform(const struct native_event_handler *event_handler) { + x11_event_handler = event_handler; return &x11_platform; } diff --git a/src/gallium/state_trackers/egl/x11/native_x11.h b/src/gallium/state_trackers/egl/x11/native_x11.h index 8945117276e..d3c9270a667 100644 --- a/src/gallium/state_trackers/egl/x11/native_x11.h +++ b/src/gallium/state_trackers/egl/x11/native_x11.h @@ -31,12 +31,10 @@ struct native_display * x11_create_ximage_display(Display *dpy, - struct native_event_handler *event_handler, - void *user_data); + const struct native_event_handler *event_handler); struct native_display * x11_create_dri2_display(Display *dpy, - struct native_event_handler *event_handler, - void *user_data); + const struct native_event_handler *event_handler); #endif /* _NATIVE_X11_H_ */ diff --git a/src/gallium/state_trackers/egl/x11/native_ximage.c b/src/gallium/state_trackers/egl/x11/native_ximage.c index 8e32c6ff0c4..e7794f0d3d7 100644 --- a/src/gallium/state_trackers/egl/x11/native_ximage.c +++ b/src/gallium/state_trackers/egl/x11/native_ximage.c @@ -43,7 +43,7 @@ struct ximage_display { Display *dpy; boolean own_dpy; - struct native_event_handler *event_handler; + const struct native_event_handler *event_handler; struct x11_screen *xscr; int xscr_number; @@ -437,14 +437,54 @@ ximage_display_get_configs(struct native_display *ndpy, int *num_configs) } static boolean -ximage_display_is_pixmap_supported(struct native_display *ndpy, - EGLNativePixmapType pix, - const struct native_config *nconf) +ximage_display_get_pixmap_format(struct native_display *ndpy, + EGLNativePixmapType pix, + enum pipe_format *format) { struct ximage_display *xdpy = ximage_display(ndpy); - enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix); - return (fmt == nconf->color_format); + *format = get_pixmap_format(&xdpy->base, pix); + + return (*format != PIPE_FORMAT_NONE); +} + +static boolean +ximage_display_copy_to_pixmap(struct native_display *ndpy, + EGLNativePixmapType pix, + struct pipe_resource *src) +{ + /* fast path to avoid unnecessary allocation and resource_copy_region */ + if (src->bind & PIPE_BIND_DISPLAY_TARGET) { + struct ximage_display *xdpy = ximage_display(ndpy); + enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix); + const struct ximage_config *xconf; + struct xlib_drawable xdraw; + int i; + + if (fmt == PIPE_FORMAT_NONE || src->format != fmt) + return FALSE; + + for (i = 0; i < xdpy->num_configs; i++) { + if (xdpy->configs[i].base.color_format == fmt) { + xconf = &xdpy->configs[i]; + break; + } + } + if (!xconf) + return FALSE; + + memset(&xdraw, 0, sizeof(xdraw)); + xdraw.visual = xconf->visual->visual; + xdraw.depth = xconf->visual->depth; + xdraw.drawable = (Drawable) pix; + + xdpy->base.screen->flush_frontbuffer(xdpy->base.screen, + src, 0, 0, &xdraw); + + return TRUE; + } + + return native_display_copy_to_pixmap(ndpy, pix, src); } static int @@ -484,13 +524,32 @@ ximage_display_destroy(struct native_display *ndpy) FREE(xdpy); } +static boolean +ximage_display_init_screen(struct native_display *ndpy) +{ + struct ximage_display *xdpy = ximage_display(ndpy); + struct sw_winsys *winsys; + + winsys = xlib_create_sw_winsys(xdpy->dpy); + if (!winsys) + return FALSE; + + xdpy->base.screen = + xdpy->event_handler->new_sw_screen(&xdpy->base, winsys); + if (!xdpy->base.screen) { + if (winsys->destroy) + winsys->destroy(winsys); + return FALSE; + } + + return TRUE; +} + struct native_display * x11_create_ximage_display(Display *dpy, - struct native_event_handler *event_handler, - void *user_data) + const struct native_event_handler *event_handler) { struct ximage_display *xdpy; - struct sw_winsys *winsys = NULL; xdpy = CALLOC_STRUCT(ximage_display); if (!xdpy) @@ -507,39 +566,25 @@ x11_create_ximage_display(Display *dpy, } xdpy->event_handler = event_handler; - xdpy->base.user_data = user_data; xdpy->xscr_number = DefaultScreen(xdpy->dpy); xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); - if (!xdpy->xscr) - goto fail; - - winsys = xlib_create_sw_winsys(xdpy->dpy); - if (!winsys) - goto fail; - - xdpy->base.screen = - xdpy->event_handler->new_sw_screen(&xdpy->base, winsys); - if (!xdpy->base.screen) - goto fail; + if (!xdpy->xscr) { + if (xdpy->own_dpy) + XCloseDisplay(xdpy->dpy); + FREE(xdpy); + return NULL; + } + xdpy->base.init_screen = ximage_display_init_screen; xdpy->base.destroy = ximage_display_destroy; xdpy->base.get_param = ximage_display_get_param; xdpy->base.get_configs = ximage_display_get_configs; - xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported; + xdpy->base.get_pixmap_format = ximage_display_get_pixmap_format; + xdpy->base.copy_to_pixmap = ximage_display_copy_to_pixmap; xdpy->base.create_window_surface = ximage_display_create_window_surface; xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; return &xdpy->base; - -fail: - if (winsys && winsys->destroy) - winsys->destroy(winsys); - if (xdpy->xscr) - x11_screen_destroy(xdpy->xscr); - if (xdpy->dpy && xdpy->own_dpy) - XCloseDisplay(xdpy->dpy); - FREE(xdpy); - return NULL; } diff --git a/src/gallium/state_trackers/egl/x11/x11_screen.c b/src/gallium/state_trackers/egl/x11/x11_screen.c index f1cc4400ba5..6155b4d03c0 100644 --- a/src/gallium/state_trackers/egl/x11/x11_screen.c +++ b/src/gallium/state_trackers/egl/x11/x11_screen.c @@ -452,6 +452,12 @@ dri2InvalidateBuffers(Display *dpy, XID drawable) extern unsigned dri2GetSwapEventType(Display *dpy, XID drawable); +extern void * +dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id); + +extern void * +GetGLXDrawable(Display *dpy, XID drawable); + /** * This is also called from src/glx/dri2.c. */ @@ -460,4 +466,16 @@ unsigned dri2GetSwapEventType(Display *dpy, XID drawable) return 0; } +void * +dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) +{ + return NULL; +} + +void * +GetGLXDrawable(Display *dpy, XID drawable) +{ + return NULL; +} + #endif /* GLX_DIRECT_RENDERING */ diff --git a/src/gallium/state_trackers/gbm/Makefile b/src/gallium/state_trackers/gbm/Makefile new file mode 100644 index 00000000000..1d96eb2032d --- /dev/null +++ b/src/gallium/state_trackers/gbm/Makefile @@ -0,0 +1,46 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +gbm_INCLUDES = \ + -I. \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gbm/main \ + -I$(TOP)/include + +gbm_SOURCES = $(wildcard *.c) +gbm_OBJECTS = $(gbm_SOURCES:.c=.o) + +ALL_INCLUDES = $(gbm_INCLUDES) +ALL_SOURCES = $(gbm_SOURCES) + +GBM_OBJECTS = $(gbm_OBJECTS) +GBM_CPPFLAGS = $(gbm_INCLUDES) + +##### TARGETS ##### + +default: depend libgbm.a + +libgbm.a: $(GBM_OBJECTS) Makefile + $(MKLIB) -o gbm -static $(GBM_OBJECTS) + +depend: + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(ALL_INCLUDES) $(ALL_SOURCES) 2> /dev/null + +clean: + rm -f libgbm.a + rm -f $(GBM_OBJECTS) + rm -f depend depend.bak + +# Dummy target +install: + @echo -n "" + +##### RULES ##### + +$(gbm_OBJECTS): %.o: %.c + $(CC) -c $(GBM_CPPFLAGS) $(DEFINES) $(CFLAGS) $< -o $@ + +sinclude depend diff --git a/src/gallium/state_trackers/gbm/gbm_drm.c b/src/gallium/state_trackers/gbm/gbm_drm.c new file mode 100644 index 00000000000..d4baf87096a --- /dev/null +++ b/src/gallium/state_trackers/gbm/gbm_drm.c @@ -0,0 +1,226 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 + * 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. + * + * Authors: + * Benjamin Franzke <[email protected]> + */ + +#include "util/u_memory.h" +#include "util/u_inlines.h" + +#include "state_tracker/drm_driver.h" + +#include <unistd.h> +#include <sys/types.h> + +#include "gbm_gallium_drmint.h" + +static INLINE enum pipe_format +gbm_format_to_gallium(enum gbm_bo_format format) +{ + switch (format) { + case GBM_BO_FORMAT_XRGB8888: + return PIPE_FORMAT_B8G8R8X8_UNORM; + case GBM_BO_FORMAT_ARGB8888: + return PIPE_FORMAT_B8G8R8A8_UNORM; + default: + return PIPE_FORMAT_NONE; + } + + return PIPE_FORMAT_NONE; +} + +static INLINE uint +gbm_usage_to_gallium(uint usage) +{ + uint resource_usage = 0; + + if (usage & GBM_BO_USE_SCANOUT) + resource_usage |= PIPE_BIND_SCANOUT; + + if (usage & GBM_BO_USE_RENDERING) + resource_usage |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + + if (usage & GBM_BO_USE_CURSOR_64X64) + resource_usage |= PIPE_BIND_CURSOR; + + return resource_usage; +} + +static int +gbm_gallium_drm_is_format_supported(struct gbm_device *gbm, + enum gbm_bo_format format, + uint32_t usage) +{ + struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm); + enum pipe_format pf; + + pf = gbm_format_to_gallium(format); + if (pf == PIPE_FORMAT_NONE) + return 0; + + if (!gdrm->screen->is_format_supported(gdrm->screen, PIPE_TEXTURE_2D, pf, 0, + gbm_usage_to_gallium(usage))) + return 0; + + if (usage & GBM_BO_USE_SCANOUT && format != GBM_BO_FORMAT_XRGB8888) + return 0; + + return 1; +} + +static void +gbm_gallium_drm_bo_destroy(struct gbm_bo *_bo) +{ + struct gbm_gallium_drm_bo *bo = gbm_gallium_drm_bo(_bo); + + pipe_resource_reference(&bo->resource, NULL); + free(bo); +} + +static struct gbm_bo * +gbm_gallium_drm_bo_create_from_egl_image(struct gbm_device *gbm, + void *egl_dpy, void *egl_image, + uint32_t width, uint32_t height, + uint32_t usage) +{ + struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm); + struct gbm_gallium_drm_bo *bo; + struct winsys_handle whandle; + + if (!gdrm->lookup_egl_image) + return NULL; + + bo = CALLOC_STRUCT(gbm_gallium_drm_bo); + if (bo == NULL) + return NULL; + + bo->resource = gdrm->lookup_egl_image(gdrm->lookup_egl_image_data, + egl_image); + if (bo->resource == NULL) { + FREE(bo); + return NULL; + } + + bo->base.base.gbm = gbm; + bo->base.base.width = width; + bo->base.base.height = height; + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_KMS; + gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle); + + bo->base.base.handle.u32 = whandle.handle; + bo->base.base.pitch = whandle.stride; + + return &bo->base.base; +} + +static struct gbm_bo * +gbm_gallium_drm_bo_create(struct gbm_device *gbm, + uint32_t width, uint32_t height, + enum gbm_bo_format format, uint32_t usage) +{ + struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm); + struct gbm_gallium_drm_bo *bo; + struct pipe_resource templ; + struct winsys_handle whandle; + enum pipe_format pf; + + bo = CALLOC_STRUCT(gbm_gallium_drm_bo); + if (bo == NULL) + return NULL; + + bo->base.base.gbm = gbm; + bo->base.base.width = width; + bo->base.base.height = height; + + pf = gbm_format_to_gallium(format); + if (pf == PIPE_FORMAT_NONE) + return NULL; + + memset(&templ, 0, sizeof(templ)); + templ.bind = gbm_usage_to_gallium(usage); + templ.format = pf; + templ.target = PIPE_TEXTURE_2D; + templ.last_level = 0; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + templ.array_size = 1; + + bo->resource = gdrm->screen->resource_create(gdrm->screen, &templ); + if (bo->resource == NULL) { + FREE(bo); + return NULL; + } + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_KMS; + gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle); + + bo->base.base.handle.u32 = whandle.handle; + bo->base.base.pitch = whandle.stride; + + return &bo->base.base; +} + +static void +gbm_gallium_drm_destroy(struct gbm_device *gbm) +{ + struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm); + + gdrm->screen->destroy(gdrm->screen); + + FREE(gdrm->base.driver_name); + + FREE(gdrm); +} + +struct gbm_device * +gbm_gallium_drm_device_create(int fd) +{ + struct gbm_gallium_drm_device *gdrm; + int ret; + + gdrm = calloc(1, sizeof *gdrm); + + gdrm->base.base.fd = fd; + gdrm->base.base.bo_create = gbm_gallium_drm_bo_create; + gdrm->base.base.bo_create_from_egl_image = + gbm_gallium_drm_bo_create_from_egl_image; + gdrm->base.base.bo_destroy = gbm_gallium_drm_bo_destroy; + gdrm->base.base.is_format_supported = gbm_gallium_drm_is_format_supported; + gdrm->base.base.destroy = gbm_gallium_drm_destroy; + + gdrm->base.type = GBM_DRM_DRIVER_TYPE_GALLIUM; + gdrm->base.base.name = "drm"; + + ret = gallium_screen_create(gdrm); + if (ret) { + free(gdrm); + return NULL; + } + + return &gdrm->base.base; +} diff --git a/src/gallium/state_trackers/gbm/gbm_gallium_drmint.h b/src/gallium/state_trackers/gbm/gbm_gallium_drmint.h new file mode 100644 index 00000000000..6277b8dba2e --- /dev/null +++ b/src/gallium/state_trackers/gbm/gbm_gallium_drmint.h @@ -0,0 +1,74 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 + * 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. + * + * Authors: + * Benjamin Franzke <[email protected]> + */ + +#ifndef _GBM_GALLIUM_DRMINT_H_ +#define _GBM_GALLIUM_DRMINT_H_ + +#include "pipe/p_state.h" + +#include "gbmint.h" + +#include "common.h" +#include "common_drm.h" + +struct gbm_gallium_drm_device { + struct gbm_drm_device base; + + struct pipe_screen *screen; + void *driver; + + struct pipe_resource *(*lookup_egl_image)(void *data, + void *egl_image); + void *lookup_egl_image_data; + +}; + +struct gbm_gallium_drm_bo { + struct gbm_drm_bo base; + + struct pipe_resource *resource; +}; + +static inline struct gbm_gallium_drm_device * +gbm_gallium_drm_device(struct gbm_device *gbm) +{ + return (struct gbm_gallium_drm_device *) gbm; +} + +static inline struct gbm_gallium_drm_bo * +gbm_gallium_drm_bo(struct gbm_bo *bo) +{ + return (struct gbm_gallium_drm_bo *) bo; +} + +struct gbm_device * +gbm_gallium_drm_device_create(int fd); + +int +gallium_screen_create(struct gbm_gallium_drm_device *gdrm); + +#endif diff --git a/src/gallium/state_trackers/glx/xlib/glx_api.c b/src/gallium/state_trackers/glx/xlib/glx_api.c index 6233fb81781..a7aafd846cd 100644 --- a/src/gallium/state_trackers/glx/xlib/glx_api.c +++ b/src/gallium/state_trackers/glx/xlib/glx_api.c @@ -864,16 +864,19 @@ choose_visual( Display *dpy, int screen, const int *list, GLboolean fbConfig ) parselist++; break; case GLX_FBCONFIG_ID: + case GLX_VISUAL_ID: if (!fbConfig) return NULL; parselist++; desiredVisualID = *parselist++; break; case GLX_X_RENDERABLE: + case GLX_MAX_PBUFFER_WIDTH: + case GLX_MAX_PBUFFER_HEIGHT: + case GLX_MAX_PBUFFER_PIXELS: if (!fbConfig) - return NULL; - parselist += 2; - /* ignore */ + return NULL; /* invalid config option */ + parselist += 2; /* ignore the parameter */ break; #ifdef GLX_EXT_texture_from_pixmap diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.c b/src/gallium/state_trackers/glx/xlib/xm_api.c index ab4f6753e11..8f6406ddaee 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_api.c +++ b/src/gallium/state_trackers/glx/xlib/xm_api.c @@ -59,6 +59,7 @@ #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "pipe/p_context.h" +#include "util/u_atomic.h" #include "xm_public.h" #include <GL/glx.h> @@ -1113,10 +1114,7 @@ XMesaDestroyBuffer(XMesaBuffer b) void xmesa_notify_invalid_buffer(XMesaBuffer b) { - XMesaContext xmctx = XMesaGetCurrentContext(); - - if (xmctx && xmctx->xm_buffer == b) - xmctx->st->notify_invalid_framebuffer(xmctx->st, b->stfb); + p_atomic_inc(&b->stfb->stamp); } @@ -1126,11 +1124,18 @@ xmesa_notify_invalid_buffer(XMesaBuffer b) void xmesa_check_buffer_size(XMesaBuffer b) { + GLuint old_width, old_height; + if (b->type == PBUFFER) return; + old_width = b->width; + old_height = b->height; + xmesa_get_window_size(b->xm_visual->display, b, &b->width, &b->height); - xmesa_notify_invalid_buffer(b); + + if (b->width != old_width || b->height != old_height) + xmesa_notify_invalid_buffer(b); } diff --git a/src/gallium/state_trackers/glx/xlib/xm_st.c b/src/gallium/state_trackers/glx/xlib/xm_st.c index 6bfe8b0788c..ec3f531f7df 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_st.c +++ b/src/gallium/state_trackers/glx/xlib/xm_st.c @@ -30,6 +30,7 @@ #include "xm_st.h" #include "util/u_inlines.h" +#include "util/u_atomic.h" struct xmesa_st_framebuffer { XMesaDisplay display; @@ -302,6 +303,7 @@ xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) stfbi->visual = &xstfb->stvis; stfbi->flush_front = xmesa_st_framebuffer_flush_front; stfbi->validate = xmesa_st_framebuffer_validate; + p_atomic_set(&stfbi->stamp, 1); stfbi->st_manager_private = (void *) xstfb; return stfbi; diff --git a/src/gallium/state_trackers/va/Makefile b/src/gallium/state_trackers/va/Makefile new file mode 100644 index 00000000000..d5b3ec3caf2 --- /dev/null +++ b/src/gallium/state_trackers/va/Makefile @@ -0,0 +1,28 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = vatracker + +VA_MAJOR = 0 +VA_MINOR = 3 +LIBRARY_DEFINES = -DVER_MAJOR=$(VA_MAJOR) -DVER_MINOR=$(VA_MINOR) $(STATE_TRACKER_DEFINES) + +LIBRARY_INCLUDES = \ + $(shell pkg-config --cflags-only-I libva) \ + -I$(TOP)/src/gallium/winsys/g3dvl + +C_SOURCES = htab.c \ + ftab.c \ + va_context.c \ + va_image.c \ + va_subpicture.c \ + va_buffer.c \ + va_config.c \ + va_picture.c \ + va_surface.c \ + va_display.c + + + +include ../../Makefile.template + diff --git a/src/gallium/state_trackers/va/ftab.c b/src/gallium/state_trackers/va/ftab.c new file mode 100644 index 00000000000..dc9513e2d7c --- /dev/null +++ b/src/gallium/state_trackers/va/ftab.c @@ -0,0 +1,136 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <va/va.h> +#include <va/va_backend.h> + +#include "va_private.h" + +static struct VADriverVTable vtable = +{ + &vlVaTerminate, /* VAStatus (*vaTerminate) ( VADriverContextP ctx ); */ + &vlVaQueryConfigProfiles, /* VAStatus (*vaQueryConfigProfiles) ( VADriverContextP ctx, VAProfile *profile_list,int *num_profiles); */ + &vlVaQueryConfigEntrypoints, /* VAStatus (*vaQueryConfigEntrypoints) ( VADriverContextP ctx, VAProfile profile, VAEntrypoint *entrypoint_list, int *num_entrypoints ); */ + &vlVaGetConfigAttributes, /* VAStatus (*vaGetConfigAttributes) ( VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs ); */ + &vlVaCreateConfig, /* VAStatus (*vaCreateConfig) ( VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs, VAConfigID *config_id); */ + &vlVaDestroyConfig, /* VAStatus (*vaDestroyConfig) ( VADriverContextP ctx, VAConfigID config_id); */ + &vlVaQueryConfigAttributes, /* VAStatus (*vaQueryConfigAttributes) ( VADriverContextP ctx, VAConfigID config_id, VAProfile *profile, VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, int *num_attribs); */ + &vlVaCreateSurfaces, /* VAStatus (*vaCreateSurfaces) ( VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID *surfaces); */ + &vlVaDestroySurfaces, /* VAStatus (*vaDestroySurfaces) ( VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces ); */ + &vlVaCreateContext, /* VAStatus (*vaCreateContext) (VADriverContextP ctx,VAConfigID config_id,int picture_width,int picture_height,int flag,VASurfaceID *render_targets,int num_render_targets,VAContextID *context); */ + &vlVaDestroyContext, /* VAStatus (*vaDestroyContext) (VADriverContextP ctx,VAContextID context); */ + &vlVaCreateBuffer, /* VAStatus (*vaCreateBuffer) (VADriverContextP ctx,VAContextID context,VABufferType type,unsigned int size,unsigned int num_elements,void *data,VABufferID *buf_id); */ + &vlVaBufferSetNumElements, /* VAStatus (*vaBufferSetNumElements) (VADriverContextP ctx,VABufferID buf_id,unsigned int num_elements); */ + &vlVaMapBuffer, /* VAStatus (*vaMapBuffer) (VADriverContextP ctx,VABufferID buf_id,void **pbuf); */ + &vlVaUnmapBuffer, /* VAStatus (*vaUnmapBuffer) (VADriverContextP ctx,VABufferID buf_id); */ + &vlVaDestroyBuffer, /* VAStatus (*vaDestroyBuffer) (VADriverContextP ctx,VABufferID buffer_id); */ + &vlVaBeginPicture, /* VAStatus (*vaBeginPicture) (VADriverContextP ctx,VAContextID context,VASurfaceID render_target); */ + &vlVaRenderPicture, /* VAStatus (*vaRenderPicture) (VADriverContextP ctx,VAContextID context,VABufferID *buffers,int num_buffers); */ + &vlVaEndPicture, /* VAStatus (*vaEndPicture) (VADriverContextP ctx,VAContextID context); */ + &vlVaSyncSurface, /* VAStatus (*vaSyncSurface) (VADriverContextP ctx,VASurfaceID render_target); */ + &vlVaQuerySurfaceStatus, /* VAStatus (*vaQuerySurfaceStatus) (VADriverContextP ctx,VASurfaceID render_target,VASurfaceStatus *status); */ + &vlVaPutSurface, /* VAStatus (*vaPutSurface) ( + VADriverContextP ctx, + VASurfaceID surface, + void* draw, + short srcx, + short srcy, + unsigned short srcw, + unsigned short srch, + short destx, + short desty, + unsigned short destw, + unsigned short desth, + VARectangle *cliprects, + unsigned int number_cliprects, + unsigned int flags); */ + &vlVaQueryImageFormats, /* VAStatus (*vaQueryImageFormats) ( VADriverContextP ctx, VAImageFormat *format_list,int *num_formats); */ + &vlVaCreateImage, /* VAStatus (*vaCreateImage) (VADriverContextP ctx,VAImageFormat *format,int width,int height,VAImage *image); */ + &vlVaDeriveImage, /* VAStatus (*vaDeriveImage) (VADriverContextP ctx,VASurfaceID surface,VAImage *image); */ + &vlVaDestroyImage, /* VAStatus (*vaDestroyImage) (VADriverContextP ctx,VAImageID image); */ + &vlVaSetImagePalette, /* VAStatus (*vaSetImagePalette) (VADriverContextP ctx,VAImageID image, unsigned char *palette); */ + &vlVaGetImage, /* VAStatus (*vaGetImage) (VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image); */ + &vlVaPutImage, /* VAStatus (*vaPutImage) ( + VADriverContextP ctx, + VASurfaceID surface, + VAImageID image, + int src_x, + int src_y, + unsigned int src_width, + unsigned int src_height, + int dest_x, + int dest_y, + unsigned int dest_width, + unsigned int dest_height + ); */ + &vlVaQuerySubpictureFormats, /* VAStatus (*vaQuerySubpictureFormats) (VADriverContextP ctx,VAImageFormat *format_list,unsigned int *flags,unsigned int *num_formats); */ + &vlVaCreateSubpicture, /* VAStatus (*vaCreateSubpicture) (VADriverContextP ctx,VAImageID image,VASubpictureID *subpicture); */ + &vlVaDestroySubpicture, /* VAStatus (*vaDestroySubpicture) (VADriverContextP ctx,VASubpictureID subpicture); */ + &vlVaSubpictureImage, /* VAStatus (*vaSetSubpictureImage) (VADriverContextP ctx,VASubpictureID subpicture,VAImageID image); */ + &vlVaSetSubpictureChromakey, /* VAStatus (*vaSetSubpictureChromakey) (VADriverContextP ctx,VASubpictureID subpicture,unsigned int chromakey_min,unsigned int chromakey_max,unsigned int chromakey_mask); */ + &vlVaSetSubpictureGlobalAlpha, /* VAStatus (*vaSetSubpictureGlobalAlpha) (VADriverContextP ctx,VASubpictureID subpicture,float global_alpha); */ + &vlVaAssociateSubpicture, /* VAStatus (*vaAssociateSubpicture) ( + VADriverContextP ctx, + VASubpictureID subpicture, + VASurfaceID *target_surfaces, + int num_surfaces, + short src_x, + short src_y, + unsigned short src_width, + unsigned short src_height, + short dest_x, + short dest_y, + unsigned short dest_width, + unsigned short dest_height, + unsigned int flags); */ + &vlVaDeassociateSubpicture, /* VAStatus (*vaDeassociateSubpicture) (VADriverContextP ctx,VASubpictureID subpicture,VASurfaceID *target_surfaces,int num_surfaces); */ + &vlVaQueryDisplayAttributes, /* VAStatus (*vaQueryDisplayAttributes) (VADriverContextP ctx,VADisplayAttribute *attr_list,int *num_attributes); */ + &vlVaGetDisplayAttributes, /* VAStatus (*vaGetDisplayAttributes) (VADriverContextP ctx,VADisplayAttribute *attr_list,int num_attributes); */ + &vlVaSetDisplayAttributes, /* VAStatus (*vaSetDisplayAttributes) (VADriverContextP ctx,VADisplayAttribute *attr_list,int num_attributes); */ + &vlVaBufferInfo, /* VAStatus (*vaBufferInfo) (VADriverContextP ctx,VAContextID context,VABufferID buf_id,VABufferType *type,unsigned int *size,unsigned int *num_elements); */ + &vlVaLockSurface, /* VAStatus (*vaLockSurface) ( + VADriverContextP ctx, + VASurfaceID surface, + unsigned int *fourcc, + unsigned int *luma_stride, + unsigned int *chroma_u_stride, + unsigned int *chroma_v_stride, + unsigned int *luma_offset, + unsigned int *chroma_u_offset, + unsigned int *chroma_v_offset, + unsigned int *buffer_name, + void **buffer); */ + &vlVaUnlockSurface, /* VAStatus (*vaUnlockSurface) (VADriverContextP ctx,VASurfaceID surface); */ + NULL /* struct VADriverVTableGLX *glx; "Optional" */ +}; + +struct VADriverVTable vlVaGetVtable() +{ + return vtable; +} diff --git a/src/gallium/state_trackers/va/htab.c b/src/gallium/state_trackers/va/htab.c new file mode 100644 index 00000000000..40b9edac819 --- /dev/null +++ b/src/gallium/state_trackers/va/htab.c @@ -0,0 +1,95 @@ +/************************************************************************** + * + * Copyright 2010 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <util/u_handle_table.h> +#include <os/os_thread.h> + +#include "va_private.h" + +#ifdef VL_HANDLES +static struct handle_table *htab = NULL; +pipe_static_mutex(htab_lock); +#endif + +bool vlCreateHTAB(void) +{ +#ifdef VL_HANDLES + bool ret; + /* Make sure handle table handles match VAAPI handles. */ + assert(sizeof(unsigned) <= sizeof(VAGenericID)); + pipe_mutex_lock(htab_lock); + if (!htab) + htab = handle_table_create(); + ret = htab != NULL; + pipe_mutex_unlock(htab_lock); + return ret; +#else + return TRUE; +#endif +} + +void vlDestroyHTAB(void) +{ +#ifdef VL_HANDLES + pipe_mutex_lock(htab_lock); + if (htab) { + handle_table_destroy(htab); + htab = NULL; + } + pipe_mutex_unlock(htab_lock); +#endif +} + +VAGenericID vlAddDataHTAB(void *data) +{ + assert(data); +#ifdef VL_HANDLES + VAGenericID handle = 0; + pipe_mutex_lock(htab_lock); + if (htab) + handle = handle_table_add(htab, data); + pipe_mutex_unlock(htab_lock); + return handle; +#else + return (VAGenericID)data; +#endif +} + +void* vlGetDataHTAB(VAGenericID handle) +{ + assert(handle); +#ifdef VL_HANDLES + void *data = NULL; + pipe_mutex_lock(htab_lock); + if (htab) + data = handle_table_get(htab, handle); + pipe_mutex_unlock(htab_lock); + return data; +#else + return (void*)handle; +#endif +} diff --git a/src/gallium/state_trackers/va/va_buffer.c b/src/gallium/state_trackers/va/va_buffer.c new file mode 100644 index 00000000000..d14e06d69e4 --- /dev/null +++ b/src/gallium/state_trackers/va/va_buffer.c @@ -0,0 +1,88 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> + +#include "va_private.h" + +VAStatus +vlVaCreateBuffer(VADriverContextP ctx, VAContextID context, VABufferType type, + unsigned int size, unsigned int num_elements, void *data, + VABufferID *buf_id) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id, unsigned int num_elements) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buffer_id) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaBufferInfo(VADriverContextP ctx, VAContextID context, VABufferID buf_id, + VABufferType *type, unsigned int *size, unsigned int *num_elements) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_config.c b/src/gallium/state_trackers/va/va_config.c new file mode 100644 index 00000000000..6f1cb78bb53 --- /dev/null +++ b/src/gallium/state_trackers/va/va_config.c @@ -0,0 +1,121 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> + +#include <util/u_debug.h> + +#include "va_private.h" + +VAStatus +vlVaQueryConfigProfiles(VADriverContextP ctx, VAProfile *profile_list, int *num_profiles) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + int i = 0; + + profile_list[i++] = VAProfileMPEG2Simple; + *num_profiles = i; + + return VA_STATUS_SUCCESS; +} + + +VAStatus +vlVaQueryConfigEntrypoints(VADriverContextP ctx, VAProfile profile, + VAEntrypoint *entrypoint_list, int *num_entrypoints) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + VAStatus vaStatus = VA_STATUS_SUCCESS; + + switch (profile) { + case VAProfileMPEG2Simple: + case VAProfileMPEG2Main: + VA_INFO("Using profile %08x\n",profile); + entrypoint_list[0] = VAEntrypointMoComp; + *num_entrypoints = 1; + break; + + case VAProfileH264Baseline: + case VAProfileH264Main: + case VAProfileH264High: + vaStatus = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; + *num_entrypoints = 0; + break; + + default: + VA_ERROR("Unsupported profile %08x\n",profile); + vaStatus = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; + *num_entrypoints = 0; + break; + } + + return vaStatus; +} + +VAStatus +vlVaGetConfigAttributes(VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoint, + VAConfigAttrib *attrib_list, int num_attribs) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaCreateConfig(VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoint, + VAConfigAttrib *attrib_list, int num_attribs, VAConfigID *config_id) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaDestroyConfig(VADriverContextP ctx, VAConfigID config_id) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaQueryConfigAttributes(VADriverContextP ctx, VAConfigID config_id, VAProfile *profile, + VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, int *num_attribs) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_context.c b/src/gallium/state_trackers/va/va_context.c new file mode 100644 index 00000000000..62ba3d24ae3 --- /dev/null +++ b/src/gallium/state_trackers/va/va_context.c @@ -0,0 +1,106 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> + +#include <pipe/p_screen.h> +#include <pipe/p_screen.h> +#include <pipe/p_video_decoder.h> + +#include <util/u_debug.h> +#include <util/u_memory.h> + +#include <vl_winsys.h> + +#include "va_private.h" + +PUBLIC VAStatus +__vaDriverInit_0_31(VADriverContextP ctx) +{ + vlVaDriverContextPriv *driver_context = NULL; + + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + + /* Create private driver context */ + driver_context = CALLOC(1,sizeof(vlVaDriverContextPriv)); + if (!driver_context) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + + driver_context->vscreen = vl_screen_create(ctx->native_dpy, ctx->x11_screen); + if (!driver_context->vscreen) { + FREE(driver_context); + return VA_STATUS_ERROR_ALLOCATION_FAILED; + } + + ctx->str_vendor = "mesa gallium vaapi"; + ctx->vtable = vlVaGetVtable(); + ctx->max_attributes = 1; + ctx->max_display_attributes = 1; + ctx->max_entrypoints = VA_MAX_ENTRYPOINTS; + ctx->max_image_formats = VA_MAX_IMAGE_FORMATS_SUPPORTED; + ctx->max_profiles = 1; + ctx->max_subpic_formats = VA_MAX_SUBPIC_FORMATS_SUPPORTED; + ctx->version_major = 3; + ctx->version_minor = 1; + ctx->pDriverData = (void *)driver_context; + + VA_INFO("vl_screen_pointer %p\n",ctx->native_dpy); + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width, + int picture_height, int flag, VASurfaceID *render_targets, + int num_render_targets, VAContextID *conext) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaDestroyContext(VADriverContextP ctx, VAContextID context) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaTerminate(VADriverContextP ctx) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_display.c b/src/gallium/state_trackers/va/va_display.c new file mode 100644 index 00000000000..11116d0c00a --- /dev/null +++ b/src/gallium/state_trackers/va/va_display.c @@ -0,0 +1,63 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + #include <va/va.h> + #include <va/va_backend.h> + + #include "va_private.h" + +VAStatus +vlVaQueryDisplayAttributes(VADriverContextP ctx, VADisplayAttribute *attr_list, int *num_attributes) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + if (!(attr_list && num_attributes)) + return VA_STATUS_ERROR_UNKNOWN; + + *num_attributes = 0; + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaGetDisplayAttributes(VADriverContextP ctx, VADisplayAttribute *attr_list, int num_attributes) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaSetDisplayAttributes(VADriverContextP ctx, VADisplayAttribute *attr_list, int num_attributes) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_image.c b/src/gallium/state_trackers/va/va_image.c new file mode 100644 index 00000000000..43c3a946737 --- /dev/null +++ b/src/gallium/state_trackers/va/va_image.c @@ -0,0 +1,151 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> + +#include <pipe/p_format.h> + +#include <util/u_memory.h> +#include <util/u_format.h> +#include <util/u_debug.h> + +#include "va_private.h" + +typedef struct { + enum pipe_format pipe_format; + VAImageFormat va_format; +} va_image_formats_supported_t; + +static const va_image_formats_supported_t va_image_formats_supported[VA_MAX_IMAGE_FORMATS_SUPPORTED] = +{ + { PIPE_FORMAT_B8G8R8A8_UNORM, + { VA_FOURCC('B','G','R','A'), VA_LSB_FIRST, 32, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }}, + { PIPE_FORMAT_R8G8B8A8_UNORM, + { VA_FOURCC_RGBA, VA_LSB_FIRST, 32, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }} +}; + +VAStatus +vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + if (!(format_list && num_formats)) + return VA_STATUS_ERROR_UNKNOWN; + + int n = 0; + + num_formats[0] = VA_MAX_IMAGE_FORMATS_SUPPORTED; + + /* Query supported formats */ + for (n = 0; n < VA_MAX_IMAGE_FORMATS_SUPPORTED; n++) { + format_list[n] = va_image_formats_supported[n].va_format; + } + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + if(!format) + return VA_STATUS_ERROR_UNKNOWN; + + if (!(width && height)) + return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT; + + if (!vlCreateHTAB()) + return VA_STATUS_ERROR_UNKNOWN; + + switch (format->fourcc) { + case VA_FOURCC('B','G','R','A'): + VA_INFO("Creating BGRA image of size %dx%d\n",width,height); + break; + case VA_FOURCC_RGBA: + VA_INFO("Creating RGBA image of size %dx%d\n",width,height); + break; + default: + VA_ERROR("Couldn't create image of type %0x08\n",format->fourcc); + return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; + } + + VA_INFO("Image %p created successfully\n",format); + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaDestroyImage(VADriverContextP ctx, VAImageID image) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y, + unsigned int width, unsigned int height, VAImageID image) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image, + int src_x, int src_y, unsigned int src_width, unsigned int src_height, + int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_picture.c b/src/gallium/state_trackers/va/va_picture.c new file mode 100644 index 00000000000..3b52a6a7e10 --- /dev/null +++ b/src/gallium/state_trackers/va/va_picture.c @@ -0,0 +1,60 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> + +#include <util/u_debug.h> + +#include "va_private.h" + +VAStatus +vlVaBeginPicture(VADriverContextP ctx, VAContextID context, VASurfaceID render_target) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaRenderPicture(VADriverContextP ctx, VAContextID context, VABufferID *buffers, int num_buffers) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaEndPicture(VADriverContextP ctx, VAContextID context) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_private.h b/src/gallium/state_trackers/va/va_private.h new file mode 100644 index 00000000000..f1023dbf87b --- /dev/null +++ b/src/gallium/state_trackers/va/va_private.h @@ -0,0 +1,162 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef VA_PRIVATE_H +#define VA_PRIVATE_H + +#include <va/va.h> +#include <va/va_backend.h> + +#include <pipe/p_format.h> +#include <pipe/p_state.h> + +#define VA_DEBUG(_str,...) debug_printf("[Gallium VA backend]: " _str,__VA_ARGS__) +#define VA_INFO(_str,...) VA_DEBUG("INFO: " _str,__VA_ARGS__) +#define VA_WARNING(_str,...) VA_DEBUG("WARNING: " _str,__VA_ARGS__) +#define VA_ERROR(_str,...) VA_DEBUG("ERROR: " _str,__VA_ARGS__) + +#define VA_MAX_IMAGE_FORMATS_SUPPORTED 2 +#define VA_MAX_SUBPIC_FORMATS_SUPPORTED 2 +#define VA_MAX_ENTRYPOINTS 1 + +#define VL_HANDLES + +typedef struct { + struct vl_screen *vscreen; + struct pipe_surface *backbuffer; +} vlVaDriverContextPriv; + +typedef struct { + unsigned int width; + unsigned int height; + enum pipe_video_chroma_format format; + VADriverContextP ctx; +} vlVaSurfacePriv; + +// Public functions: +VAStatus __vaDriverInit_0_31 (VADriverContextP ctx); + +// Private functions: +struct VADriverVTable vlVaGetVtable(); + +bool vlCreateHTAB(void); +void vlDestroyHTAB(void); +VAGenericID vlAddDataHTAB(void *data); +void* vlGetDataHTAB(VAGenericID handle); + +// Vtable functions: +VAStatus vlVaTerminate (VADriverContextP ctx); +VAStatus vlVaQueryConfigProfiles (VADriverContextP ctx, VAProfile *profile_list,int *num_profiles); +VAStatus vlVaQueryConfigEntrypoints (VADriverContextP ctx, VAProfile profile, VAEntrypoint *entrypoint_list, int *num_entrypoints); +VAStatus vlVaGetConfigAttributes (VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs); +VAStatus vlVaCreateConfig (VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs, VAConfigID *config_id); +VAStatus vlVaDestroyConfig (VADriverContextP ctx, VAConfigID config_id); +VAStatus vlVaQueryConfigAttributes (VADriverContextP ctx, VAConfigID config_id, VAProfile *profile, VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, int *num_attribs); +VAStatus vlVaCreateSurfaces (VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID *surfaces); +VAStatus vlVaDestroySurfaces (VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces); +VAStatus vlVaCreateContext (VADriverContextP ctx,VAConfigID config_id,int picture_width,int picture_height,int flag,VASurfaceID *render_targets,int num_render_targets,VAContextID *context); +VAStatus vlVaDestroyContext (VADriverContextP ctx,VAContextID context); +VAStatus vlVaCreateBuffer (VADriverContextP ctx,VAContextID context,VABufferType type,unsigned int size,unsigned int num_elements,void *data,VABufferID *buf_id); +VAStatus vlVaBufferSetNumElements (VADriverContextP ctx,VABufferID buf_id,unsigned int num_elements); +VAStatus vlVaMapBuffer (VADriverContextP ctx,VABufferID buf_id,void **pbuf); +VAStatus vlVaUnmapBuffer (VADriverContextP ctx,VABufferID buf_id); +VAStatus vlVaDestroyBuffer (VADriverContextP ctx,VABufferID buffer_id); +VAStatus vlVaBeginPicture (VADriverContextP ctx,VAContextID context,VASurfaceID render_target); +VAStatus vlVaRenderPicture (VADriverContextP ctx,VAContextID context,VABufferID *buffers,int num_buffers); +VAStatus vlVaEndPicture (VADriverContextP ctx,VAContextID context); +VAStatus vlVaSyncSurface (VADriverContextP ctx,VASurfaceID render_target); +VAStatus vlVaQuerySurfaceStatus (VADriverContextP ctx,VASurfaceID render_target,VASurfaceStatus *status); +VAStatus vlVaPutSurface (VADriverContextP ctx, + VASurfaceID surface, + void* draw, + short srcx, + short srcy, + unsigned short srcw, + unsigned short srch, + short destx, + short desty, + unsigned short destw, + unsigned short desth, + VARectangle *cliprects, + unsigned int number_cliprects, + unsigned int flags); +VAStatus vlVaQueryImageFormats (VADriverContextP ctx,VAImageFormat *format_list,int *num_formats); +VAStatus vlVaQuerySubpictureFormats(VADriverContextP ctx,VAImageFormat *format_list,unsigned int *flags,unsigned int *num_formats); +VAStatus vlVaCreateImage(VADriverContextP ctx,VAImageFormat *format,int width,int height,VAImage *image); +VAStatus vlVaDeriveImage(VADriverContextP ctx,VASurfaceID surface,VAImage *image); +VAStatus vlVaDestroyImage(VADriverContextP ctx,VAImageID image); +VAStatus vlVaSetImagePalette(VADriverContextP ctx,VAImageID image, unsigned char *palette); +VAStatus vlVaGetImage(VADriverContextP ctx,VASurfaceID surface,int x,int y,unsigned int width,unsigned int height,VAImageID image); +VAStatus vlVaPutImage(VADriverContextP ctx, + VASurfaceID surface, + VAImageID image, + int src_x, + int src_y, + unsigned int src_width, + unsigned int src_height, + int dest_x, + int dest_y, + unsigned int dest_width, + unsigned int dest_height); +VAStatus vlVaQuerySubpictureFormats(VADriverContextP ctx,VAImageFormat *format_list,unsigned int *flags,unsigned int *num_formats); +VAStatus vlVaCreateSubpicture(VADriverContextP ctx,VAImageID image,VASubpictureID *subpicture); +VAStatus vlVaDestroySubpicture(VADriverContextP ctx,VASubpictureID subpicture); +VAStatus vlVaSubpictureImage(VADriverContextP ctx,VASubpictureID subpicture,VAImageID image); +VAStatus vlVaSetSubpictureChromakey(VADriverContextP ctx,VASubpictureID subpicture,unsigned int chromakey_min,unsigned int chromakey_max,unsigned int chromakey_mask); +VAStatus vlVaSetSubpictureGlobalAlpha(VADriverContextP ctx,VASubpictureID subpicture,float global_alpha); +VAStatus vlVaAssociateSubpicture(VADriverContextP ctx, + VASubpictureID subpicture, + VASurfaceID *target_surfaces, + int num_surfaces, + short src_x, + short src_y, + unsigned short src_width, + unsigned short src_height, + short dest_x, + short dest_y, + unsigned short dest_width, + unsigned short dest_height, + unsigned int flags); +VAStatus vlVaDeassociateSubpicture(VADriverContextP ctx,VASubpictureID subpicture,VASurfaceID *target_surfaces,int num_surfaces); +VAStatus vlVaQueryDisplayAttributes(VADriverContextP ctx,VADisplayAttribute *attr_list,int *num_attributes); +VAStatus vlVaGetDisplayAttributes(VADriverContextP ctx,VADisplayAttribute *attr_list,int num_attributes); +VAStatus vlVaSetDisplayAttributes(VADriverContextP ctx,VADisplayAttribute *attr_list,int num_attributes); +VAStatus vlVaBufferInfo(VADriverContextP ctx,VAContextID context,VABufferID buf_id,VABufferType *type,unsigned int *size,unsigned int *num_elements); +VAStatus vlVaLockSurface(VADriverContextP ctx, + VASurfaceID surface, + unsigned int *fourcc, + unsigned int *luma_stride, + unsigned int *chroma_u_stride, + unsigned int *chroma_v_stride, + unsigned int *luma_offset, + unsigned int *chroma_u_offset, + unsigned int *chroma_v_offset, + unsigned int *buffer_name, + void **buffer); +VAStatus vlVaUnlockSurface(VADriverContextP ctx,VASurfaceID surface); + +#endif //VA_PRIVATE_H diff --git a/src/gallium/state_trackers/va/va_subpicture.c b/src/gallium/state_trackers/va/va_subpicture.c new file mode 100644 index 00000000000..3f370e5889f --- /dev/null +++ b/src/gallium/state_trackers/va/va_subpicture.c @@ -0,0 +1,143 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> + +#include <pipe/p_format.h> + +#include "va_private.h" + +typedef struct { + enum pipe_format pipe_format; + VAImageFormat va_format; + unsigned int va_flags; +} va_subpicture_formats_supported_t; + +static const va_subpicture_formats_supported_t va_subpicture_formats_supported[VA_MAX_SUBPIC_FORMATS_SUPPORTED + 1] = +{ + { PIPE_FORMAT_B8G8R8A8_UNORM, + { VA_FOURCC('B','G','R','A'), VA_LSB_FIRST, 32, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + 0 }, + { PIPE_FORMAT_R8G8B8A8_UNORM, + { VA_FOURCC_RGBA, VA_LSB_FIRST, 32, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, + 0 } +}; + +VAStatus +vlVaQuerySubpictureFormats(VADriverContextP ctx, VAImageFormat *format_list, + unsigned int *flags, unsigned int *num_formats) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + if (!(format_list && flags && num_formats)) + return VA_STATUS_ERROR_UNKNOWN; + + num_formats[0] = VA_MAX_SUBPIC_FORMATS_SUPPORTED; + + int n = 0; + /* Query supported formats */ + for (n = 0; n < VA_MAX_SUBPIC_FORMATS_SUPPORTED ; n++) { + const va_subpicture_formats_supported_t * const format_map = &va_subpicture_formats_supported[n]; + flags[n] = format_map->va_flags; + format_list[n] = format_map->va_format; + } + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaCreateSubpicture(VADriverContextP ctx, VAImageID image, VASubpictureID *subpicture) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaDestroySubpicture(VADriverContextP ctx, VASubpictureID subpicture) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaSubpictureImage(VADriverContextP ctx, VASubpictureID subpicture, VAImageID image) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaSetSubpictureChromakey(VADriverContextP ctx, VASubpictureID subpicture, + unsigned int chromakey_min, unsigned int chromakey_max, unsigned int chromakey_mask) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaSetSubpictureGlobalAlpha(VADriverContextP ctx, VASubpictureID subpicture, float global_alpha) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaAssociateSubpicture(VADriverContextP ctx, VASubpictureID subpicture, VASurfaceID *target_surfaces, + int num_surfaces, short src_x, short src_y, + unsigned short src_width, unsigned short src_height, + short dest_x, short dest_y, + unsigned short dest_width, + unsigned short dest_height, + unsigned int flags) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaDeassociateSubpicture(VADriverContextP ctx, VASubpictureID subpicture, + VASurfaceID *target_surfaces, int num_surfaces) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/va/va_surface.c b/src/gallium/state_trackers/va/va_surface.c new file mode 100644 index 00000000000..b7f9732d248 --- /dev/null +++ b/src/gallium/state_trackers/va/va_surface.c @@ -0,0 +1,142 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <va/va.h> +#include <va/va_backend.h> +#include <util/u_debug.h> +#include <util/u_memory.h> +#include "va_private.h" + +static enum pipe_video_chroma_format +VaRTFormatToPipe(unsigned int va_type) +{ + switch (va_type) { + case VA_RT_FORMAT_YUV420: + return PIPE_VIDEO_CHROMA_FORMAT_420; + case VA_RT_FORMAT_YUV422: + return PIPE_VIDEO_CHROMA_FORMAT_422; + case VA_RT_FORMAT_YUV444: + return PIPE_VIDEO_CHROMA_FORMAT_444; + default: + assert(0); + } + + return -1; +} + +VAStatus +vlVaCreateSurfaces(VADriverContextP ctx, int width, int height, int format, + int num_surfaces, VASurfaceID *surfaces) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + /* We only support one format */ + if (VA_RT_FORMAT_YUV420 != format) + return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; + + if (!(width && height)) + return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT; + + if (!vlCreateHTAB()) + return VA_STATUS_ERROR_UNKNOWN; + + vlVaSurfacePriv *va_surface = (vlVaSurfacePriv *)CALLOC(num_surfaces,sizeof(vlVaSurfacePriv)); + if (!va_surface) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + + int n = 0; + for (n = 0; n < num_surfaces; n++) { + va_surface[n].width = width; + va_surface[n].height = height; + va_surface[n].format = VaRTFormatToPipe(format); + va_surface[n].ctx = ctx; + surfaces[n] = vlAddDataHTAB((void *)(va_surface + n)); + } + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface, void* draw, short srcx, short srcy, + unsigned short srcw, unsigned short srch, short destx, short desty, + unsigned short destw, unsigned short desth, VARectangle *cliprects, + unsigned int number_cliprects, unsigned int flags) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaLockSurface(VADriverContextP ctx, VASurfaceID surface, unsigned int *fourcc, + unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride, + unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset, + unsigned int *buffer_name, void **buffer) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} + +VAStatus +vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface) +{ + if (!ctx) + return VA_STATUS_ERROR_INVALID_CONTEXT; + + return VA_STATUS_ERROR_UNIMPLEMENTED; +} diff --git a/src/gallium/state_trackers/vdpau/Makefile b/src/gallium/state_trackers/vdpau/Makefile new file mode 100644 index 00000000000..c1fd0eb7d0e --- /dev/null +++ b/src/gallium/state_trackers/vdpau/Makefile @@ -0,0 +1,28 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = vdpautracker + +VDPAU_MAJOR = 1 +VDPAU_MINOR = 0 +LIBRARY_DEFINES = -DVER_MAJOR=$(VDPAU_MAJOR) -DVER_MINOR=$(VDPAU_MINOR) $(STATE_TRACKER_DEFINES) + +LIBRARY_INCLUDES = \ + $(shell pkg-config --cflags-only-I vdpau) \ + -I$(TOP)/src/gallium/winsys/g3dvl + +C_SOURCES = htab.c \ + ftab.c \ + device.c \ + query.c \ + surface.c \ + decode.c \ + presentation.c \ + bitmap.c \ + output.c \ + preemption.c \ + mixer.c + + +include ../../Makefile.template + diff --git a/src/gallium/state_trackers/vdpau/bitmap.c b/src/gallium/state_trackers/vdpau/bitmap.c new file mode 100644 index 00000000000..e336568df47 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/bitmap.c @@ -0,0 +1,74 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <vdpau/vdpau.h> + +#include "vdpau_private.h" + +VdpStatus +vlVdpBitmapSurfaceCreate(VdpDevice device, + VdpRGBAFormat rgba_format, + uint32_t width, uint32_t height, + VdpBool frequently_accessed, + VdpBitmapSurface *surface) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating a bitmap surface\n"); + if (!surface) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpBitmapSurfaceDestroy(VdpBitmapSurface surface) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpBitmapSurfaceGetParameters(VdpBitmapSurface surface, + VdpRGBAFormat *rgba_format, + uint32_t *width, uint32_t *height, + VdpBool *frequently_accessed) +{ + if (!(rgba_format && width && height && frequently_accessed)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpBitmapSurfacePutBitsNative(VdpBitmapSurface surface, + void const *const *source_data, + uint32_t const *source_pitches, + VdpRect const *destination_rect ) +{ + if (!(source_data && source_pitches && destination_rect)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} diff --git a/src/gallium/state_trackers/vdpau/decode.c b/src/gallium/state_trackers/vdpau/decode.c new file mode 100644 index 00000000000..96542f874d9 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/decode.c @@ -0,0 +1,274 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <util/u_memory.h> +#include <util/u_math.h> +#include <util/u_debug.h> + +#include "vdpau_private.h" + +VdpStatus +vlVdpDecoderCreate(VdpDevice device, + VdpDecoderProfile profile, + uint32_t width, uint32_t height, + uint32_t max_references, + VdpDecoder *decoder) +{ + enum pipe_video_profile p_profile; + struct pipe_context *pipe; + vlVdpDevice *dev; + vlVdpDecoder *vldecoder; + VdpStatus ret; + unsigned i; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating decoder\n"); + + if (!decoder) + return VDP_STATUS_INVALID_POINTER; + + if (!(width && height)) + return VDP_STATUS_INVALID_VALUE; + + p_profile = ProfileToPipe(profile); + if (p_profile == PIPE_VIDEO_PROFILE_UNKNOWN) + return VDP_STATUS_INVALID_DECODER_PROFILE; + + dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + pipe = dev->context->pipe; + + vldecoder = CALLOC(1,sizeof(vlVdpDecoder)); + if (!vldecoder) + return VDP_STATUS_RESOURCES; + + vldecoder->device = dev; + + // TODO: Define max_references. Used mainly for H264 + vldecoder->decoder = pipe->create_video_decoder + ( + pipe, p_profile, + PIPE_VIDEO_ENTRYPOINT_BITSTREAM, + PIPE_VIDEO_CHROMA_FORMAT_420, + width, height + ); + if (!vldecoder->decoder) { + ret = VDP_STATUS_ERROR; + goto error_decoder; + } + + 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]) { + ret = VDP_STATUS_ERROR; + goto error_buffer; + } + } + + *decoder = vlAddDataHTAB(vldecoder); + if (*decoder == 0) { + ret = VDP_STATUS_ERROR; + goto error_handle; + } + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoder created succesfully\n"); + + return VDP_STATUS_OK; + +error_handle: +error_buffer: + + for (i = 0; i < VL_NUM_DECODE_BUFFERS; ++i) + if (vldecoder->buffer[i]) + vldecoder->buffer[i]->destroy(vldecoder->buffer[i]); + + vldecoder->decoder->destroy(vldecoder->decoder); + +error_decoder: + FREE(vldecoder); + return ret; +} + +VdpStatus +vlVdpDecoderDestroy(VdpDecoder decoder) +{ + vlVdpDecoder *vldecoder; + unsigned i; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying decoder\n"); + + vldecoder = (vlVdpDecoder *)vlGetDataHTAB(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]); + + vldecoder->decoder->destroy(vldecoder->decoder); + + FREE(vldecoder); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpDecoderGetParameters(VdpDecoder decoder, + VdpDecoderProfile *profile, + uint32_t *width, + uint32_t *height) +{ + vlVdpDecoder *vldecoder; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] decoder get parameters called\n"); + + vldecoder = (vlVdpDecoder *)vlGetDataHTAB(decoder); + if (!vldecoder) + return VDP_STATUS_INVALID_HANDLE; + + *profile = PipeToProfile(vldecoder->decoder->profile); + *width = vldecoder->decoder->width; + *height = vldecoder->decoder->height; + + return VDP_STATUS_OK; +} + +static VdpStatus +vlVdpDecoderRenderMpeg12(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) +{ + struct pipe_mpeg12_picture_desc picture; + 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"); + + /* 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]) + return VDP_STATUS_INVALID_HANDLE; + } + + 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]) + return VDP_STATUS_INVALID_HANDLE; + } + + memset(&picture, 0, sizeof(picture)); + picture.base.profile = decoder->profile; + picture.picture_coding_type = picture_info->picture_coding_type; + picture.picture_structure = picture_info->picture_structure; + picture.frame_pred_frame_dct = picture_info->frame_pred_frame_dct; + picture.q_scale_type = picture_info->q_scale_type; + 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.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); + + 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); + + 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); + + buffer->end_frame(buffer); + + decoder->flush_buffer(buffer, num_ycbcr_blocks, ref_frames, target); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpDecoderRender(VdpDecoder decoder, + VdpVideoSurface target, + VdpPictureInfo const *picture_info, + uint32_t bitstream_buffer_count, + VdpBitstreamBuffer const *bitstream_buffers) +{ + vlVdpDecoder *vldecoder; + vlVdpSurface *vlsurf; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoding\n"); + + if (!(picture_info && bitstream_buffers)) + return VDP_STATUS_INVALID_POINTER; + + vldecoder = (vlVdpDecoder *)vlGetDataHTAB(decoder); + if (!vldecoder) + return VDP_STATUS_INVALID_HANDLE; + + vlsurf = (vlVdpSurface *)vlGetDataHTAB(target); + if (!vlsurf) + return VDP_STATUS_INVALID_HANDLE; + + if (vlsurf->device != vldecoder->device) + return VDP_STATUS_HANDLE_DEVICE_MISMATCH; + + if (vlsurf->video_buffer->chroma_format != vldecoder->decoder->chroma_format) + // TODO: Recreate decoder with correct chroma + return VDP_STATUS_INVALID_CHROMA_TYPE; + + // 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 vlVdpDecoderRenderMpeg12(vldecoder->decoder, + vldecoder->buffer[vldecoder->cur_buffer], + vlsurf->video_buffer, + (VdpPictureInfoMPEG1Or2 *)picture_info, + bitstream_buffer_count,bitstream_buffers); + break; + + default: + return VDP_STATUS_INVALID_DECODER_PROFILE; + } +} diff --git a/src/gallium/state_trackers/vdpau/device.c b/src/gallium/state_trackers/vdpau/device.c new file mode 100644 index 00000000000..200d5f62f63 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/device.c @@ -0,0 +1,225 @@ +/************************************************************************** + * + * Copyright 2010 Younes Manton og Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <pipe/p_compiler.h> + +#include <util/u_memory.h> +#include <util/u_debug.h> + +#include <vl_winsys.h> + +#include "vdpau_private.h" + +PUBLIC VdpStatus +vdp_imp_device_create_x11(Display *display, int screen, VdpDevice *device, + VdpGetProcAddress **get_proc_address) +{ + VdpStatus ret; + vlVdpDevice *dev = NULL; + + if (!(display && device && get_proc_address)) + return VDP_STATUS_INVALID_POINTER; + + if (!vlCreateHTAB()) { + ret = VDP_STATUS_RESOURCES; + goto no_htab; + } + + dev = CALLOC(1, sizeof(vlVdpDevice)); + if (!dev) { + ret = VDP_STATUS_RESOURCES; + goto no_dev; + } + + dev->vscreen = vl_screen_create(display, screen); + if (!dev->vscreen) { + ret = VDP_STATUS_RESOURCES; + goto no_vscreen; + } + + dev->context = vl_video_create(dev->vscreen); + if (!dev->context) { + ret = VDP_STATUS_RESOURCES; + goto no_context; + } + + *device = vlAddDataHTAB(dev); + if (*device == 0) { + ret = VDP_STATUS_ERROR; + goto no_handle; + } + + *get_proc_address = &vlVdpGetProcAddress; + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Device created succesfully\n"); + + return VDP_STATUS_OK; + +no_handle: + /* Destroy vscreen */ +no_context: + vl_screen_destroy(dev->vscreen); +no_vscreen: + FREE(dev); +no_dev: + vlDestroyHTAB(); +no_htab: + return ret; +} + +PUBLIC VdpStatus +vlVdpPresentationQueueTargetCreateX11(VdpDevice device, Drawable drawable, + VdpPresentationQueueTarget *target) +{ + vlVdpPresentationQueueTarget *pqt; + VdpStatus ret; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating PresentationQueueTarget\n"); + + if (!drawable) + return VDP_STATUS_INVALID_HANDLE; + + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + pqt = CALLOC(1, sizeof(vlVdpPresentationQueue)); + if (!pqt) + return VDP_STATUS_RESOURCES; + + pqt->device = dev; + pqt->drawable = drawable; + + *target = vlAddDataHTAB(pqt); + if (*target == 0) { + ret = VDP_STATUS_ERROR; + goto no_handle; + } + + return VDP_STATUS_OK; + +no_handle: + FREE(pqt); + return ret; +} + +VdpStatus +vlVdpPresentationQueueTargetDestroy(VdpPresentationQueueTarget presentation_queue_target) +{ + vlVdpPresentationQueueTarget *pqt; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying PresentationQueueTarget\n"); + + pqt = vlGetDataHTAB(presentation_queue_target); + if (!pqt) + return VDP_STATUS_INVALID_HANDLE; + + vlRemoveDataHTAB(presentation_queue_target); + FREE(pqt); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpDeviceDestroy(VdpDevice device) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying destroy\n"); + + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + vl_video_destroy(dev->context); + vl_screen_destroy(dev->vscreen); + + FREE(dev); + vlDestroyHTAB(); + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Device destroyed succesfully\n"); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpGetProcAddress(VdpDevice device, VdpFuncId function_id, void **function_pointer) +{ + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + if (!function_pointer) + return VDP_STATUS_INVALID_POINTER; + + if (!vlGetFuncFTAB(function_id, function_pointer)) + return VDP_STATUS_INVALID_FUNC_ID; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Got proc adress %p for id %d\n", *function_pointer, function_id); + + return VDP_STATUS_OK; +} + +#define _ERROR_TYPE(TYPE,STRING) case TYPE: return STRING; + +char const * +vlVdpGetErrorString (VdpStatus status) +{ + switch (status) { + _ERROR_TYPE(VDP_STATUS_OK,"The operation completed successfully; no error."); + _ERROR_TYPE(VDP_STATUS_NO_IMPLEMENTATION,"No backend implementation could be loaded."); + _ERROR_TYPE(VDP_STATUS_DISPLAY_PREEMPTED,"The display was preempted, or a fatal error occurred. The application must re-initialize VDPAU."); + _ERROR_TYPE(VDP_STATUS_INVALID_HANDLE,"An invalid handle value was provided. Either the handle does not exist at all, or refers to an object of an incorrect type."); + _ERROR_TYPE(VDP_STATUS_INVALID_POINTER ,"An invalid pointer was provided. Typically, this means that a NULL pointer was provided for an 'output' parameter."); + _ERROR_TYPE(VDP_STATUS_INVALID_CHROMA_TYPE ,"An invalid/unsupported VdpChromaType value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_Y_CB_CR_FORMAT,"An invalid/unsupported VdpYCbCrFormat value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_RGBA_FORMAT,"An invalid/unsupported VdpRGBAFormat value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_INDEXED_FORMAT,"An invalid/unsupported VdpIndexedFormat value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_COLOR_STANDARD,"An invalid/unsupported VdpColorStandard value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_COLOR_TABLE_FORMAT,"An invalid/unsupported VdpColorTableFormat value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_BLEND_FACTOR,"An invalid/unsupported VdpOutputSurfaceRenderBlendFactor value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_BLEND_EQUATION,"An invalid/unsupported VdpOutputSurfaceRenderBlendEquation value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_FLAG,"An invalid/unsupported flag value/combination was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_DECODER_PROFILE,"An invalid/unsupported VdpDecoderProfile value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE,"An invalid/unsupported VdpVideoMixerFeature value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER ,"An invalid/unsupported VdpVideoMixerParameter value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE,"An invalid/unsupported VdpVideoMixerAttribute value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE,"An invalid/unsupported VdpVideoMixerPictureStructure value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_FUNC_ID,"An invalid/unsupported VdpFuncId value was supplied."); + _ERROR_TYPE(VDP_STATUS_INVALID_SIZE,"The size of a supplied object does not match the object it is being used with.\ + For example, a VdpVideoMixer is configured to process VdpVideoSurface objects of a specific size.\ + If presented with a VdpVideoSurface of a different size, this error will be raised."); + _ERROR_TYPE(VDP_STATUS_INVALID_VALUE,"An invalid/unsupported value was supplied.\ + This is a catch-all error code for values of type other than those with a specific error code."); + _ERROR_TYPE(VDP_STATUS_INVALID_STRUCT_VERSION,"An invalid/unsupported structure version was specified in a versioned structure. \ + This implies that the implementation is older than the header file the application was built against."); + _ERROR_TYPE(VDP_STATUS_RESOURCES,"The system does not have enough resources to complete the requested operation at this time."); + _ERROR_TYPE(VDP_STATUS_HANDLE_DEVICE_MISMATCH,"The set of handles supplied are not all related to the same VdpDevice.When performing operations \ + that operate on multiple surfaces, such as VdpOutputSurfaceRenderOutputSurface or VdpVideoMixerRender, \ + all supplied surfaces must have been created within the context of the same VdpDevice object. \ + This error is raised if they were not."); + _ERROR_TYPE(VDP_STATUS_ERROR,"A catch-all error, used when no other error code applies."); + default: return "Unknown Error"; + } +} diff --git a/src/gallium/state_trackers/vdpau/ftab.c b/src/gallium/state_trackers/vdpau/ftab.c new file mode 100644 index 00000000000..66ed50c3299 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/ftab.c @@ -0,0 +1,122 @@ +/************************************************************************** + * + * Copyright 2010 Younes Manton & Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include "vdpau_private.h" + +static void* ftab[67] = +{ + &vlVdpGetErrorString, /* VDP_FUNC_ID_GET_ERROR_STRING */ + &vlVdpGetProcAddress, /* VDP_FUNC_ID_GET_PROC_ADDRESS */ + &vlVdpGetApiVersion, /* VDP_FUNC_ID_GET_API_VERSION */ + NULL, /* DUMMY */ + &vlVdpGetInformationString, /* VDP_FUNC_ID_GET_INFORMATION_STRING */ + &vlVdpDeviceDestroy, /* VDP_FUNC_ID_DEVICE_DESTROY */ + &vlVdpGenerateCSCMatrix, /* VDP_FUNC_ID_GENERATE_CSC_MATRIX */ + &vlVdpVideoSurfaceQueryCapabilities, /* VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES */ + &vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities, /* VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES */ + &vlVdpVideoSurfaceCreate, /* VDP_FUNC_ID_VIDEO_SURFACE_CREATE */ + &vlVdpVideoSurfaceDestroy, /* VDP_FUNC_ID_VIDEO_SURFACE_DESTROY */ + &vlVdpVideoSurfaceGetParameters, /* VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS */ + &vlVdpVideoSurfaceGetBitsYCbCr, /* VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR */ + &vlVdpVideoSurfacePutBitsYCbCr, /* VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR */ + &vlVdpOutputSurfaceQueryCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES */ + &vlVdpOutputSurfaceQueryGetPutBitsNativeCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_GET_PUT_BITS_NATIVE_CAPABILITIES */ + &vlVdpOutputSurfaceQueryPutBitsIndexedCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_INDEXED_CAPABILITIES */ + &vlVdpOutputSurfaceQueryPutBitsYCbCrCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_Y_CB_CR_CAPABILITIES */ + &vlVdpOutputSurfaceCreate, /* VDP_FUNC_ID_OUTPUT_SURFACE_CREATE */ + &vlVdpOutputSurfaceDestroy, /* VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY */ + &vlVdpOutputSurfaceGetParameters, /* VDP_FUNC_ID_OUTPUT_SURFACE_GET_PARAMETERS */ + &vlVdpOutputSurfaceGetBitsNative, /* VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE */ + &vlVdpOutputSurfacePutBitsNative, /* VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE */ + &vlVdpOutputSurfacePutBitsIndexed, /* VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED */ + &vlVdpOutputSurfacePutBitsYCbCr, /* VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR */ + &vlVdpBitmapSurfaceQueryCapabilities, /* VDP_FUNC_ID_BITMAP_SURFACE_QUERY_CAPABILITIES */ + &vlVdpBitmapSurfaceCreate, /* VDP_FUNC_ID_BITMAP_SURFACE_CREATE */ + &vlVdpBitmapSurfaceDestroy, /* VDP_FUNC_ID_BITMAP_SURFACE_DESTROY */ + &vlVdpBitmapSurfaceGetParameters, /* VDP_FUNC_ID_BITMAP_SURFACE_GET_PARAMETERS */ + &vlVdpBitmapSurfacePutBitsNative, /* VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE */ + NULL, /* DUMMY */ + NULL, /* DUMMY */ + NULL, /* DUMMY */ + &vlVdpOutputSurfaceRenderOutputSurface, /* VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE */ + &vlVdpOutputSurfaceRenderBitmapSurface, /* VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE */ + NULL, /* VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_VIDEO_SURFACE_LUMA */ + &vlVdpDecoderQueryCapabilities, /* VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES */ + &vlVdpDecoderCreate, /* VDP_FUNC_ID_DECODER_CREATE */ + &vlVdpDecoderDestroy, /* VDP_FUNC_ID_DECODER_DESTROY */ + &vlVdpDecoderGetParameters, /* VDP_FUNC_ID_DECODER_GET_PARAMETERS */ + &vlVdpDecoderRender, /* VDP_FUNC_ID_DECODER_RENDER */ + &vlVdpVideoMixerQueryFeatureSupport, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT */ + &vlVdpVideoMixerQueryParameterSupport, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT */ + &vlVdpVideoMixerQueryAttributeSupport, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT */ + &vlVdpVideoMixerQueryParameterValueRange, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE */ + &vlVdpVideoMixerQueryAttributeValueRange, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE */ + &vlVdpVideoMixerCreate, /* VDP_FUNC_ID_VIDEO_MIXER_CREATE */ + &vlVdpVideoMixerSetFeatureEnables, /* VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES */ + &vlVdpVideoMixerSetAttributeValues, /* VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES */ + &vlVdpVideoMixerGetFeatureSupport, /* VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_SUPPORT */ + &vlVdpVideoMixerGetFeatureEnables, /* VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_ENABLES */ + &vlVdpVideoMixerGetParameterValues, /* VDP_FUNC_ID_VIDEO_MIXER_GET_PARAMETER_VALUES */ + &vlVdpVideoMixerGetAttributeValues, /* VDP_FUNC_ID_VIDEO_MIXER_GET_ATTRIBUTE_VALUES */ + &vlVdpVideoMixerDestroy, /* VDP_FUNC_ID_VIDEO_MIXER_DESTROY */ + &vlVdpVideoMixerRender, /* VDP_FUNC_ID_VIDEO_MIXER_RENDER */ + &vlVdpPresentationQueueTargetDestroy, /* VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY */ + &vlVdpPresentationQueueCreate, /* VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE */ + &vlVdpPresentationQueueDestroy, /* VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY */ + &vlVdpPresentationQueueSetBackgroundColor, /* VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR */ + &vlVdpPresentationQueueGetBackgroundColor, /* VDP_FUNC_ID_PRESENTATION_QUEUE_GET_BACKGROUND_COLOR */ + NULL, /* DUMMY */ + NULL, /* DUMMY */ + &vlVdpPresentationQueueGetTime, /* VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME */ + &vlVdpPresentationQueueDisplay, /* VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY */ + &vlVdpPresentationQueueBlockUntilSurfaceIdle, /* VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE */ + &vlVdpPresentationQueueQuerySurfaceStatus, /* VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS */ + &vlVdpPreemptionCallbackRegister /* VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER */ +}; + +static void* ftab_winsys[1] = +{ + &vlVdpPresentationQueueTargetCreateX11 /* VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 */ +}; + +boolean vlGetFuncFTAB(VdpFuncId function_id, void **func) +{ + assert(func); + if (function_id < VDP_FUNC_ID_BASE_WINSYS) { + if (function_id > 66) + return FALSE; + *func = ftab[function_id]; + } + else { + function_id -= VDP_FUNC_ID_BASE_WINSYS; + if (function_id > 0) + return FALSE; + *func = ftab_winsys[function_id]; + } + return *func != NULL; +} diff --git a/src/gallium/state_trackers/vdpau/htab.c b/src/gallium/state_trackers/vdpau/htab.c new file mode 100644 index 00000000000..20f5a171f19 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/htab.c @@ -0,0 +1,104 @@ +/************************************************************************** + * + * Copyright 2010 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <util/u_handle_table.h> +#include <os/os_thread.h> +#include "vdpau_private.h" + +#ifdef VL_HANDLES +static struct handle_table *htab = NULL; +pipe_static_mutex(htab_lock); +#endif + +boolean vlCreateHTAB(void) +{ +#ifdef VL_HANDLES + boolean ret; + /* Make sure handle table handles match VDPAU handles. */ + assert(sizeof(unsigned) <= sizeof(vlHandle)); + pipe_mutex_lock(htab_lock); + if (!htab) + htab = handle_table_create(); + ret = htab != NULL; + pipe_mutex_unlock(htab_lock); + return ret; +#else + return TRUE; +#endif +} + +void vlDestroyHTAB(void) +{ +#ifdef VL_HANDLES + pipe_mutex_lock(htab_lock); + if (htab) { + handle_table_destroy(htab); + htab = NULL; + } + pipe_mutex_unlock(htab_lock); +#endif +} + +vlHandle vlAddDataHTAB(void *data) +{ + assert(data); +#ifdef VL_HANDLES + vlHandle handle = 0; + pipe_mutex_lock(htab_lock); + if (htab) + handle = handle_table_add(htab, data); + pipe_mutex_unlock(htab_lock); + return handle; +#else + return (vlHandle)data; +#endif +} + +void* vlGetDataHTAB(vlHandle handle) +{ + assert(handle); +#ifdef VL_HANDLES + void *data = NULL; + pipe_mutex_lock(htab_lock); + if (htab) + data = handle_table_get(htab, handle); + pipe_mutex_unlock(htab_lock); + return data; +#else + return (void*)handle; +#endif +} + +void vlRemoveDataHTAB(vlHandle handle) +{ +#ifdef VL_HANDLES + pipe_mutex_lock(htab_lock); + if (htab) + handle_table_remove(htab, handle); + pipe_mutex_unlock(htab_lock); +#endif +} diff --git a/src/gallium/state_trackers/vdpau/mixer.c b/src/gallium/state_trackers/vdpau/mixer.c new file mode 100644 index 00000000000..d5187006bfc --- /dev/null +++ b/src/gallium/state_trackers/vdpau/mixer.c @@ -0,0 +1,233 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <vdpau/vdpau.h> + +#include <util/u_memory.h> +#include <util/u_debug.h> + +#include <vl/vl_csc.h> + +#include "vdpau_private.h" + +VdpStatus +vlVdpVideoMixerCreate(VdpDevice device, + uint32_t feature_count, + VdpVideoMixerFeature const *features, + uint32_t parameter_count, + VdpVideoMixerParameter const *parameters, + void const *const *parameter_values, + VdpVideoMixer *mixer) +{ + vlVdpVideoMixer *vmixer = NULL; + VdpStatus ret; + float csc[16]; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating VideoMixer\n"); + + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + vmixer = CALLOC(1, sizeof(vlVdpVideoMixer)); + if (!vmixer) + return VDP_STATUS_RESOURCES; + + vmixer->device = dev; + vl_compositor_init(&vmixer->compositor, dev->context->pipe); + + vl_csc_get_matrix + ( + debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? + VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601, + NULL, true, csc + ); + vl_compositor_set_csc_matrix(&vmixer->compositor, csc); + + /* + * TODO: Handle features and parameters + * */ + + *mixer = vlAddDataHTAB(vmixer); + if (*mixer == 0) { + ret = VDP_STATUS_ERROR; + goto no_handle; + } + + return VDP_STATUS_OK; +no_handle: + return ret; +} + +VdpStatus +vlVdpVideoMixerDestroy(VdpVideoMixer mixer) +{ + vlVdpVideoMixer *vmixer; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying VideoMixer\n"); + + vmixer = vlGetDataHTAB(mixer); + if (!vmixer) + return VDP_STATUS_INVALID_HANDLE; + + vl_compositor_cleanup(&vmixer->compositor); + + FREE(vmixer); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer, + uint32_t feature_count, + VdpVideoMixerFeature const *features, + VdpBool const *feature_enables) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Setting VideoMixer features\n"); + + if (!(features && feature_enables)) + return VDP_STATUS_INVALID_POINTER; + + vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); + if (!vmixer) + return VDP_STATUS_INVALID_HANDLE; + + /* + * TODO: Set features + * */ + + return VDP_STATUS_OK; +} + +VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, + VdpOutputSurface background_surface, + VdpRect const *background_source_rect, + VdpVideoMixerPictureStructure current_picture_structure, + uint32_t video_surface_past_count, + VdpVideoSurface const *video_surface_past, + VdpVideoSurface video_surface_current, + uint32_t video_surface_future_count, + VdpVideoSurface const *video_surface_future, + VdpRect const *video_source_rect, + VdpOutputSurface destination_surface, + VdpRect const *destination_rect, + VdpRect const *destination_video_rect, + uint32_t layer_count, + VdpLayer const *layers) +{ + vlVdpVideoMixer *vmixer; + vlVdpSurface *surf; + vlVdpOutputSurface *dst; + + vmixer = vlGetDataHTAB(mixer); + if (!vmixer) + return VDP_STATUS_INVALID_HANDLE; + + surf = vlGetDataHTAB(video_surface_current); + if (!surf) + return VDP_STATUS_INVALID_HANDLE; + + dst = vlGetDataHTAB(destination_surface); + if (!dst) + return VDP_STATUS_INVALID_HANDLE; + + 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); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer, + uint32_t attribute_count, + VdpVideoMixerAttribute const *attributes, + void const *const *attribute_values) +{ + if (!(attributes && attribute_values)) + return VDP_STATUS_INVALID_POINTER; + + vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); + if (!vmixer) + return VDP_STATUS_INVALID_HANDLE; + + /* + * TODO: Implement the function + * + * */ + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer, + uint32_t feature_count, + VdpVideoMixerFeature const *features, + VdpBool *feature_supports) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer, + uint32_t feature_count, + VdpVideoMixerFeature const *features, + VdpBool *feature_enables) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer, + uint32_t parameter_count, + VdpVideoMixerParameter const *parameters, + void *const *parameter_values) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer, + uint32_t attribute_count, + VdpVideoMixerAttribute const *attributes, + void *const *attribute_values) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpGenerateCSCMatrix(VdpProcamp *procamp, + VdpColorStandard standard, + VdpCSCMatrix *csc_matrix) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Generating CSCMatrix\n"); + if (!(csc_matrix && procamp)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_OK; +} diff --git a/src/gallium/state_trackers/vdpau/output.c b/src/gallium/state_trackers/vdpau/output.c new file mode 100644 index 00000000000..bc4b39ae75c --- /dev/null +++ b/src/gallium/state_trackers/vdpau/output.c @@ -0,0 +1,221 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <vdpau/vdpau.h> + +#include <util/u_debug.h> +#include <util/u_memory.h> +#include <util/u_sampler.h> + +#include "vdpau_private.h" + +VdpStatus +vlVdpOutputSurfaceCreate(VdpDevice device, + VdpRGBAFormat rgba_format, + uint32_t width, uint32_t height, + VdpOutputSurface *surface) +{ + struct pipe_context *pipe; + struct pipe_resource res_tmpl, *res; + struct pipe_sampler_view sv_templ; + struct pipe_surface surf_templ; + + vlVdpOutputSurface *vlsurface = NULL; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating output surface\n"); + if (!(width && height)) + return VDP_STATUS_INVALID_SIZE; + + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + pipe = dev->context->pipe; + if (!pipe) + return VDP_STATUS_INVALID_HANDLE; + + vlsurface = CALLOC(1, sizeof(vlVdpOutputSurface)); + if (!vlsurface) + return VDP_STATUS_RESOURCES; + + memset(&res_tmpl, 0, sizeof(res_tmpl)); + + res_tmpl.target = PIPE_TEXTURE_2D; + res_tmpl.format = FormatRGBAToPipe(rgba_format); + res_tmpl.width0 = width; + res_tmpl.height0 = height; + res_tmpl.depth0 = 1; + res_tmpl.array_size = 1; + res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + res_tmpl.usage = PIPE_USAGE_STATIC; + + res = pipe->screen->resource_create(pipe->screen, &res_tmpl); + if (!res) { + FREE(dev); + return VDP_STATUS_ERROR; + } + + memset(&sv_templ, 0, sizeof(sv_templ)); + u_sampler_view_default_template(&sv_templ, res, res->format); + + // as long as we don't have a background picture we don't want an alpha channel + sv_templ.swizzle_a = PIPE_SWIZZLE_ONE; + + vlsurface->sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ); + if (!vlsurface->sampler_view) { + pipe_resource_reference(&res, NULL); + FREE(dev); + return VDP_STATUS_ERROR; + } + + memset(&surf_templ, 0, sizeof(surf_templ)); + surf_templ.format = res->format; + surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + vlsurface->surface = pipe->create_surface(pipe, res, &surf_templ); + if (!vlsurface->surface) { + pipe_resource_reference(&res, NULL); + FREE(dev); + return VDP_STATUS_ERROR; + } + + *surface = vlAddDataHTAB(vlsurface); + if (*surface == 0) { + pipe_resource_reference(&res, NULL); + FREE(dev); + return VDP_STATUS_ERROR; + } + + pipe_resource_reference(&res, NULL); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpOutputSurfaceDestroy(VdpOutputSurface surface) +{ + vlVdpOutputSurface *vlsurface; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying output surface\n"); + + vlsurface = vlGetDataHTAB(surface); + if (!vlsurface) + return VDP_STATUS_INVALID_HANDLE; + + pipe_surface_reference(&vlsurface->surface, NULL); + pipe_sampler_view_reference(&vlsurface->sampler_view, NULL); + + vlRemoveDataHTAB(surface); + FREE(vlsurface); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpOutputSurfaceGetParameters(VdpOutputSurface surface, + VdpRGBAFormat *rgba_format, + uint32_t *width, uint32_t *height) +{ + vlVdpOutputSurface *vlsurface; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] getting surface parameters\n"); + + vlsurface = vlGetDataHTAB(surface); + if (!vlsurface) + return VDP_STATUS_INVALID_HANDLE; + + *rgba_format = PipeToFormatRGBA(vlsurface->sampler_view->texture->format); + *width = vlsurface->sampler_view->texture->width0; + *height = vlsurface->sampler_view->texture->height0; + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface, + VdpRect const *source_rect, + void *const *destination_data, + uint32_t const *destination_pitches) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfacePutBitsNative(VdpOutputSurface surface, + void const *const *source_data, + uint32_t const *source_pitches, + VdpRect const *destination_rect) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface, + VdpIndexedFormat source_indexed_format, + void const *const *source_data, + uint32_t const *source_pitch, + VdpRect const *destination_rect, + VdpColorTableFormat color_table_format, + void const *color_table) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface, + VdpYCbCrFormat source_ycbcr_format, + void const *const *source_data, + uint32_t const *source_pitches, + VdpRect const *destination_rect, + VdpCSCMatrix const *csc_matrix) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface, + VdpRect const *destination_rect, + VdpOutputSurface source_surface, + VdpRect const *source_rect, + VdpColor const *colors, + VdpOutputSurfaceRenderBlendState const *blend_state, + uint32_t flags) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface, + VdpRect const *destination_rect, + VdpBitmapSurface source_surface, + VdpRect const *source_rect, + VdpColor const *colors, + VdpOutputSurfaceRenderBlendState const *blend_state, + uint32_t flags) +{ + return VDP_STATUS_NO_IMPLEMENTATION; +} diff --git a/src/gallium/state_trackers/vdpau/preemption.c b/src/gallium/state_trackers/vdpau/preemption.c new file mode 100644 index 00000000000..fa70bb09cbc --- /dev/null +++ b/src/gallium/state_trackers/vdpau/preemption.c @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + #include <vdpau/vdpau.h> + + void vlVdpPreemptionCallback(VdpDevice device, void *context) + { + /* TODO: Implement preemption */ + } + + VdpStatus vlVdpPreemptionCallbackRegister(VdpDevice device, VdpPreemptionCallback callback, + void *context) + { + return VDP_STATUS_OK; + } diff --git a/src/gallium/state_trackers/vdpau/presentation.c b/src/gallium/state_trackers/vdpau/presentation.c new file mode 100644 index 00000000000..1176c7a30b7 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/presentation.c @@ -0,0 +1,223 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <stdio.h> + +#include <vdpau/vdpau.h> + +#include <util/u_debug.h> +#include <util/u_memory.h> + +#include "vdpau_private.h" + +VdpStatus +vlVdpPresentationQueueCreate(VdpDevice device, + VdpPresentationQueueTarget presentation_queue_target, + VdpPresentationQueue *presentation_queue) +{ + vlVdpPresentationQueue *pq = NULL; + VdpStatus ret; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating PresentationQueue\n"); + + if (!presentation_queue) + return VDP_STATUS_INVALID_POINTER; + + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target); + if (!pqt) + return VDP_STATUS_INVALID_HANDLE; + + if (dev != pqt->device) + return VDP_STATUS_HANDLE_DEVICE_MISMATCH; + + pq = CALLOC(1, sizeof(vlVdpPresentationQueue)); + if (!pq) + return VDP_STATUS_RESOURCES; + + pq->device = dev; + pq->drawable = pqt->drawable; + + if (!vl_compositor_init(&pq->compositor, dev->context->pipe)) { + ret = VDP_STATUS_ERROR; + goto no_compositor; + } + + *presentation_queue = vlAddDataHTAB(pq); + if (*presentation_queue == 0) { + ret = VDP_STATUS_ERROR; + goto no_handle; + } + + return VDP_STATUS_OK; +no_handle: +no_compositor: + FREE(pq); + return ret; +} + +VdpStatus +vlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue) +{ + vlVdpPresentationQueue *pq; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying PresentationQueue\n"); + + pq = vlGetDataHTAB(presentation_queue); + if (!pq) + return VDP_STATUS_INVALID_HANDLE; + + vl_compositor_cleanup(&pq->compositor); + + vlRemoveDataHTAB(presentation_queue); + FREE(pq); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue, + VdpColor *const background_color) +{ + vlVdpPresentationQueue *pq; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Setting Background Color\n"); + + if (!background_color) + return VDP_STATUS_INVALID_POINTER; + + pq = vlGetDataHTAB(presentation_queue); + if (!pq) + return VDP_STATUS_INVALID_HANDLE; + + vl_compositor_set_clear_color(&pq->compositor, (float*)background_color); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue, + VdpColor *const background_color) +{ + if (!background_color) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue, + VdpTime *current_time) +{ + if (!current_time) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue, + VdpOutputSurface surface, + uint32_t clip_width, + uint32_t clip_height, + VdpTime earliest_presentation_time) +{ + static int dump_window = -1; + + vlVdpPresentationQueue *pq; + vlVdpOutputSurface *surf; + struct pipe_surface *drawable_surface; + + pq = vlGetDataHTAB(presentation_queue); + if (!pq) + return VDP_STATUS_INVALID_HANDLE; + + drawable_surface = vl_drawable_surface_get(pq->device->context, pq->drawable); + if (!drawable_surface) + return VDP_STATUS_INVALID_HANDLE; + + surf = vlGetDataHTAB(surface); + if (!surf) + return VDP_STATUS_INVALID_HANDLE; + + 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); + + pq->device->context->pipe->screen->flush_frontbuffer + ( + pq->device->context->pipe->screen, + drawable_surface->texture, + 0, 0, + vl_contextprivate_get(pq->device->context, drawable_surface) + ); + + if(dump_window == -1) { + dump_window = debug_get_num_option("VDPAU_DUMP", 0); + } + + if(dump_window) { + static unsigned int framenum = 0; + char cmd[256]; + + sprintf(cmd, "xwd -id %d -out vdpau_frame_%08d.xwd", (int)pq->drawable, ++framenum); + if (system(cmd) != 0) + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Dumping surface %d failed.\n", surface); + } + + pipe_surface_reference(&drawable_surface, NULL); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue, + VdpOutputSurface surface, + VdpTime *first_presentation_time) +{ + if (!first_presentation_time) + return VDP_STATUS_INVALID_POINTER; + + //return VDP_STATUS_NO_IMPLEMENTATION; + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue, + VdpOutputSurface surface, + VdpPresentationQueueStatus *status, + VdpTime *first_presentation_time) +{ + if (!(status && first_presentation_time)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} diff --git a/src/gallium/state_trackers/vdpau/query.c b/src/gallium/state_trackers/vdpau/query.c new file mode 100644 index 00000000000..ec17e59118f --- /dev/null +++ b/src/gallium/state_trackers/vdpau/query.c @@ -0,0 +1,279 @@ +/************************************************************************** + * + * Copyright 2010 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include "vdpau_private.h" +#include <vl_winsys.h> +#include <assert.h> +#include <pipe/p_screen.h> +#include <pipe/p_defines.h> +#include <math.h> +#include <util/u_debug.h> + + +VdpStatus +vlVdpGetApiVersion(uint32_t *api_version) +{ + if (!api_version) + return VDP_STATUS_INVALID_POINTER; + + *api_version = 1; + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpGetInformationString(char const **information_string) +{ + if (!information_string) + return VDP_STATUS_INVALID_POINTER; + + *information_string = INFORMATION_STRING; + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoSurfaceQueryCapabilities(VdpDevice device, VdpChromaType surface_chroma_type, + VdpBool *is_supported, uint32_t *max_width, uint32_t *max_height) +{ + vlVdpDevice *dev; + struct pipe_screen *pscreen; + uint32_t max_2d_texture_level; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying video surfaces\n"); + + if (!(is_supported && max_width && max_height)) + return VDP_STATUS_INVALID_POINTER; + + dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + pscreen = dev->vscreen->pscreen; + if (!pscreen) + return VDP_STATUS_RESOURCES; + + /* XXX: Current limits */ + *is_supported = true; + if (surface_chroma_type != VDP_CHROMA_TYPE_420) + *is_supported = false; + + max_2d_texture_level = pscreen->get_param(pscreen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); + if (!max_2d_texture_level) + return VDP_STATUS_RESOURCES; + + /* I am not quite sure if it is max_2d_texture_level-1 or just max_2d_texture_level */ + *max_width = *max_height = pow(2,max_2d_texture_level-1); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities(VdpDevice device, VdpChromaType surface_chroma_type, + VdpYCbCrFormat bits_ycbcr_format, + VdpBool *is_supported) +{ + vlVdpDevice *dev; + struct pipe_screen *pscreen; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying get put video surfaces\n"); + + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + pscreen = dev->vscreen->pscreen; + if (!pscreen) + return VDP_STATUS_RESOURCES; + + *is_supported = pscreen->is_video_format_supported + ( + pscreen, + FormatYCBCRToPipe(bits_ycbcr_format), + PIPE_VIDEO_PROFILE_UNKNOWN + ); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpDecoderQueryCapabilities(VdpDevice device, VdpDecoderProfile profile, + VdpBool *is_supported, uint32_t *max_level, uint32_t *max_macroblocks, + uint32_t *max_width, uint32_t *max_height) +{ + vlVdpDevice *dev; + struct pipe_screen *pscreen; + enum pipe_video_profile p_profile; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying decoder\n"); + + if (!(is_supported && max_level && max_macroblocks && max_width && max_height)) + return VDP_STATUS_INVALID_POINTER; + + dev = vlGetDataHTAB(device); + if (!dev) + return VDP_STATUS_INVALID_HANDLE; + + pscreen = dev->vscreen->pscreen; + if (!pscreen) + return VDP_STATUS_RESOURCES; + + p_profile = ProfileToPipe(profile); + if (p_profile == PIPE_VIDEO_PROFILE_UNKNOWN) { + *is_supported = false; + return VDP_STATUS_OK; + } + + *is_supported = pscreen->get_video_param(pscreen, p_profile, PIPE_VIDEO_CAP_SUPPORTED); + if (*is_supported) { + *max_width = pscreen->get_video_param(pscreen, p_profile, PIPE_VIDEO_CAP_MAX_WIDTH); + *max_height = pscreen->get_video_param(pscreen, p_profile, PIPE_VIDEO_CAP_MAX_HEIGHT); + *max_level = 16; + *max_macroblocks = (*max_width/16)*(*max_height/16); + } else { + *max_width = 0; + *max_height = 0; + *max_level = 0; + *max_macroblocks = 0; + } + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpOutputSurfaceQueryCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format, + VdpBool *is_supported, uint32_t *max_width, uint32_t *max_height) +{ + if (!(is_supported && max_width && max_height)) + return VDP_STATUS_INVALID_POINTER; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying ouput surfaces\n"); + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfaceQueryGetPutBitsNativeCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format, + VdpBool *is_supported) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying output surfaces get put native cap\n"); + + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfaceQueryPutBitsIndexedCapabilities(VdpDevice device, + VdpRGBAFormat surface_rgba_format, + VdpIndexedFormat bits_indexed_format, + VdpColorTableFormat color_table_format, + VdpBool *is_supported) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying output surfaces get put indexed cap\n"); + + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpOutputSurfaceQueryPutBitsYCbCrCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format, + VdpYCbCrFormat bits_ycbcr_format, + VdpBool *is_supported) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying output surfaces put ycrcb cap\n"); + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpBitmapSurfaceQueryCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format, + VdpBool *is_supported, uint32_t *max_width, uint32_t *max_height) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying bitmap surfaces\n"); + if (!(is_supported && max_width && max_height)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerQueryFeatureSupport(VdpDevice device, VdpVideoMixerFeature feature, + VdpBool *is_supported) +{ + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Querying mixer feature support\n"); + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerQueryParameterSupport(VdpDevice device, VdpVideoMixerParameter parameter, + VdpBool *is_supported) +{ + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerQueryParameterValueRange(VdpDevice device, VdpVideoMixerParameter parameter, + void *min_value, void *max_value) +{ + if (!(min_value && max_value)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerQueryAttributeSupport(VdpDevice device, VdpVideoMixerAttribute attribute, + VdpBool *is_supported) +{ + if (!is_supported) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoMixerQueryAttributeValueRange(VdpDevice device, VdpVideoMixerAttribute attribute, + void *min_value, void *max_value) +{ + if (!(min_value && max_value)) + return VDP_STATUS_INVALID_POINTER; + + return VDP_STATUS_NO_IMPLEMENTATION; +} diff --git a/src/gallium/state_trackers/vdpau/surface.c b/src/gallium/state_trackers/vdpau/surface.c new file mode 100644 index 00000000000..d3f6b5d8bc5 --- /dev/null +++ b/src/gallium/state_trackers/vdpau/surface.c @@ -0,0 +1,210 @@ +/************************************************************************** + * + * Copyright 2010 Thomas Balling Sørensen. + * Copyright 2011 Christian König. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <pipe/p_state.h> + +#include <util/u_memory.h> +#include <util/u_debug.h> +#include <util/u_rect.h> + +#include "vdpau_private.h" + +VdpStatus +vlVdpVideoSurfaceCreate(VdpDevice device, VdpChromaType chroma_type, + uint32_t width, uint32_t height, + VdpVideoSurface *surface) +{ + vlVdpSurface *p_surf; + VdpStatus ret; + + VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating a surface\n"); + + if (!(width && height)) { + ret = VDP_STATUS_INVALID_SIZE; + goto inv_size; + } + + if (!vlCreateHTAB()) { + ret = VDP_STATUS_RESOURCES; + goto no_htab; + } + + p_surf = CALLOC(1, sizeof(vlVdpSurface)); + if (!p_surf) { + ret = VDP_STATUS_RESOURCES; + goto no_res; + } + + vlVdpDevice *dev = vlGetDataHTAB(device); + if (!dev) { + ret = VDP_STATUS_INVALID_HANDLE; + goto inv_device; + } + + p_surf->device = dev; + p_surf->video_buffer = dev->context->pipe->create_video_buffer + ( + dev->context->pipe, + PIPE_FORMAT_YV12, // most common used + ChromaToPipe(chroma_type), + width, height + ); + + *surface = vlAddDataHTAB(p_surf); + if (*surface == 0) { + ret = VDP_STATUS_ERROR; + goto no_handle; + } + + return VDP_STATUS_OK; + +no_handle: + p_surf->video_buffer->destroy(p_surf->video_buffer); + +inv_device: + FREE(p_surf); + +no_res: +no_htab: +inv_size: + return ret; +} + +VdpStatus +vlVdpVideoSurfaceDestroy(VdpVideoSurface surface) +{ + vlVdpSurface *p_surf; + + p_surf = (vlVdpSurface *)vlGetDataHTAB((vlHandle)surface); + if (!p_surf) + return VDP_STATUS_INVALID_HANDLE; + + if (p_surf->video_buffer) + p_surf->video_buffer->destroy(p_surf->video_buffer); + + FREE(p_surf); + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoSurfaceGetParameters(VdpVideoSurface surface, + VdpChromaType *chroma_type, + uint32_t *width, uint32_t *height) +{ + if (!(width && height && chroma_type)) + return VDP_STATUS_INVALID_POINTER; + + vlVdpSurface *p_surf = vlGetDataHTAB(surface); + if (!p_surf) + return VDP_STATUS_INVALID_HANDLE; + + *width = p_surf->video_buffer->width; + *height = p_surf->video_buffer->height; + *chroma_type = PipeToChroma(p_surf->video_buffer->chroma_format); + + return VDP_STATUS_OK; +} + +VdpStatus +vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface, + VdpYCbCrFormat destination_ycbcr_format, + void *const *destination_data, + uint32_t const *destination_pitches) +{ + if (!vlCreateHTAB()) + return VDP_STATUS_RESOURCES; + + vlVdpSurface *p_surf = vlGetDataHTAB(surface); + if (!p_surf) + return VDP_STATUS_INVALID_HANDLE; + + //if (!p_surf->psurface) + // return VDP_STATUS_RESOURCES; + + //return VDP_STATUS_OK; + return VDP_STATUS_NO_IMPLEMENTATION; +} + +VdpStatus +vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface, + VdpYCbCrFormat source_ycbcr_format, + void const *const *source_data, + uint32_t const *source_pitches) +{ + enum pipe_format pformat = FormatYCBCRToPipe(source_ycbcr_format); + struct pipe_context *pipe; + struct pipe_sampler_view **sampler_views; + unsigned i; + + if (!vlCreateHTAB()) + return VDP_STATUS_RESOURCES; + + vlVdpSurface *p_surf = vlGetDataHTAB(surface); + if (!p_surf) + return VDP_STATUS_INVALID_HANDLE; + + pipe = p_surf->device->context->pipe; + if (!pipe) + return VDP_STATUS_INVALID_HANDLE; + + if (p_surf->video_buffer == NULL || pformat != p_surf->video_buffer->buffer_format) { + assert(0); // TODO Recreate resource + return VDP_STATUS_NO_IMPLEMENTATION; + } + + sampler_views = p_surf->video_buffer->get_sampler_view_planes(p_surf->video_buffer); + if (!sampler_views) + return VDP_STATUS_RESOURCES; + + for (i = 0; i < 3; ++i) { //TODO put nr of planes into util format + struct pipe_sampler_view *sv = sampler_views[i ? i ^ 3 : 0]; + struct pipe_box dst_box = { 0, 0, 0, sv->texture->width0, sv->texture->height0, 1 }; + + struct pipe_transfer *transfer; + void *map; + + transfer = pipe->get_transfer(pipe, sv->texture, 0, PIPE_TRANSFER_WRITE, &dst_box); + if (!transfer) + return VDP_STATUS_RESOURCES; + + map = pipe->transfer_map(pipe, transfer); + if (map) { + util_copy_rect(map, sv->texture->format, transfer->stride, 0, 0, + dst_box.width, dst_box.height, + source_data[i], source_pitches[i], 0, 0); + + pipe->transfer_unmap(pipe, transfer); + } + + pipe->transfer_destroy(pipe, transfer); + } + + return VDP_STATUS_OK; +} diff --git a/src/gallium/state_trackers/vdpau/vdpau_private.h b/src/gallium/state_trackers/vdpau/vdpau_private.h new file mode 100644 index 00000000000..e5d945629fb --- /dev/null +++ b/src/gallium/state_trackers/vdpau/vdpau_private.h @@ -0,0 +1,361 @@ +/************************************************************************** + * + * Copyright 2010 Younes Manton & Thomas Balling Sørensen. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef VDPAU_PRIVATE_H +#define VDPAU_PRIVATE_H + +#include <assert.h> + +#include <vdpau/vdpau.h> +#include <vdpau/vdpau_x11.h> + +#include <pipe/p_compiler.h> +#include <pipe/p_video_decoder.h> + +#include <util/u_debug.h> +#include <vl/vl_compositor.h> + +#include <vl_winsys.h> + +#define INFORMATION G3DVL VDPAU Driver Shared Library version VER_MAJOR.VER_MINOR +#define QUOTEME(x) #x +#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) +{ + switch (vdpau_type) { + case VDP_CHROMA_TYPE_420: + return PIPE_VIDEO_CHROMA_FORMAT_420; + case VDP_CHROMA_TYPE_422: + return PIPE_VIDEO_CHROMA_FORMAT_422; + case VDP_CHROMA_TYPE_444: + return PIPE_VIDEO_CHROMA_FORMAT_444; + default: + assert(0); + } + + return -1; +} + +static inline VdpChromaType +PipeToChroma(enum pipe_video_chroma_format pipe_type) +{ + switch (pipe_type) { + case PIPE_VIDEO_CHROMA_FORMAT_420: + return VDP_CHROMA_TYPE_420; + case PIPE_VIDEO_CHROMA_FORMAT_422: + return VDP_CHROMA_TYPE_422; + case PIPE_VIDEO_CHROMA_FORMAT_444: + return VDP_CHROMA_TYPE_444; + default: + assert(0); + } + + return -1; +} + + +static inline enum pipe_format +FormatYCBCRToPipe(VdpYCbCrFormat vdpau_format) +{ + switch (vdpau_format) { + case VDP_YCBCR_FORMAT_NV12: + return PIPE_FORMAT_NV12; + case VDP_YCBCR_FORMAT_YV12: + return PIPE_FORMAT_YV12; + case VDP_YCBCR_FORMAT_UYVY: + return PIPE_FORMAT_UYVY; + case VDP_YCBCR_FORMAT_YUYV: + return PIPE_FORMAT_YUYV; + case VDP_YCBCR_FORMAT_Y8U8V8A8: /* Not defined in p_format.h */ + return 0; + case VDP_YCBCR_FORMAT_V8U8Y8A8: + return PIPE_FORMAT_VUYA; + default: + assert(0); + } + + return -1; +} + +static inline VdpYCbCrFormat +PipeToFormatYCBCR(enum pipe_format p_format) +{ + switch (p_format) { + case PIPE_FORMAT_NV12: + return VDP_YCBCR_FORMAT_NV12; + case PIPE_FORMAT_YV12: + return VDP_YCBCR_FORMAT_YV12; + case PIPE_FORMAT_UYVY: + return VDP_YCBCR_FORMAT_UYVY; + case PIPE_FORMAT_YUYV: + return VDP_YCBCR_FORMAT_YUYV; + //case PIPE_FORMAT_YUVA: + // return VDP_YCBCR_FORMAT_Y8U8V8A8; + case PIPE_FORMAT_VUYA: + return VDP_YCBCR_FORMAT_V8U8Y8A8; + default: + assert(0); + } + + return -1; +} + +static inline enum pipe_format +FormatRGBAToPipe(VdpRGBAFormat vdpau_format) +{ + switch (vdpau_format) { + case VDP_RGBA_FORMAT_A8: + return PIPE_FORMAT_A8_UNORM; + case VDP_RGBA_FORMAT_B10G10R10A2: + return PIPE_FORMAT_B10G10R10A2_UNORM; + case VDP_RGBA_FORMAT_B8G8R8A8: + return PIPE_FORMAT_B8G8R8A8_UNORM; + case VDP_RGBA_FORMAT_R10G10B10A2: + return PIPE_FORMAT_R10G10B10A2_UNORM; + case VDP_RGBA_FORMAT_R8G8B8A8: + return PIPE_FORMAT_R8G8B8A8_UNORM; + default: + assert(0); + } + + return -1; +} + +static inline VdpRGBAFormat +PipeToFormatRGBA(enum pipe_format p_format) +{ + switch (p_format) { + case PIPE_FORMAT_A8_UNORM: + return VDP_RGBA_FORMAT_A8; + case PIPE_FORMAT_B10G10R10A2_UNORM: + return VDP_RGBA_FORMAT_B10G10R10A2; + case PIPE_FORMAT_B8G8R8A8_UNORM: + return VDP_RGBA_FORMAT_B8G8R8A8; + case PIPE_FORMAT_R10G10B10A2_UNORM: + return VDP_RGBA_FORMAT_R10G10B10A2; + case PIPE_FORMAT_R8G8B8A8_UNORM: + return VDP_RGBA_FORMAT_R8G8B8A8; + default: + assert(0); + } + + return -1; +} + +static inline enum pipe_video_profile +ProfileToPipe(VdpDecoderProfile vdpau_profile) +{ + switch (vdpau_profile) { + case VDP_DECODER_PROFILE_MPEG1: + return PIPE_VIDEO_PROFILE_MPEG1; + case VDP_DECODER_PROFILE_MPEG2_SIMPLE: + return PIPE_VIDEO_PROFILE_MPEG2_SIMPLE; + case VDP_DECODER_PROFILE_MPEG2_MAIN: + return PIPE_VIDEO_PROFILE_MPEG2_MAIN; + case VDP_DECODER_PROFILE_H264_BASELINE: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE; + case VDP_DECODER_PROFILE_H264_MAIN: /* Not defined in p_format.h */ + return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN; + case VDP_DECODER_PROFILE_H264_HIGH: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH; + default: + return PIPE_VIDEO_PROFILE_UNKNOWN; + } +} + +static inline VdpDecoderProfile +PipeToProfile(enum pipe_video_profile p_profile) +{ + switch (p_profile) { + case PIPE_VIDEO_PROFILE_MPEG1: + return VDP_DECODER_PROFILE_MPEG1; + case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE: + return VDP_DECODER_PROFILE_MPEG2_SIMPLE; + case PIPE_VIDEO_PROFILE_MPEG2_MAIN: + return VDP_DECODER_PROFILE_MPEG2_MAIN; + case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE: + return VDP_DECODER_PROFILE_H264_BASELINE; + case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: /* Not defined in p_format.h */ + return VDP_DECODER_PROFILE_H264_MAIN; + case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: + return VDP_DECODER_PROFILE_H264_HIGH; + default: + assert(0); + return -1; + } +} + +typedef struct +{ + struct vl_screen *vscreen; + struct vl_context *context; +} vlVdpDevice; + +typedef struct +{ + vlVdpDevice *device; + Drawable drawable; +} vlVdpPresentationQueueTarget; + +typedef struct +{ + vlVdpDevice *device; + Drawable drawable; + struct vl_compositor compositor; +} vlVdpPresentationQueue; + +typedef struct +{ + vlVdpDevice *device; + struct vl_compositor compositor; +} vlVdpVideoMixer; + +typedef struct +{ + vlVdpDevice *device; + struct pipe_video_buffer *video_buffer; +} vlVdpSurface; + +typedef struct +{ + vlVdpDevice *device; + struct pipe_surface *surface; + struct pipe_sampler_view *sampler_view; +} vlVdpOutputSurface; + +typedef struct +{ + vlVdpDevice *device; + struct pipe_video_decoder *decoder; + struct pipe_video_decode_buffer *buffer[VL_NUM_DECODE_BUFFERS]; + unsigned cur_buffer; +} vlVdpDecoder; + +typedef uint32_t vlHandle; + +boolean vlCreateHTAB(void); +void vlDestroyHTAB(void); +vlHandle vlAddDataHTAB(void *data); +void* vlGetDataHTAB(vlHandle handle); +void vlRemoveDataHTAB(vlHandle handle); + +boolean vlGetFuncFTAB(VdpFuncId function_id, void **func); + +/* Public functions */ +VdpDeviceCreateX11 vdp_imp_device_create_x11; +VdpPresentationQueueTargetCreateX11 vlVdpPresentationQueueTargetCreateX11; + +/* Internal function pointers */ +VdpGetErrorString vlVdpGetErrorString; +VdpDeviceDestroy vlVdpDeviceDestroy; +VdpGetProcAddress vlVdpGetProcAddress; +VdpGetApiVersion vlVdpGetApiVersion; +VdpGetInformationString vlVdpGetInformationString; +VdpVideoSurfaceQueryCapabilities vlVdpVideoSurfaceQueryCapabilities; +VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities; +VdpDecoderQueryCapabilities vlVdpDecoderQueryCapabilities; +VdpOutputSurfaceQueryCapabilities vlVdpOutputSurfaceQueryCapabilities; +VdpOutputSurfaceQueryGetPutBitsNativeCapabilities vlVdpOutputSurfaceQueryGetPutBitsNativeCapabilities; +VdpOutputSurfaceQueryPutBitsIndexedCapabilities vlVdpOutputSurfaceQueryPutBitsIndexedCapabilities; +VdpOutputSurfaceQueryPutBitsYCbCrCapabilities vlVdpOutputSurfaceQueryPutBitsYCbCrCapabilities; +VdpBitmapSurfaceQueryCapabilities vlVdpBitmapSurfaceQueryCapabilities; +VdpVideoMixerQueryFeatureSupport vlVdpVideoMixerQueryFeatureSupport; +VdpVideoMixerQueryParameterSupport vlVdpVideoMixerQueryParameterSupport; +VdpVideoMixerQueryParameterValueRange vlVdpVideoMixerQueryParameterValueRange; +VdpVideoMixerQueryAttributeSupport vlVdpVideoMixerQueryAttributeSupport; +VdpVideoMixerQueryAttributeValueRange vlVdpVideoMixerQueryAttributeValueRange; +VdpVideoSurfaceCreate vlVdpVideoSurfaceCreate; +VdpVideoSurfaceDestroy vlVdpVideoSurfaceDestroy; +VdpVideoSurfaceGetParameters vlVdpVideoSurfaceGetParameters; +VdpVideoSurfaceGetBitsYCbCr vlVdpVideoSurfaceGetBitsYCbCr; +VdpVideoSurfacePutBitsYCbCr vlVdpVideoSurfacePutBitsYCbCr; +VdpDecoderCreate vlVdpDecoderCreate; +VdpDecoderDestroy vlVdpDecoderDestroy; +VdpDecoderGetParameters vlVdpDecoderGetParameters; +VdpDecoderRender vlVdpDecoderRender; +VdpOutputSurfaceCreate vlVdpOutputSurfaceCreate; +VdpOutputSurfaceDestroy vlVdpOutputSurfaceDestroy; +VdpOutputSurfaceGetParameters vlVdpOutputSurfaceGetParameters; +VdpOutputSurfaceGetBitsNative vlVdpOutputSurfaceGetBitsNative; +VdpOutputSurfacePutBitsNative vlVdpOutputSurfacePutBitsNative; +VdpOutputSurfacePutBitsIndexed vlVdpOutputSurfacePutBitsIndexed; +VdpOutputSurfacePutBitsYCbCr vlVdpOutputSurfacePutBitsYCbCr; +VdpOutputSurfaceRenderOutputSurface vlVdpOutputSurfaceRenderOutputSurface; +VdpOutputSurfaceRenderBitmapSurface vlVdpOutputSurfaceRenderBitmapSurface; +VdpBitmapSurfaceCreate vlVdpBitmapSurfaceCreate; +VdpBitmapSurfaceDestroy vlVdpBitmapSurfaceDestroy; +VdpBitmapSurfaceGetParameters vlVdpBitmapSurfaceGetParameters; +VdpBitmapSurfacePutBitsNative vlVdpBitmapSurfacePutBitsNative; +VdpPresentationQueueTargetDestroy vlVdpPresentationQueueTargetDestroy; +VdpPresentationQueueCreate vlVdpPresentationQueueCreate; +VdpPresentationQueueDestroy vlVdpPresentationQueueDestroy; +VdpPresentationQueueSetBackgroundColor vlVdpPresentationQueueSetBackgroundColor; +VdpPresentationQueueGetBackgroundColor vlVdpPresentationQueueGetBackgroundColor; +VdpPresentationQueueGetTime vlVdpPresentationQueueGetTime; +VdpPresentationQueueDisplay vlVdpPresentationQueueDisplay; +VdpPresentationQueueBlockUntilSurfaceIdle vlVdpPresentationQueueBlockUntilSurfaceIdle; +VdpPresentationQueueQuerySurfaceStatus vlVdpPresentationQueueQuerySurfaceStatus; +VdpPreemptionCallback vlVdpPreemptionCallback; +VdpPreemptionCallbackRegister vlVdpPreemptionCallbackRegister; +VdpVideoMixerSetFeatureEnables vlVdpVideoMixerSetFeatureEnables; +VdpVideoMixerCreate vlVdpVideoMixerCreate; +VdpVideoMixerRender vlVdpVideoMixerRender; +VdpVideoMixerSetAttributeValues vlVdpVideoMixerSetAttributeValues; +VdpVideoMixerGetFeatureSupport vlVdpVideoMixerGetFeatureSupport; +VdpVideoMixerGetFeatureEnables vlVdpVideoMixerGetFeatureEnables; +VdpVideoMixerGetParameterValues vlVdpVideoMixerGetParameterValues; +VdpVideoMixerGetAttributeValues vlVdpVideoMixerGetAttributeValues; +VdpVideoMixerDestroy vlVdpVideoMixerDestroy; +VdpGenerateCSCMatrix vlVdpGenerateCSCMatrix; + +#define VDPAU_OUT 0 +#define VDPAU_ERR 1 +#define VDPAU_WARN 2 +#define VDPAU_TRACE 3 + +static inline void VDPAU_MSG(unsigned int level, const char *fmt, ...) +{ + static int debug_level = -1; + + if (debug_level == -1) { + debug_level = MAX2(debug_get_num_option("VDPAU_DEBUG", 0), 0); + } + + if (level <= debug_level) { + va_list ap; + va_start(ap, fmt); + _debug_vprintf(fmt, ap); + va_end(ap); + } +} + +#endif // VDPAU_PRIVATE_H diff --git a/src/gallium/state_trackers/vega/vg_context.h b/src/gallium/state_trackers/vega/vg_context.h index 71491a5aa22..d91ee9797f1 100644 --- a/src/gallium/state_trackers/vega/vg_context.h +++ b/src/gallium/state_trackers/vega/vg_context.h @@ -65,6 +65,8 @@ struct st_framebuffer { enum st_attachment_type strb_att; void *privateData; + int32_t stamp; + int32_t iface_stamp; }; enum vg_object_type { @@ -105,7 +107,6 @@ struct vg_context VGErrorCode _error; struct st_framebuffer *draw_buffer; - int32_t draw_buffer_invalid; struct cso_hash *owned_objects[VG_OBJECT_LAST]; @@ -129,6 +130,8 @@ struct vg_context struct vg_paint *default_paint; struct blit_state *blit; + + int32_t draw_stamp; }; diff --git a/src/gallium/state_trackers/vega/vg_manager.c b/src/gallium/state_trackers/vega/vg_manager.c index eeea68677de..dec1581fb84 100644 --- a/src/gallium/state_trackers/vega/vg_manager.c +++ b/src/gallium/state_trackers/vega/vg_manager.c @@ -106,35 +106,38 @@ vg_manager_validate_framebuffer(struct vg_context *ctx) { struct st_framebuffer *stfb = ctx->draw_buffer; struct pipe_resource *pt; + int32_t new_stamp; /* no binding surface */ if (!stfb) return; - if (!p_atomic_read(&ctx->draw_buffer_invalid)) - return; + new_stamp = p_atomic_read(&stfb->iface->stamp); + if (stfb->iface_stamp != new_stamp) { + do { + /* validate the fb */ + if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, + 1, &pt) || !pt) + return; - /* validate the fb */ - if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt) - return; + stfb->iface_stamp = new_stamp; + new_stamp = p_atomic_read(&stfb->iface->stamp); - p_atomic_set(&ctx->draw_buffer_invalid, FALSE); + } while (stfb->iface_stamp != new_stamp); - if (vg_context_update_color_rb(ctx, pt) || - stfb->width != pt->width0 || - stfb->height != pt->height0) - ctx->state.dirty |= FRAMEBUFFER_DIRTY; + if (vg_context_update_color_rb(ctx, pt) || + stfb->width != pt->width0 || + stfb->height != pt->height0) + ++stfb->stamp; - stfb->width = pt->width0; - stfb->height = pt->height0; -} + stfb->width = pt->width0; + stfb->height = pt->height0; + } -static void -vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi, - struct st_framebuffer_iface *stfbi) -{ - struct vg_context *ctx = (struct vg_context *) stctxi; - p_atomic_set(&ctx->draw_buffer_invalid, TRUE); + if (ctx->draw_stamp != stfb->stamp) { + ctx->state.dirty |= FRAMEBUFFER_DIRTY; + ctx->draw_stamp = stfb->stamp; + } } static void @@ -187,8 +190,6 @@ vg_api_create_context(struct st_api *stapi, struct st_manager *smapi, ctx->iface.destroy = vg_context_destroy; - ctx->iface.notify_invalid_framebuffer = - vg_context_notify_invalid_framebuffer; ctx->iface.flush = vg_context_flush; ctx->iface.teximage = NULL; @@ -266,8 +267,6 @@ vg_context_bind_framebuffers(struct st_context_iface *stctxi, if (stdrawi != streadi) return FALSE; - p_atomic_set(&ctx->draw_buffer_invalid, TRUE); - strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID; if (ctx->draw_buffer) { @@ -313,11 +312,14 @@ vg_context_bind_framebuffers(struct st_context_iface *stctxi, stfb->width = 0; stfb->height = 0; stfb->strb_att = strb_att; + stfb->stamp = 1; + stfb->iface_stamp = p_atomic_read(&stdrawi->stamp) - 1; ctx->draw_buffer = stfb; } ctx->draw_buffer->iface = stdrawi; + ctx->draw_stamp = ctx->draw_buffer->stamp - 1; return TRUE; } diff --git a/src/gallium/state_trackers/wgl/stw_context.c b/src/gallium/state_trackers/wgl/stw_context.c index 5608d4f4ce7..c2839fe815f 100644 --- a/src/gallium/state_trackers/wgl/stw_context.c +++ b/src/gallium/state_trackers/wgl/stw_context.c @@ -31,6 +31,7 @@ #include "pipe/p_context.h" #include "pipe/p_state.h" #include "util/u_memory.h" +#include "util/u_atomic.h" #include "state_tracker/st_api.h" #include "stw_icd.h" @@ -361,10 +362,7 @@ stw_flush_current_locked( struct stw_framebuffer *fb ) void stw_notify_current_locked( struct stw_framebuffer *fb ) { - struct stw_context *ctx = stw_current_context(); - - if (ctx && ctx->current_framebuffer == fb) - ctx->st->notify_invalid_framebuffer(ctx->st, fb->stfb); + p_atomic_inc(&fb->stfb->stamp); } /** diff --git a/src/gallium/state_trackers/wgl/stw_ext_pbuffer.c b/src/gallium/state_trackers/wgl/stw_ext_pbuffer.c index 424d8daccb3..c7273f26545 100644 --- a/src/gallium/state_trackers/wgl/stw_ext_pbuffer.c +++ b/src/gallium/state_trackers/wgl/stw_ext_pbuffer.c @@ -268,7 +268,7 @@ wglQueryPbufferARB(HPBUFFERARB hPbuffer, *piValue = fb->width; return TRUE; case WGL_PBUFFER_HEIGHT_ARB: - *piValue = fb->width; + *piValue = fb->height; return TRUE; case WGL_PBUFFER_LOST_ARB: /* We assume that no content is ever lost due to display mode change */ diff --git a/src/gallium/state_trackers/wgl/stw_st.c b/src/gallium/state_trackers/wgl/stw_st.c index 9174533fc06..28c93f4fb57 100644 --- a/src/gallium/state_trackers/wgl/stw_st.c +++ b/src/gallium/state_trackers/wgl/stw_st.c @@ -27,6 +27,7 @@ #include "util/u_memory.h" #include "util/u_inlines.h" +#include "util/u_atomic.h" #include "state_tracker/st_gl_api.h" /* for st_gl_api_create */ #include "stw_st.h" @@ -196,6 +197,7 @@ stw_st_create_framebuffer(struct stw_framebuffer *fb) stwfb->stvis = fb->pfi->stvis; stwfb->base.visual = &stwfb->stvis; + p_atomic_set(&stwfb->base.stamp, 1); stwfb->base.flush_front = stw_st_framebuffer_flush_front; stwfb->base.validate = stw_st_framebuffer_validate; diff --git a/src/gallium/state_trackers/xa/Makefile b/src/gallium/state_trackers/xa/Makefile new file mode 100644 index 00000000000..d95f9382630 --- /dev/null +++ b/src/gallium/state_trackers/xa/Makefile @@ -0,0 +1,67 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +##### MACROS ##### + +XA_MAJOR = 0 +XA_MINOR = 4 +XA_TINY = 0 +XA_CFLAGS = -g -fPIC -Wall + +XA_INCLUDES= -I$(TOP)/src/gallium/ \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/winsys \ + -I$(TOP)/src/gallium/drivers + +XA_LIB = xatracker +XA_LIB_NAME = lib$(XA_LIB).o +XA_LIB_DEPS = + +COMMON_GALLIUM_SOURCES= + +SOURCES = \ + xa_tracker.c \ + xa_context.c \ + xa_renderer.c \ + xa_tgsi.c \ + xa_yuv.c \ + xa_composite.c +OBJECTS = $(SOURCES:.c=.o) + +##### RULES ##### + +.c.o: + $(CC) -c $(XA_CFLAGS) $(XA_INCLUDES) $< + + +##### TARGETS ##### + +default: $(XA_LIB_NAME) + + +# Make the library +$(XA_LIB_NAME): depend $(OBJECTS) + $(CC) -r -nostdlib -o $(XA_LIB_NAME) $(OBJECTS) + +install: FORCE + +clean: + -rm -f *.o *~ + -rm -f *.lo + -rm -f *.la + -rm -f *.pc + -rm -rf .libs + -rm -f depend depend.bak + + +depend: $(SOURCES) + @ echo "running $(MKDEP)" + @ rm -f depend + @ touch depend + @ $(MKDEP) $(MKDEP_OPTIONS) -I$(TOP)/include $(XA_INCLUDES) $(SOURCES) \ + > /dev/null + +-include depend + +FORCE: diff --git a/src/gallium/state_trackers/xa/README b/src/gallium/state_trackers/xa/README new file mode 100644 index 00000000000..1f08861588c --- /dev/null +++ b/src/gallium/state_trackers/xa/README @@ -0,0 +1,72 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +The XA state tracker is intended as a versioned interface to gallium for +xorg driver writers. Initially it's mostly based on Zack Rusin's +composite / video work for the Xorg state tracker. + +The motivation behind this state tracker is that the Xorg state tracker has +a number of interfaces to work with: + +1) The Xorg sdk (versioned) +2) Gallium3D (not versioned) +3) KMS modesetting (versioned) +4) Driver-private (hopefully versioned) + +Since Gallium3D is not versioned, the Xorg state tracker needs to be compiled +with Gallium, but it's really beneficial to be able to compile xorg drivers +standalone. + +Therefore the xa state tracker is intended to supply the following +functionality: + +1) Versioning. +2) Surface functionality (creation and copying for a basic dri2 implementation) +3) YUV blits for textured Xv. +4) Solid fills without ROP functionality. +5) Copies with format conversion and - reinterpretation but without ROP +6) Xrender- type compositing for general acceleration. + + +The first user will be the vmwgfx xorg driver. When there are more users, +we need to be able to load the appropriate gallium pipe driver, and we +should investigate sharing the loadig mechanism with the EGL state tracker. + +IMPORTANT: +Version compatibilities: +While this library remains OUTSIDE any mesa release branch, +and the major version number is still 0. Any minor bump should be viewed as +an incompatibility event, and any user of this library should test for that +and refuse to use the library if minor versions differ. +As soon as the library enters a mesa release branch, if not earlier, major +will be bumped to 1, and normal incompatibility rules (major bump) +will be followed. +It is allowed to add function interfaces while only bumping minor. Any +user that uses these function interfaces must therefore use lazy symbol +lookups and test minor for compatibility before using such a function. diff --git a/src/gallium/state_trackers/xa/xa-indent b/src/gallium/state_trackers/xa/xa-indent new file mode 100755 index 00000000000..1972e53226f --- /dev/null +++ b/src/gallium/state_trackers/xa/xa-indent @@ -0,0 +1,3 @@ +# +indent --linux-style -i4 -ip4 -bad -bap -psl $* + diff --git a/src/gallium/state_trackers/xa/xa_composite.c b/src/gallium/state_trackers/xa/xa_composite.c new file mode 100644 index 00000000000..347fe0cd379 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_composite.c @@ -0,0 +1,530 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#include "xa_composite.h" +#include "xa_context.h" +#include "xa_priv.h" +#include "cso_cache/cso_context.h" +#include "util/u_sampler.h" +#include "util/u_inlines.h" + + +/*XXX also in Xrender.h but the including it here breaks compilition */ +#define XFixedToDouble(f) (((double) (f)) / 65536.) + +struct xa_composite_blend { + enum xa_composite_op op : 8; + + unsigned alpha_dst : 4; + unsigned alpha_src : 4; + + unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */ + unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */ +}; + +#define XA_BLEND_OP_OVER 3 +static const struct xa_composite_blend xa_blends[] = { + { xa_op_clear, + 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO}, + { xa_op_src, + 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO}, + { xa_op_dst, + 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE}, + { xa_op_over, + 0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { xa_op_over_reverse, + 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE}, + { xa_op_in, + 1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, + { xa_op_in_reverse, + 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA}, + { xa_op_out, + 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO}, + { xa_op_out_reverse, + 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { xa_op_atop, + 1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { xa_op_atop_reverse, + 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA}, + { xa_op_xor, + 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA}, + { xa_op_add, + 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE}, +}; + + +/* + * The alpha value stored in a luminance texture is read by the + * hardware as color. + */ +static unsigned +xa_convert_blend_for_luminance(unsigned factor) +{ + switch(factor) { + case PIPE_BLENDFACTOR_DST_ALPHA: + return PIPE_BLENDFACTOR_DST_COLOR; + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + return PIPE_BLENDFACTOR_INV_DST_COLOR; + default: + break; + } + return factor; +} + + +static boolean +blend_for_op(struct xa_composite_blend *blend, + enum xa_composite_op op, + struct xa_picture *src_pic, + struct xa_picture *mask_pic, + struct xa_picture *dst_pic) +{ + const int num_blends = + sizeof(xa_blends)/sizeof(struct xa_composite_blend); + int i; + boolean supported = FALSE; + + /* + * Temporarily disable component alpha since it appears buggy. + */ + if (src_pic->component_alpha || + (mask_pic && mask_pic->component_alpha)) + return FALSE; + + /* + * our default in case something goes wrong + */ + *blend = xa_blends[XA_BLEND_OP_OVER]; + + for (i = 0; i < num_blends; ++i) { + if (xa_blends[i].op == op) { + *blend = xa_blends[i]; + supported = TRUE; + } + } + + if (!dst_pic->srf) + return supported; + + if (dst_pic->srf->tex->format == PIPE_FORMAT_L8_UNORM) { + blend->rgb_src = xa_convert_blend_for_luminance(blend->rgb_src); + blend->rgb_dst = xa_convert_blend_for_luminance(blend->rgb_dst); + } + + /* + * If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. + */ + + if (xa_format_a(dst_pic->pict_format) == 0 && blend->alpha_dst) { + if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA) + blend->rgb_src = PIPE_BLENDFACTOR_ONE; + else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA) + blend->rgb_src = PIPE_BLENDFACTOR_ZERO; + } + + /* + * If the source alpha is being used, then we should only be in a case where + * the source blend factor is 0, and the source blend value is the mask + * channels multiplied by the source picture's alpha. + */ + if (mask_pic && mask_pic->component_alpha && + xa_format_rgb(mask_pic->pict_format) && + blend->alpha_src) { + if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) { + blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR; + } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) { + blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR; + } + } + + return supported; +} + + +static INLINE int +xa_repeat_to_gallium(int mode) +{ + switch(mode) { + case xa_wrap_clamp_to_border: + return PIPE_TEX_WRAP_CLAMP_TO_BORDER; + case xa_wrap_repeat: + return PIPE_TEX_WRAP_REPEAT; + case xa_wrap_mirror_repeat: + return PIPE_TEX_WRAP_MIRROR_REPEAT; + case xa_wrap_clamp_to_edge: + return PIPE_TEX_WRAP_CLAMP_TO_EDGE; + default: + break; + } + return PIPE_TEX_WRAP_REPEAT; +} + +static INLINE boolean +xa_filter_to_gallium(int xrender_filter, int *out_filter) +{ + + switch (xrender_filter) { + case xa_filter_nearest: + *out_filter = PIPE_TEX_FILTER_NEAREST; + break; + case xa_filter_linear: + *out_filter = PIPE_TEX_FILTER_LINEAR; + break; + default: + *out_filter = PIPE_TEX_FILTER_NEAREST; + return FALSE; + } + return TRUE; +} + +static int +xa_is_filter_accelerated(struct xa_picture *pic) +{ + int filter; + if (pic && !xa_filter_to_gallium(pic->filter, &filter)) + return 0; + return 1; +} + +int +xa_composite_check_accelerated(const struct xa_composite *comp) +{ + struct xa_composite_blend blend; + struct xa_picture *src_pic = comp->src; + + if (!xa_is_filter_accelerated(src_pic) || + !xa_is_filter_accelerated(comp->mask)) { + return -XA_ERR_INVAL; + } + + + if (src_pic->src_pict) { + if (src_pic->src_pict->type != xa_src_pict_solid_fill) + return -XA_ERR_INVAL; + } + + if (blend_for_op(&blend, comp->op, comp->src, comp->mask, comp->dst)) { + struct xa_picture *mask = comp->mask; + if (mask && mask->component_alpha && + xa_format_rgb(mask->pict_format)) { + if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) { + return -XA_ERR_INVAL; + } + } + + return XA_ERR_NONE; + } + return -XA_ERR_INVAL; +} + +static int +bind_composite_blend_state(struct xa_context *ctx, + const struct xa_composite *comp) +{ + struct xa_composite_blend blend_opt; + struct pipe_blend_state blend; + + if (!blend_for_op(&blend_opt, comp->op, comp->src, comp->mask, comp->dst)) + return -XA_ERR_INVAL; + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.rt[0].blend_enable = 1; + blend.rt[0].colormask = PIPE_MASK_RGBA; + + blend.rt[0].rgb_src_factor = blend_opt.rgb_src; + blend.rt[0].alpha_src_factor = blend_opt.rgb_src; + blend.rt[0].rgb_dst_factor = blend_opt.rgb_dst; + blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst; + + cso_set_blend(ctx->cso, &blend); + return XA_ERR_NONE; +} + +static unsigned int +picture_format_fixups(struct xa_picture *src_pic, + int mask) +{ + boolean set_alpha = FALSE; + boolean swizzle = FALSE; + unsigned ret = 0; + struct xa_surface *src = src_pic->srf; + enum xa_formats src_hw_format, src_pic_format; + enum xa_surface_type src_hw_type, src_pic_type; + + if (!src) + return 0; + + src_hw_format = xa_surface_format(src); + src_pic_format = src_pic->pict_format; + + set_alpha = (xa_format_type_is_color(src_pic_format) && + xa_format_a(src_pic_format) == 0); + + if (set_alpha) + ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA; + + if (src_hw_format == src_pic_format) { + if (src->tex->format == PIPE_FORMAT_L8_UNORM) + return ((mask) ? FS_MASK_LUMINANCE : FS_SRC_LUMINANCE); + + return ret; + } + + src_hw_type = xa_format_type(src_hw_format); + src_pic_type = xa_format_type(src_pic_format); + + swizzle = ((src_hw_type == xa_type_argb && + src_pic_type == xa_type_abgr) || + ((src_hw_type == xa_type_abgr && + src_pic_type == xa_type_argb))); + + if (!swizzle && (src_hw_type != src_pic_type)) + return ret; + + if (swizzle) + ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB; + + return ret; +} + +static int +bind_shaders(struct xa_context *ctx, const struct xa_composite *comp) +{ + unsigned vs_traits = 0, fs_traits = 0; + struct xa_shader shader; + struct xa_picture *src_pic = comp->src; + struct xa_picture *mask_pic = comp->mask; + + ctx->has_solid_color = FALSE; + + if (src_pic) { + if (src_pic->wrap == xa_wrap_clamp_to_border && src_pic->has_transform) + fs_traits |= FS_SRC_REPEAT_NONE; + + if (src_pic->src_pict) { + if (src_pic->src_pict->type == xa_src_pict_solid_fill) { + fs_traits |= FS_SOLID_FILL; + vs_traits |= VS_SOLID_FILL; + xa_pixel_to_float4(src_pic->src_pict->solid_fill.color, + ctx->solid_color); + ctx->has_solid_color = TRUE; + } + } else { + fs_traits |= FS_COMPOSITE; + vs_traits |= VS_COMPOSITE; + } + + fs_traits |= picture_format_fixups(src_pic, 0); + } + + if (mask_pic) { + vs_traits |= VS_MASK; + fs_traits |= FS_MASK; + if (mask_pic->wrap == xa_wrap_clamp_to_border && + mask_pic->has_transform) + fs_traits |= FS_MASK_REPEAT_NONE; + + if (mask_pic->component_alpha) { + struct xa_composite_blend blend; + if (!blend_for_op(&blend, comp->op, src_pic, mask_pic, NULL)) + return -XA_ERR_INVAL; + + if (blend.alpha_src) { + fs_traits |= FS_CA_SRCALPHA; + } else + fs_traits |= FS_CA_FULL; + } + + fs_traits |= picture_format_fixups(mask_pic, 1); + } + + if (ctx->dst->srf->format == PIPE_FORMAT_L8_UNORM) + fs_traits |= FS_DST_LUMINANCE; + + shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(ctx->cso, shader.vs); + cso_set_fragment_shader_handle(ctx->cso, shader.fs); + return XA_ERR_NONE; +} + +static void +bind_samplers(struct xa_context *ctx, + const struct xa_composite *comp) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state src_sampler, mask_sampler; + struct pipe_sampler_view view_templ; + struct pipe_sampler_view *src_view; + struct pipe_context *pipe = ctx->pipe; + struct xa_picture *src_pic = comp->src; + struct xa_picture *mask_pic = comp->mask; + + ctx->num_bound_samplers = 0; + + memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); + memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); + + if (src_pic) { + if (ctx->has_solid_color) { + samplers[0] = NULL; + pipe_sampler_view_reference(&ctx->bound_sampler_views[0], NULL); + } else { + unsigned src_wrap = xa_repeat_to_gallium(src_pic->wrap); + int filter; + + (void) xa_filter_to_gallium(src_pic->filter, &filter); + + src_sampler.wrap_s = src_wrap; + src_sampler.wrap_t = src_wrap; + src_sampler.min_img_filter = filter; + src_sampler.mag_img_filter = filter; + src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + src_sampler.normalized_coords = 1; + samplers[0] = &src_sampler; + ctx->num_bound_samplers = 1; + u_sampler_view_default_template(&view_templ, + src_pic->srf->tex, + src_pic->srf->tex->format); + src_view = pipe->create_sampler_view(pipe, src_pic->srf->tex, + &view_templ); + pipe_sampler_view_reference(&ctx->bound_sampler_views[0], NULL); + ctx->bound_sampler_views[0] = src_view; + } + } + + if (mask_pic) { + unsigned mask_wrap = xa_repeat_to_gallium(mask_pic->wrap); + int filter; + + (void) xa_filter_to_gallium(mask_pic->filter, &filter); + + mask_sampler.wrap_s = mask_wrap; + mask_sampler.wrap_t = mask_wrap; + mask_sampler.min_img_filter = filter; + mask_sampler.mag_img_filter = filter; + src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + mask_sampler.normalized_coords = 1; + samplers[1] = &mask_sampler; + ctx->num_bound_samplers = 2; + u_sampler_view_default_template(&view_templ, + mask_pic->srf->tex, + mask_pic->srf->tex->format); + src_view = pipe->create_sampler_view(pipe, mask_pic->srf->tex, + &view_templ); + pipe_sampler_view_reference(&ctx->bound_sampler_views[1], NULL); + ctx->bound_sampler_views[1] = src_view; + } + + cso_set_samplers(ctx->cso, ctx->num_bound_samplers, + (const struct pipe_sampler_state **)samplers); + cso_set_fragment_sampler_views(ctx->cso, ctx->num_bound_samplers, + ctx->bound_sampler_views); +} + +int +xa_composite_prepare(struct xa_context *ctx, + const struct xa_composite *comp) +{ + struct xa_surface *dst_srf = comp->dst->srf; + int ret; + + ret = xa_surface_psurf_create(ctx, dst_srf); + if (ret != XA_ERR_NONE) + return ret; + + ctx->dst = dst_srf; + renderer_bind_destination(ctx, dst_srf->srf, + dst_srf->srf->width, + dst_srf->srf->height); + + ret = bind_composite_blend_state(ctx, comp); + if (ret != XA_ERR_NONE) + return ret; + ret = bind_shaders(ctx, comp); + if (ret != XA_ERR_NONE) + return ret; + bind_samplers(ctx, comp); + + if (ctx->num_bound_samplers == 0 ) { /* solid fill */ + renderer_begin_solid(ctx); + } else { + renderer_begin_textures(ctx); + ctx->comp = comp; + } + + xa_surface_psurf_destroy(dst_srf); + return XA_ERR_NONE; +} + +void xa_composite_rect(struct xa_context *ctx, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + if (ctx->num_bound_samplers == 0 ) { /* solid fill */ + renderer_solid(ctx, dstX, dstY, dstX + width, dstY + height, + ctx->solid_color); + } else { + const struct xa_composite *comp = ctx->comp; + int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY}; + const float *src_matrix = NULL; + const float *mask_matrix = NULL; + + if (comp->src->has_transform) + src_matrix = comp->src->transform; + if (comp->mask && comp->mask->has_transform) + mask_matrix = comp->mask->transform; + + renderer_texture(ctx, pos, width, height, + src_matrix, mask_matrix); + } +} + +void +xa_composite_done(struct xa_context *ctx) +{ + renderer_draw_flush(ctx); + ctx->pipe->flush(ctx->pipe, &ctx->last_fence); + + ctx->comp = NULL; + ctx->has_solid_color = FALSE; + ctx->num_bound_samplers = 0; +} + +static const struct xa_composite_allocation a = { + .xa_composite_size = sizeof(struct xa_composite), + .xa_picture_size = sizeof(struct xa_picture), + .xa_source_pict_size = sizeof(union xa_source_pict), +}; + +const struct xa_composite_allocation * +xa_composite_allocation(void) +{ + return &a; +} diff --git a/src/gallium/state_trackers/xa/xa_composite.h b/src/gallium/state_trackers/xa/xa_composite.h new file mode 100644 index 00000000000..d16ef89ebd8 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_composite.h @@ -0,0 +1,140 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#ifndef _XA_COMPOSITE_H_ +#define _XA_COMPOSITE_H_ + +#include "xa_tracker.h" +#include "xa_context.h" + +/* + * Supported composite ops. + */ +enum xa_composite_op { + xa_op_clear, + xa_op_src, + xa_op_dst, + xa_op_over, + xa_op_over_reverse, + xa_op_in, + xa_op_in_reverse, + xa_op_out, + xa_op_out_reverse, + xa_op_atop, + xa_op_atop_reverse, + xa_op_xor, + xa_op_add +}; + +/* + * Supported filters. + */ +enum xa_composite_filter { + xa_filter_nearest, + xa_filter_linear +}; + +/* + * Supported clamp methods. + */ +enum xa_composite_wrap { + xa_wrap_clamp_to_border, + xa_wrap_repeat, + xa_wrap_mirror_repeat, + xa_wrap_clamp_to_edge +}; + +/* + * Src picture types. + */ +enum xa_composite_src_pict_type { + xa_src_pict_solid_fill +}; + +struct xa_pict_solid_fill { + enum xa_composite_src_pict_type type; + unsigned int class; + uint32_t color; +}; + +union xa_source_pict { + unsigned int type; + struct xa_pict_solid_fill solid_fill; +}; + +struct xa_picture { + enum xa_formats pict_format; + struct xa_surface *srf; + struct xa_surface *alpha_map; + float transform[9]; + int has_transform; + int component_alpha; + enum xa_composite_wrap wrap; + enum xa_composite_filter filter; + union xa_source_pict *src_pict; +}; + +struct xa_composite { + struct xa_picture *src, *mask, *dst; + int op; + int no_solid; +}; + +struct xa_composite_allocation { + unsigned int xa_composite_size; + unsigned int xa_picture_size; + unsigned int xa_source_pict_size; +}; + +/* + * Get allocation sizes for minor bump compatibility. + */ + +extern const struct xa_composite_allocation * +xa_composite_allocation(void); + +/* + * This function checks most things except the format of the hardware + * surfaces, since they are generally not available at the time this + * function is called. Returns usual XA error codes. + */ +extern int +xa_composite_check_accelerated(const struct xa_composite *comp); + +extern int +xa_composite_prepare(struct xa_context *ctx, const struct xa_composite *comp); + +extern void +xa_composite_rect(struct xa_context *ctx, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height); +extern void +xa_composite_done(struct xa_context *ctx); + +#endif diff --git a/src/gallium/state_trackers/xa/xa_context.c b/src/gallium/state_trackers/xa/xa_context.c new file mode 100644 index 00000000000..118a390a14a --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_context.c @@ -0,0 +1,389 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ +#include "xa_context.h" +#include "xa_priv.h" +#include "cso_cache/cso_context.h" +#include "util/u_inlines.h" +#include "util/u_rect.h" +#include "util/u_surface.h" +#include "pipe/p_context.h" + + +struct xa_context * +xa_context_default(struct xa_tracker *xa) +{ + return xa->default_ctx; +} + +struct xa_context * +xa_context_create(struct xa_tracker *xa) +{ + struct xa_context *ctx = calloc(1, sizeof(*ctx)); + + ctx->xa = xa; + ctx->pipe = xa->screen->context_create(xa->screen, NULL); + ctx->cso = cso_create_context(ctx->pipe); + ctx->shaders = xa_shaders_create(ctx); + renderer_init_state(ctx); + + return ctx; +} + +void +xa_context_destroy(struct xa_context *r) +{ + struct pipe_resource **vsbuf = &r->vs_const_buffer; + struct pipe_resource **fsbuf = &r->fs_const_buffer; + + if (*vsbuf) + pipe_resource_reference(vsbuf, NULL); + + if (*fsbuf) + pipe_resource_reference(fsbuf, NULL); + + if (r->shaders) { + xa_shaders_destroy(r->shaders); + r->shaders = NULL; + } + + if (r->cso) { + cso_release_all(r->cso); + cso_destroy_context(r->cso); + r->cso = NULL; + } +} + +int +xa_surface_dma(struct xa_context *ctx, + struct xa_surface *srf, + void *data, + unsigned int pitch, + int to_surface, struct xa_box *boxes, unsigned int num_boxes) +{ + struct pipe_transfer *transfer; + void *map; + int w, h, i; + enum pipe_transfer_usage transfer_direction; + struct pipe_context *pipe = ctx->pipe; + + transfer_direction = (to_surface ? PIPE_TRANSFER_WRITE : + PIPE_TRANSFER_READ); + + for (i = 0; i < num_boxes; ++i, ++boxes) { + w = boxes->x2 - boxes->x1; + h = boxes->y2 - boxes->y1; + + transfer = pipe_get_transfer(pipe, srf->tex, 0, 0, + transfer_direction, boxes->x1, boxes->y1, + w, h); + if (!transfer) + return -XA_ERR_NORES; + + map = pipe_transfer_map(ctx->pipe, transfer); + if (!map) + goto out_no_map; + + if (to_surface) { + util_copy_rect(map, srf->tex->format, transfer->stride, + 0, 0, w, h, data, pitch, boxes->x1, boxes->y1); + } else { + util_copy_rect(data, srf->tex->format, pitch, + boxes->x1, boxes->y1, w, h, map, transfer->stride, 0, + 0); + } + pipe->transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); + if (to_surface) + pipe->flush(pipe, &ctx->last_fence); + } + return XA_ERR_NONE; + out_no_map: + pipe->transfer_destroy(pipe, transfer); + return -XA_ERR_NORES; +} + +void * +xa_surface_map(struct xa_context *ctx, + struct xa_surface *srf, unsigned int usage) +{ + void *map; + unsigned int transfer_direction = 0; + struct pipe_context *pipe = ctx->pipe; + + if (srf->transfer) + return NULL; + + if (usage & XA_MAP_READ) + transfer_direction = PIPE_TRANSFER_READ; + if (usage & XA_MAP_WRITE) + transfer_direction = PIPE_TRANSFER_WRITE; + + if (!transfer_direction) + return NULL; + + srf->transfer = pipe_get_transfer(pipe, srf->tex, 0, 0, + transfer_direction, 0, 0, + srf->tex->width0, srf->tex->height0); + if (!srf->transfer) + return NULL; + + map = pipe_transfer_map(pipe, srf->transfer); + if (!map) + pipe->transfer_destroy(pipe, srf->transfer); + + srf->mapping_pipe = pipe; + return map; +} + +void +xa_surface_unmap(struct xa_surface *srf) +{ + if (srf->transfer) { + struct pipe_context *pipe = srf->mapping_pipe; + + pipe->transfer_unmap(pipe, srf->transfer); + pipe->transfer_destroy(pipe, srf->transfer); + srf->transfer = NULL; + } +} + +int +xa_surface_psurf_create(struct xa_context *ctx, struct xa_surface *dst) +{ + struct pipe_screen *screen = ctx->pipe->screen; + struct pipe_surface srf_templ; + + if (dst->srf) + return -XA_ERR_INVAL; + + if (!screen->is_format_supported(screen, dst->tex->format, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET)) + return -XA_ERR_INVAL; + + u_surface_default_template(&srf_templ, dst->tex, + PIPE_BIND_RENDER_TARGET); + dst->srf = ctx->pipe->create_surface(ctx->pipe, dst->tex, &srf_templ); + if (!dst->srf) + return -XA_ERR_NORES; + + return XA_ERR_NONE; +} + +void +xa_surface_psurf_destroy(struct xa_surface *dst) +{ + pipe_surface_reference(&dst->srf, NULL); +} + +int +xa_copy_prepare(struct xa_context *ctx, + struct xa_surface *dst, struct xa_surface *src) +{ + if (src == dst || dst->srf != NULL) + return -XA_ERR_INVAL; + + if (src->tex->format != dst->tex->format) { + int ret = xa_surface_psurf_create(ctx, dst); + if (ret != XA_ERR_NONE) + return ret; + renderer_copy_prepare(ctx, dst->srf, src->tex); + ctx->simple_copy = 0; + } else + ctx->simple_copy = 1; + + ctx->src = src; + ctx->dst = dst; + + return 0; +} + +void +xa_copy(struct xa_context *ctx, + int dx, int dy, int sx, int sy, int width, int height) +{ + struct pipe_box src_box; + + if (ctx->simple_copy) { + u_box_2d(sx, sy, width, height, &src_box); + ctx->pipe->resource_copy_region(ctx->pipe, + ctx->dst->tex, 0, dx, dy, 0, + ctx->src->tex, + 0, &src_box); + } else + renderer_copy(ctx, dx, dy, sx, sy, width, height, + (float) width, (float) height); +} + +void +xa_copy_done(struct xa_context *ctx) +{ + if (!ctx->simple_copy) { + renderer_draw_flush(ctx); + ctx->pipe->flush(ctx->pipe, &ctx->last_fence); + xa_surface_psurf_destroy(ctx->dst); + } else + ctx->pipe->flush(ctx->pipe, &ctx->last_fence); +} + +static void +bind_solid_blend_state(struct xa_context *ctx) +{ + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.rt[0].blend_enable = 0; + blend.rt[0].colormask = PIPE_MASK_RGBA; + + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + + cso_set_blend(ctx->cso, &blend); +} + +int +xa_solid_prepare(struct xa_context *ctx, struct xa_surface *dst, + uint32_t fg) +{ + unsigned vs_traits, fs_traits; + struct xa_shader shader; + int width, height; + int ret; + + ret = xa_surface_psurf_create(ctx, dst); + if (ret != XA_ERR_NONE) + return ret; + + if (dst->srf->format == PIPE_FORMAT_L8_UNORM) + xa_pixel_to_float4_a8(fg, ctx->solid_color); + else + xa_pixel_to_float4(fg, ctx->solid_color); + ctx->has_solid_color = 1; + + ctx->dst = dst; + width = dst->srf->width; + height = dst->srf->height; + +#if 0 + debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", + (fg >> 24) & 0xff, (fg >> 16) & 0xff, + (fg >> 8) & 0xff, (fg >> 0) & 0xff, + exa->solid_color[0], exa->solid_color[1], + exa->solid_color[2], exa->solid_color[3]); +#endif + + vs_traits = VS_SOLID_FILL; + fs_traits = FS_SOLID_FILL; + + renderer_bind_destination(ctx, dst->srf, width, height); + bind_solid_blend_state(ctx); + cso_set_samplers(ctx->cso, 0, NULL); + cso_set_fragment_sampler_views(ctx->cso, 0, NULL); + + shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(ctx->cso, shader.vs); + cso_set_fragment_shader_handle(ctx->cso, shader.fs); + + renderer_begin_solid(ctx); + + xa_surface_psurf_destroy(dst); + return XA_ERR_NONE; +} + +void +xa_solid(struct xa_context *ctx, int x, int y, int width, int height) +{ + renderer_solid(ctx, x, y, x + width, y + height, ctx->solid_color); +} + +void +xa_solid_done(struct xa_context *ctx) +{ + renderer_draw_flush(ctx); + ctx->pipe->flush(ctx->pipe, &ctx->last_fence); + + ctx->comp = NULL; + ctx->has_solid_color = FALSE; + ctx->num_bound_samplers = 0; +} + +struct xa_fence * +xa_fence_get(struct xa_context *ctx) +{ + struct xa_fence *fence = malloc(sizeof(*fence)); + struct pipe_screen *screen = ctx->xa->screen; + + if (!fence) + return NULL; + + fence->xa = ctx->xa; + + if (ctx->last_fence == NULL) + fence->pipe_fence = NULL; + else + screen->fence_reference(screen, &fence->pipe_fence, ctx->last_fence); + + return fence; +} + +int +xa_fence_wait(struct xa_fence *fence, uint64_t timeout) +{ + if (!fence) + return XA_ERR_NONE; + + if (fence->pipe_fence) { + struct pipe_screen *screen = fence->xa->screen; + boolean timed_out; + + timed_out = !screen->fence_finish(screen, fence->pipe_fence, timeout); + if (timed_out) + return -XA_ERR_BUSY; + + screen->fence_reference(screen, &fence->pipe_fence, NULL); + } + return XA_ERR_NONE; +} + +void +xa_fence_destroy(struct xa_fence *fence) +{ + if (!fence) + return; + + if (fence->pipe_fence) { + struct pipe_screen *screen = fence->xa->screen; + + screen->fence_reference(screen, &fence->pipe_fence, NULL); + } + + free(fence); +} diff --git a/src/gallium/state_trackers/xa/xa_context.h b/src/gallium/state_trackers/xa/xa_context.h new file mode 100644 index 00000000000..ea2b923a5a1 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_context.h @@ -0,0 +1,86 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#ifndef _XA_CONTEXT_H_ +#define _XA_CONTEXT_H_ +#include "xa_tracker.h" +#include <stdint.h> + +struct xa_context; + +extern struct xa_context *xa_context_default(struct xa_tracker *xa); + +extern struct xa_context *xa_context_create(struct xa_tracker *xa); + +extern void xa_context_destroy(struct xa_context *r); + +extern int xa_yuv_planar_blit(struct xa_context *r, + int src_x, + int src_y, + int src_w, + int src_h, + int dst_x, + int dst_y, + int dst_w, + int dst_h, + struct xa_box *box, + unsigned int num_boxes, + const float conversion_matrix[], + struct xa_surface *dst, struct xa_surface *yuv[]); + +extern int xa_copy_prepare(struct xa_context *ctx, + struct xa_surface *dst, struct xa_surface *src); + +extern void xa_copy(struct xa_context *ctx, + int dx, int dy, int sx, int sy, int width, int height); + +extern void xa_copy_done(struct xa_context *ctx); + +extern int xa_surface_dma(struct xa_context *ctx, + struct xa_surface *srf, + void *data, + unsigned int byte_pitch, + int to_surface, struct xa_box *boxes, + unsigned int num_boxes); + +extern int +xa_solid_prepare(struct xa_context *ctx, struct xa_surface *dst, + uint32_t fg); +extern void +xa_solid(struct xa_context *ctx, int x, int y, int width, int height); + +extern void +xa_solid_done(struct xa_context *ctx); + +extern struct xa_fence *xa_fence_get(struct xa_context *ctx); + +extern int xa_fence_wait(struct xa_fence *fence, uint64_t timeout); + +extern void xa_fence_destroy(struct xa_fence *fence); +#endif diff --git a/src/gallium/state_trackers/xa/xa_priv.h b/src/gallium/state_trackers/xa/xa_priv.h new file mode 100644 index 00000000000..e8f67a12276 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_priv.h @@ -0,0 +1,253 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#ifndef _XA_PRIV_H_ +#define _XA_PRIV_H_ + +#include "xa_tracker.h" +#include "xa_context.h" +#include "xa_composite.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" + +#define XA_VB_SIZE (100 * 4 * 3 * 4) +#define XA_LAST_SURFACE_TYPE (xa_type_yuv_component + 1) +#define XA_MAX_SAMPLERS 3 + +struct xa_fence { + struct pipe_fence_handle *pipe_fence; + struct xa_tracker *xa; +}; + +struct xa_format_descriptor { + enum pipe_format format; + enum xa_formats xa_format; +}; + +struct xa_surface { + struct pipe_resource template; + struct xa_tracker *xa; + struct pipe_resource *tex; + struct pipe_surface *srf; + struct pipe_sampler_view *view; + unsigned int flags; + struct xa_format_descriptor fdesc; + struct pipe_transfer *transfer; + struct pipe_context *mapping_pipe; +}; + +struct xa_tracker { + enum xa_formats *supported_formats; + unsigned int format_map[XA_LAST_SURFACE_TYPE][2]; + int d_depth_bits_last; + int ds_depth_bits_last; + struct pipe_screen *screen; + struct xa_context *default_ctx; +}; + +struct xa_context { + struct xa_tracker *xa; + struct pipe_context *pipe; + + struct cso_context *cso; + struct xa_shaders *shaders; + + struct pipe_resource *vs_const_buffer; + struct pipe_resource *fs_const_buffer; + + float buffer[XA_VB_SIZE]; + unsigned int buffer_size; + struct pipe_vertex_element velems[3]; + + /* number of attributes per vertex for the current + * draw operation */ + unsigned int attrs_per_vertex; + + unsigned int fb_width; + unsigned int fb_height; + + struct pipe_fence_handle *last_fence; + struct xa_surface *src; + struct xa_surface *dst; + int simple_copy; + + int has_solid_color; + float solid_color[4]; + + unsigned int num_bound_samplers; + struct pipe_sampler_view *bound_sampler_views[XA_MAX_SAMPLERS]; + const struct xa_composite *comp; +}; + +enum xa_vs_traits { + VS_COMPOSITE = 1 << 0, + VS_MASK = 1 << 1, + VS_SOLID_FILL = 1 << 2, + VS_LINGRAD_FILL = 1 << 3, + VS_RADGRAD_FILL = 1 << 4, + VS_YUV = 1 << 5, + + VS_FILL = (VS_SOLID_FILL | VS_LINGRAD_FILL | VS_RADGRAD_FILL) +}; + +enum xa_fs_traits { + FS_COMPOSITE = 1 << 0, + FS_MASK = 1 << 1, + FS_SOLID_FILL = 1 << 2, + FS_LINGRAD_FILL = 1 << 3, + FS_RADGRAD_FILL = 1 << 4, + FS_CA_FULL = 1 << 5, /* src.rgba * mask.rgba */ + FS_CA_SRCALPHA = 1 << 6, /* src.aaaa * mask.rgba */ + FS_YUV = 1 << 7, + FS_SRC_REPEAT_NONE = 1 << 8, + FS_MASK_REPEAT_NONE = 1 << 9, + FS_SRC_SWIZZLE_RGB = 1 << 10, + FS_MASK_SWIZZLE_RGB = 1 << 11, + FS_SRC_SET_ALPHA = 1 << 12, + FS_MASK_SET_ALPHA = 1 << 13, + FS_SRC_LUMINANCE = 1 << 14, + FS_MASK_LUMINANCE = 1 << 15, + FS_DST_LUMINANCE = 1 << 16, + + FS_FILL = (FS_SOLID_FILL | FS_LINGRAD_FILL | FS_RADGRAD_FILL), + FS_COMPONENT_ALPHA = (FS_CA_FULL | FS_CA_SRCALPHA) +}; + +struct xa_shader { + void *fs; + void *vs; +}; + +struct xa_shaders; + +/* + * Inline utilities + */ + +static INLINE int +xa_min(int a, int b) +{ + return ((a <= b) ? a : b); +} + +static INLINE void +xa_pixel_to_float4(uint32_t pixel, float *color) +{ + uint32_t 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.; +} + +static INLINE void +xa_pixel_to_float4_a8(uint32_t pixel, float *color) +{ + uint32_t a; + + a = (pixel >> 24) & 0xff; + color[0] = ((float)a) / 255.; + color[1] = ((float)a) / 255.; + color[2] = ((float)a) / 255.; + color[3] = ((float)a) / 255.; +} + +/* + * xa_tgsi.c + */ + +extern struct xa_shaders *xa_shaders_create(struct xa_context *); + +void xa_shaders_destroy(struct xa_shaders *shaders); + +struct xa_shader xa_shaders_get(struct xa_shaders *shaders, + unsigned vs_traits, unsigned fs_traits); + +/* + * xa_context.c + */ +extern int +xa_surface_psurf_create(struct xa_context *ctx, struct xa_surface *dst); + +extern void +xa_surface_psurf_destroy(struct xa_surface *dst); + +/* + * xa_renderer.c + */ +void renderer_set_constants(struct xa_context *r, + int shader_type, const float *params, + int param_bytes); + +void renderer_draw_yuv(struct xa_context *r, + float src_x, + float src_y, + float src_w, + float src_h, + int dst_x, + int dst_y, int dst_w, int dst_h, + struct xa_surface *srf[]); + +void renderer_bind_destination(struct xa_context *r, + struct pipe_surface *surface, int width, + int height); + +void renderer_init_state(struct xa_context *r); +void renderer_copy_prepare(struct xa_context *r, + struct pipe_surface *dst_surface, + struct pipe_resource *src_texture); +void renderer_copy(struct xa_context *r, int dx, + int dy, + int sx, + int sy, + int width, int height, float src_width, float src_height); + +void renderer_draw_flush(struct xa_context *r); + +void renderer_begin_solid(struct xa_context *r); +void renderer_solid(struct xa_context *r, + int x0, int y0, int x1, int y1, float *color); +void +renderer_begin_textures(struct xa_context *r); + +void +renderer_texture(struct xa_context *r, + int *pos, + int width, int height, + const float *src_matrix, + const float *mask_matrix); + +#endif diff --git a/src/gallium/state_trackers/xa/xa_renderer.c b/src/gallium/state_trackers/xa/xa_renderer.c new file mode 100644 index 00000000000..ef762f0ab49 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_renderer.c @@ -0,0 +1,632 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + */ + +#include "xa_context.h" +#include "xa_priv.h" +#include <math.h> +#include "cso_cache/cso_context.h" +#include "util/u_inlines.h" +#include "util/u_sampler.h" +#include "util/u_draw_quad.h" + +#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y))) +#define floatIsZero(x) (floatsEqual((x) + 1, 1)) + +#define NUM_COMPONENTS 4 + +void + + +renderer_set_constants(struct xa_context *r, + int shader_type, const float *params, int param_bytes); + +static INLINE boolean +is_affine(float *matrix) +{ + return floatIsZero(matrix[2]) && floatIsZero(matrix[5]) + && floatsEqual(matrix[8], 1); +} + +static INLINE void +map_point(float *mat, float x, float y, float *out_x, float *out_y) +{ + if (!mat) { + *out_x = x; + *out_y = y; + return; + } + + *out_x = mat[0] * x + mat[3] * y + mat[6]; + *out_y = mat[1] * x + mat[4] * y + mat[7]; + if (!is_affine(mat)) { + float w = 1 / (mat[2] * x + mat[5] * y + mat[8]); + + *out_x *= w; + *out_y *= w; + } +} + +static INLINE struct pipe_resource * +renderer_buffer_create(struct xa_context *r) +{ + struct pipe_resource *buf = pipe_user_buffer_create(r->pipe->screen, + r->buffer, + sizeof(float) * + r->buffer_size, + PIPE_BIND_VERTEX_BUFFER); + + r->buffer_size = 0; + + return buf; +} + +static INLINE void +renderer_draw(struct xa_context *r) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_resource *buf = 0; + int num_verts = r->buffer_size / (r->attrs_per_vertex * NUM_COMPONENTS); + + if (!r->buffer_size) + return; + + buf = renderer_buffer_create(r); + + if (buf) { + cso_set_vertex_elements(r->cso, r->attrs_per_vertex, r->velems); + + util_draw_vertex_buffer(pipe, r->cso, buf, 0, PIPE_PRIM_QUADS, num_verts, /* verts */ + r->attrs_per_vertex); /* attribs/vert */ + + pipe_resource_reference(&buf, NULL); + } +} + +static INLINE void +renderer_draw_conditional(struct xa_context *r, int next_batch) +{ + if (r->buffer_size + next_batch >= XA_VB_SIZE || + (next_batch == 0 && r->buffer_size)) { + renderer_draw(r); + } +} + +void +renderer_init_state(struct xa_context *r) +{ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_rasterizer_state raster; + unsigned i; + + /* set common initial clip state */ + memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + cso_set_depth_stencil_alpha(r->cso, &dsa); + + /* XXX: move to renderer_init_state? */ + memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); + raster.gl_rasterization_rules = 1; + cso_set_rasterizer(r->cso, &raster); + + /* vertex elements state */ + memset(&r->velems[0], 0, sizeof(r->velems[0]) * 3); + for (i = 0; i < 3; i++) { + r->velems[i].src_offset = i * 4 * sizeof(float); + r->velems[i].instance_divisor = 0; + r->velems[i].vertex_buffer_index = 0; + r->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } +} + +static INLINE void +add_vertex_color(struct xa_context *r, float x, float y, float color[4]) +{ + float *vertex = r->buffer + r->buffer_size; + + vertex[0] = x; + vertex[1] = y; + vertex[2] = 0.f; /*z */ + vertex[3] = 1.f; /*w */ + + vertex[4] = color[0]; /*r */ + vertex[5] = color[1]; /*g */ + vertex[6] = color[2]; /*b */ + vertex[7] = color[3]; /*a */ + + r->buffer_size += 8; +} + +static INLINE void +add_vertex_1tex(struct xa_context *r, float x, float y, float s, float t) +{ + float *vertex = r->buffer + r->buffer_size; + + vertex[0] = x; + vertex[1] = y; + vertex[2] = 0.f; /*z */ + vertex[3] = 1.f; /*w */ + + vertex[4] = s; /*s */ + vertex[5] = t; /*t */ + vertex[6] = 0.f; /*r */ + vertex[7] = 1.f; /*q */ + + r->buffer_size += 8; +} + +static INLINE void +add_vertex_2tex(struct xa_context *r, + float x, float y, float s0, float t0, float s1, float t1) +{ + float *vertex = r->buffer + r->buffer_size; + + vertex[0] = x; + vertex[1] = y; + vertex[2] = 0.f; /*z */ + vertex[3] = 1.f; /*w */ + + vertex[4] = s0; /*s */ + vertex[5] = t0; /*t */ + vertex[6] = 0.f; /*r */ + vertex[7] = 1.f; /*q */ + + vertex[8] = s1; /*s */ + vertex[9] = t1; /*t */ + vertex[10] = 0.f; /*r */ + vertex[11] = 1.f; /*q */ + + r->buffer_size += 12; +} + +static void +add_vertex_data1(struct xa_context *r, + float srcX, float srcY, float dstX, float dstY, + float width, float height, + struct pipe_resource *src, const float *src_matrix) +{ + float s0, t0, s1, t1, s2, t2, s3, t3; + float pt0[2], pt1[2], pt2[2], pt3[2]; + + pt0[0] = srcX; + pt0[1] = srcY; + pt1[0] = (srcX + width); + pt1[1] = srcY; + pt2[0] = (srcX + width); + pt2[1] = (srcY + height); + pt3[0] = srcX; + pt3[1] = (srcY + height); + + if (src_matrix) { + map_point((float *)src_matrix, pt0[0], pt0[1], &pt0[0], &pt0[1]); + map_point((float *)src_matrix, pt1[0], pt1[1], &pt1[0], &pt1[1]); + map_point((float *)src_matrix, pt2[0], pt2[1], &pt2[0], &pt2[1]); + map_point((float *)src_matrix, pt3[0], pt3[1], &pt3[0], &pt3[1]); + } + + s0 = pt0[0] / src->width0; + s1 = pt1[0] / src->width0; + s2 = pt2[0] / src->width0; + s3 = pt3[0] / src->width0; + t0 = pt0[1] / src->height0; + t1 = pt1[1] / src->height0; + t2 = pt2[1] / src->height0; + t3 = pt3[1] / src->height0; + + /* 1st vertex */ + add_vertex_1tex(r, dstX, dstY, s0, t0); + /* 2nd vertex */ + add_vertex_1tex(r, dstX + width, dstY, s1, t1); + /* 3rd vertex */ + add_vertex_1tex(r, dstX + width, dstY + height, s2, t2); + /* 4th vertex */ + add_vertex_1tex(r, dstX, dstY + height, s3, t3); +} + +static void +add_vertex_data2(struct xa_context *r, + float srcX, float srcY, float maskX, float maskY, + float dstX, float dstY, float width, float height, + struct pipe_resource *src, + struct pipe_resource *mask, + const float *src_matrix, const float *mask_matrix) +{ + float src_s0, src_t0, src_s1, src_t1; + float mask_s0, mask_t0, mask_s1, mask_t1; + float spt0[2], spt1[2]; + float mpt0[2], mpt1[2]; + + spt0[0] = srcX; + spt0[1] = srcY; + spt1[0] = srcX + width; + spt1[1] = srcY + height; + + mpt0[0] = maskX; + mpt0[1] = maskY; + mpt1[0] = maskX + width; + mpt1[1] = maskY + height; + + if (src_matrix) { + map_point((float *)src_matrix, spt0[0], spt0[1], &spt0[0], &spt0[1]); + map_point((float *)src_matrix, spt1[0], spt1[1], &spt1[0], &spt1[1]); + } + + if (mask_matrix) { + map_point((float *)mask_matrix, mpt0[0], mpt0[1], &mpt0[0], &mpt0[1]); + map_point((float *)mask_matrix, mpt1[0], mpt1[1], &mpt1[0], &mpt1[1]); + } + + src_s0 = spt0[0] / src->width0; + src_t0 = spt0[1] / src->height0; + src_s1 = spt1[0] / src->width0; + src_t1 = spt1[1] / src->height0; + + mask_s0 = mpt0[0] / mask->width0; + mask_t0 = mpt0[1] / mask->height0; + mask_s1 = mpt1[0] / mask->width0; + mask_t1 = mpt1[1] / mask->height0; + + /* 1st vertex */ + add_vertex_2tex(r, dstX, dstY, + src_s0, src_t0, mask_s0, mask_t0); + /* 2nd vertex */ + add_vertex_2tex(r, dstX + width, dstY, + src_s1, src_t0, mask_s1, mask_t0); + /* 3rd vertex */ + add_vertex_2tex(r, dstX + width, dstY + height, + src_s1, src_t1, mask_s1, mask_t1); + /* 4th vertex */ + add_vertex_2tex(r, dstX, dstY + height, + src_s0, src_t1, mask_s0, mask_t1); +} + +static struct pipe_resource * +setup_vertex_data_yuv(struct xa_context *r, + float srcX, + float srcY, + float srcW, + float srcH, + float dstX, + float dstY, + float dstW, float dstH, struct xa_surface *srf[]) +{ + float s0, t0, s1, t1; + float spt0[2], spt1[2]; + struct pipe_resource *tex; + + spt0[0] = srcX; + spt0[1] = srcY; + spt1[0] = srcX + srcW; + spt1[1] = srcY + srcH; + + tex = srf[0]->tex; + s0 = spt0[0] / tex->width0; + t0 = spt0[1] / tex->height0; + s1 = spt1[0] / tex->width0; + t1 = spt1[1] / tex->height0; + + /* 1st vertex */ + add_vertex_1tex(r, dstX, dstY, s0, t0); + /* 2nd vertex */ + add_vertex_1tex(r, dstX + dstW, dstY, s1, t0); + /* 3rd vertex */ + add_vertex_1tex(r, dstX + dstW, dstY + dstH, s1, t1); + /* 4th vertex */ + add_vertex_1tex(r, dstX, dstY + dstH, s0, t1); + + return renderer_buffer_create(r); +} + +/* Set up framebuffer, viewport and vertex shader constant buffer + * state for a particular destinaton surface. In all our rendering, + * these concepts are linked. + */ +void +renderer_bind_destination(struct xa_context *r, + struct pipe_surface *surface, int width, int height) +{ + + struct pipe_framebuffer_state fb; + struct pipe_viewport_state viewport; + + /* Framebuffer uses actual surface width/height + */ + memset(&fb, 0, sizeof fb); + fb.width = surface->width; + fb.height = surface->height; + fb.nr_cbufs = 1; + fb.cbufs[0] = surface; + fb.zsbuf = 0; + + /* Viewport just touches the bit we're interested in: + */ + viewport.scale[0] = width / 2.f; + viewport.scale[1] = height / 2.f; + viewport.scale[2] = 1.0; + viewport.scale[3] = 1.0; + viewport.translate[0] = width / 2.f; + viewport.translate[1] = height / 2.f; + viewport.translate[2] = 0.0; + viewport.translate[3] = 0.0; + + /* Constant buffer set up to match viewport dimensions: + */ + if (r->fb_width != width || r->fb_height != height) { + float vs_consts[8] = { + 2.f / width, 2.f / height, 1, 1, + -1, -1, 0, 0 + }; + + r->fb_width = width; + r->fb_height = height; + + renderer_set_constants(r, PIPE_SHADER_VERTEX, + vs_consts, sizeof vs_consts); + } + + cso_set_framebuffer(r->cso, &fb); + cso_set_viewport(r->cso, &viewport); +} + +void +renderer_set_constants(struct xa_context *r, + int shader_type, const float *params, int param_bytes) +{ + struct pipe_resource **cbuf = + (shader_type == PIPE_SHADER_VERTEX) ? &r->vs_const_buffer : + &r->fs_const_buffer; + + pipe_resource_reference(cbuf, NULL); + *cbuf = pipe_buffer_create(r->pipe->screen, + PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_STATIC, + param_bytes); + + if (*cbuf) { + pipe_buffer_write(r->pipe, *cbuf, 0, param_bytes, params); + } + r->pipe->set_constant_buffer(r->pipe, shader_type, 0, *cbuf); +} + +void +renderer_copy_prepare(struct xa_context *r, + struct pipe_surface *dst_surface, + struct pipe_resource *src_texture) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_screen *screen = pipe->screen; + struct xa_shader shader; + uint32_t fs_traits = FS_COMPOSITE; + + assert(screen->is_format_supported(screen, dst_surface->format, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET)); + (void)screen; + + /* set misc state we care about */ + { + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(blend)); + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].colormask = PIPE_MASK_RGBA; + cso_set_blend(r->cso, &blend); + } + + /* sampler */ + { + struct pipe_sampler_state sampler; + + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = 1; + cso_single_sampler(r->cso, 0, &sampler); + cso_single_sampler_done(r->cso); + } + + renderer_bind_destination(r, dst_surface, + dst_surface->width, dst_surface->height); + + /* texture/sampler view */ + { + struct pipe_sampler_view templ; + struct pipe_sampler_view *src_view; + + u_sampler_view_default_template(&templ, + src_texture, src_texture->format); + src_view = pipe->create_sampler_view(pipe, src_texture, &templ); + cso_set_fragment_sampler_views(r->cso, 1, &src_view); + pipe_sampler_view_reference(&src_view, NULL); + } + + /* shaders */ + if (src_texture->format == PIPE_FORMAT_L8_UNORM) + fs_traits |= FS_SRC_LUMINANCE; + if (dst_surface->format == PIPE_FORMAT_L8_UNORM) + fs_traits |= FS_DST_LUMINANCE; + + shader = xa_shaders_get(r->shaders, VS_COMPOSITE, fs_traits); + cso_set_vertex_shader_handle(r->cso, shader.vs); + cso_set_fragment_shader_handle(r->cso, shader.fs); + + r->buffer_size = 0; + r->attrs_per_vertex = 2; +} + +void +renderer_copy(struct xa_context *r, + int dx, + int dy, + int sx, + int sy, + int width, int height, float src_width, float src_height) +{ + float s0, t0, s1, t1; + float x0, y0, x1, y1; + + /* XXX: could put the texcoord scaling calculation into the vertex + * shader. + */ + s0 = sx / src_width; + s1 = (sx + width) / src_width; + t0 = sy / src_height; + t1 = (sy + height) / src_height; + + x0 = dx; + x1 = dx + width; + y0 = dy; + y1 = dy + height; + + /* draw quad */ + renderer_draw_conditional(r, 4 * 8); + add_vertex_1tex(r, x0, y0, s0, t0); + add_vertex_1tex(r, x1, y0, s1, t0); + add_vertex_1tex(r, x1, y1, s1, t1); + add_vertex_1tex(r, x0, y1, s0, t1); +} + +void +renderer_draw_yuv(struct xa_context *r, + float src_x, + float src_y, + float src_w, + float src_h, + int dst_x, + int dst_y, int dst_w, int dst_h, struct xa_surface *srf[]) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_resource *buf = 0; + + buf = setup_vertex_data_yuv(r, + src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, + dst_h, srf); + + if (buf) { + const int num_attribs = 2; /*pos + tex coord */ + + cso_set_vertex_elements(r->cso, num_attribs, r->velems); + + util_draw_vertex_buffer(pipe, r->cso, buf, 0, PIPE_PRIM_QUADS, 4, /* verts */ + num_attribs); /* attribs/vert */ + + pipe_resource_reference(&buf, NULL); + } +} + +void +renderer_begin_solid(struct xa_context *r) +{ + r->buffer_size = 0; + r->attrs_per_vertex = 2; +} + +void +renderer_solid(struct xa_context *r, + int x0, int y0, int x1, int y1, float *color) +{ + /* + * debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n", + * x0, y0, x1, y1, color[0], color[1], color[2], color[3]); */ + + renderer_draw_conditional(r, 4 * 8); + + /* 1st vertex */ + add_vertex_color(r, x0, y0, color); + /* 2nd vertex */ + add_vertex_color(r, x1, y0, color); + /* 3rd vertex */ + add_vertex_color(r, x1, y1, color); + /* 4th vertex */ + add_vertex_color(r, x0, y1, color); +} + +void +renderer_draw_flush(struct xa_context *r) +{ + renderer_draw_conditional(r, 0); +} + +void +renderer_begin_textures(struct xa_context *r) +{ + r->attrs_per_vertex = 1 + r->num_bound_samplers; + r->buffer_size = 0; +} + +void +renderer_texture(struct xa_context *r, + int *pos, + int width, int height, + const float *src_matrix, + const float *mask_matrix) +{ + struct pipe_sampler_view **sampler_view = r->bound_sampler_views; + +#if 0 + if (src_matrix) { + debug_printf("src_matrix = \n"); + debug_printf("%f, %f, %f\n", src_matrix[0], src_matrix[1], src_matrix[2]); + debug_printf("%f, %f, %f\n", src_matrix[3], src_matrix[4], src_matrix[5]); + debug_printf("%f, %f, %f\n", src_matrix[6], src_matrix[7], src_matrix[8]); + } + if (mask_matrix) { + debug_printf("mask_matrix = \n"); + debug_printf("%f, %f, %f\n", mask_matrix[0], mask_matrix[1], mask_matrix[2]); + debug_printf("%f, %f, %f\n", mask_matrix[3], mask_matrix[4], mask_matrix[5]); + debug_printf("%f, %f, %f\n", mask_matrix[6], mask_matrix[7], mask_matrix[8]); + } +#endif + + switch(r->attrs_per_vertex) { + case 2: + renderer_draw_conditional(r, 4 * 8); + add_vertex_data1(r, + pos[0], pos[1], /* src */ + pos[4], pos[5], /* dst */ + width, height, + sampler_view[0]->texture, src_matrix); + break; + case 3: + renderer_draw_conditional(r, 4 * 12); + add_vertex_data2(r, + pos[0], pos[1], /* src */ + pos[2], pos[3], /* mask */ + pos[4], pos[5], /* dst */ + width, height, + sampler_view[0]->texture, sampler_view[1]->texture, + src_matrix, mask_matrix); + break; + default: + break; + } +} diff --git a/src/gallium/state_trackers/xa/xa_symbols b/src/gallium/state_trackers/xa/xa_symbols new file mode 100644 index 00000000000..6da701f9702 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_symbols @@ -0,0 +1,30 @@ +xa_tracker_version +xa_tracker_create +xa_tracker_destroy +xa_surface_create +xa_surface_destroy +xa_surface_redefine +xa_surface_dma +xa_surface_map +xa_surface_unmap +xa_surface_format +xa_surface_handle +xa_format_check_supported +xa_context_default +xa_context_create +xa_context_destroy +xa_fence_get +xa_fence_wait +xa_fence_destroy +xa_copy_prepare +xa_copy +xa_copy_done +xa_solid_prepare +xa_solid +xa_solid_done +xa_composite_allocation +xa_composite_check_accelerated +xa_composite_prepare +xa_composite_rect +xa_composite_done +xa_yuv_planar_blit diff --git a/src/gallium/state_trackers/xa/xa_tgsi.c b/src/gallium/state_trackers/xa/xa_tgsi.c new file mode 100644 index 00000000000..ed1690ed369 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_tgsi.c @@ -0,0 +1,663 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + */ +#include "xa_priv.h" + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_shader_tokens.h" + +#include "util/u_memory.h" + +#include "tgsi/tgsi_ureg.h" + +#include "cso_cache/cso_context.h" +#include "cso_cache/cso_hash.h" + +/* Vertex shader: + * IN[0] = vertex pos + * IN[1] = src tex coord | solid fill color + * IN[2] = mask tex coord + * IN[3] = dst tex coord + * CONST[0] = (2/dst_width, 2/dst_height, 1, 1) + * CONST[1] = (-1, -1, 0, 0) + * + * OUT[0] = vertex pos + * OUT[1] = src tex coord | solid fill color + * OUT[2] = mask tex coord + * OUT[3] = dst tex coord + */ + +/* Fragment shader: + * SAMP[0] = src + * SAMP[1] = mask + * SAMP[2] = dst + * IN[0] = pos src | solid fill color + * IN[1] = pos mask + * IN[2] = pos dst + * CONST[0] = (0, 0, 0, 1) + * + * OUT[0] = color + */ + +static void +print_fs_traits(int fs_traits) +{ + const char *strings[] = { + "FS_COMPOSITE", /* = 1 << 0, */ + "FS_MASK", /* = 1 << 1, */ + "FS_SOLID_FILL", /* = 1 << 2, */ + "FS_LINGRAD_FILL", /* = 1 << 3, */ + "FS_RADGRAD_FILL", /* = 1 << 4, */ + "FS_CA_FULL", /* = 1 << 5, *//* src.rgba * mask.rgba */ + "FS_CA_SRCALPHA", /* = 1 << 6, *//* src.aaaa * mask.rgba */ + "FS_YUV", /* = 1 << 7, */ + "FS_SRC_REPEAT_NONE", /* = 1 << 8, */ + "FS_MASK_REPEAT_NONE", /* = 1 << 9, */ + "FS_SRC_SWIZZLE_RGB", /* = 1 << 10, */ + "FS_MASK_SWIZZLE_RGB", /* = 1 << 11, */ + "FS_SRC_SET_ALPHA", /* = 1 << 12, */ + "FS_MASK_SET_ALPHA", /* = 1 << 13, */ + "FS_SRC_LUMINANCE", /* = 1 << 14, */ + "FS_MASK_LUMINANCE", /* = 1 << 15, */ + "FS_DST_LUMINANCE", /* = 1 << 15, */ + }; + int i, k; + + debug_printf("%s: ", __func__); + + for (i = 0, k = 1; k < (1 << 16); i++, k <<= 1) { + if (fs_traits & k) + debug_printf("%s, ", strings[i]); + } + + debug_printf("\n"); +} + +struct xa_shaders { + struct xa_context *r; + + struct cso_hash *vs_hash; + struct cso_hash *fs_hash; +}; + +static INLINE void +src_in_mask(struct ureg_program *ureg, + struct ureg_dst dst, + struct ureg_src src, + struct ureg_src mask, + unsigned component_alpha, unsigned mask_luminance) +{ + if (component_alpha == FS_CA_FULL) { + ureg_MUL(ureg, dst, src, mask); + } else if (component_alpha == FS_CA_SRCALPHA) { + ureg_MUL(ureg, dst, ureg_scalar(src, TGSI_SWIZZLE_W), mask); + } else { + if (mask_luminance) + ureg_MUL(ureg, dst, src, ureg_scalar(mask, TGSI_SWIZZLE_X)); + else + ureg_MUL(ureg, dst, src, ureg_scalar(mask, TGSI_SWIZZLE_W)); + } +} + +static struct ureg_src +vs_normalize_coords(struct ureg_program *ureg, + struct ureg_src coords, + struct ureg_src const0, struct ureg_src const1) +{ + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + struct ureg_src ret; + + ureg_MAD(ureg, tmp, coords, const0, const1); + ret = ureg_src(tmp); + ureg_release_temporary(ureg, tmp); + return ret; +} + +static void +linear_gradient(struct ureg_program *ureg, + struct ureg_dst out, + struct ureg_src pos, + struct ureg_src sampler, + struct ureg_src coords, + struct ureg_src const0124, + struct ureg_src matrow0, + struct ureg_src matrow1, struct ureg_src matrow2) +{ + struct ureg_dst temp0 = ureg_DECL_temporary(ureg); + struct ureg_dst temp1 = ureg_DECL_temporary(ureg); + struct ureg_dst temp2 = ureg_DECL_temporary(ureg); + struct ureg_dst temp3 = ureg_DECL_temporary(ureg); + struct ureg_dst temp4 = ureg_DECL_temporary(ureg); + struct ureg_dst temp5 = ureg_DECL_temporary(ureg); + + ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos); + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_Z), + ureg_scalar(const0124, TGSI_SWIZZLE_Y)); + + ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0)); + ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0)); + ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0)); + ureg_RCP(ureg, temp3, ureg_src(temp3)); + ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3)); + ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3)); + + ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X), ureg_src(temp1)); + ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y), ureg_src(temp2)); + + ureg_MUL(ureg, temp0, + ureg_scalar(coords, TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp1, + ureg_scalar(coords, TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X), ureg_src(temp0)); + + ureg_MUL(ureg, temp2, ureg_src(temp1), ureg_scalar(coords, TGSI_SWIZZLE_Z)); + + ureg_TEX(ureg, out, TGSI_TEXTURE_1D, ureg_src(temp2), sampler); + + ureg_release_temporary(ureg, temp0); + ureg_release_temporary(ureg, temp1); + ureg_release_temporary(ureg, temp2); + ureg_release_temporary(ureg, temp3); + ureg_release_temporary(ureg, temp4); + ureg_release_temporary(ureg, temp5); +} + +static void +radial_gradient(struct ureg_program *ureg, + struct ureg_dst out, + struct ureg_src pos, + struct ureg_src sampler, + struct ureg_src coords, + struct ureg_src const0124, + struct ureg_src matrow0, + struct ureg_src matrow1, struct ureg_src matrow2) +{ + struct ureg_dst temp0 = ureg_DECL_temporary(ureg); + struct ureg_dst temp1 = ureg_DECL_temporary(ureg); + struct ureg_dst temp2 = ureg_DECL_temporary(ureg); + struct ureg_dst temp3 = ureg_DECL_temporary(ureg); + struct ureg_dst temp4 = ureg_DECL_temporary(ureg); + struct ureg_dst temp5 = ureg_DECL_temporary(ureg); + + ureg_MOV(ureg, ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos); + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_Z), + ureg_scalar(const0124, TGSI_SWIZZLE_Y)); + + ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0)); + ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0)); + ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0)); + ureg_RCP(ureg, temp3, ureg_src(temp3)); + ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3)); + ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3)); + + ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X), ureg_src(temp1)); + ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y), ureg_src(temp2)); + + ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp1, + ureg_scalar(coords, TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), ureg_src(temp0)); + ureg_ADD(ureg, temp1, ureg_src(temp1), ureg_src(temp1)); + ureg_MUL(ureg, temp3, + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp4, + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), ureg_src(temp3)); + ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4))); + ureg_MUL(ureg, temp2, ureg_scalar(coords, TGSI_SWIZZLE_Z), ureg_src(temp4)); + ureg_MUL(ureg, temp0, + ureg_scalar(const0124, TGSI_SWIZZLE_W), ureg_src(temp2)); + ureg_MUL(ureg, temp3, ureg_src(temp1), ureg_src(temp1)); + ureg_SUB(ureg, temp2, ureg_src(temp3), ureg_src(temp0)); + ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2))); + ureg_RCP(ureg, temp2, ureg_src(temp2)); + ureg_SUB(ureg, temp1, ureg_src(temp2), ureg_src(temp1)); + ureg_ADD(ureg, temp0, + ureg_scalar(coords, TGSI_SWIZZLE_Z), + ureg_scalar(coords, TGSI_SWIZZLE_Z)); + ureg_RCP(ureg, temp0, ureg_src(temp0)); + ureg_MUL(ureg, temp2, ureg_src(temp1), ureg_src(temp0)); + ureg_TEX(ureg, out, TGSI_TEXTURE_1D, ureg_src(temp2), sampler); + + ureg_release_temporary(ureg, temp0); + ureg_release_temporary(ureg, temp1); + ureg_release_temporary(ureg, temp2); + ureg_release_temporary(ureg, temp3); + ureg_release_temporary(ureg, temp4); + ureg_release_temporary(ureg, temp5); +} + +static void * +create_vs(struct pipe_context *pipe, unsigned vs_traits) +{ + struct ureg_program *ureg; + struct ureg_src src; + struct ureg_dst dst; + struct ureg_src const0, const1; + boolean is_fill = (vs_traits & VS_FILL) != 0; + boolean is_composite = (vs_traits & VS_COMPOSITE) != 0; + boolean has_mask = (vs_traits & VS_MASK) != 0; + boolean is_yuv = (vs_traits & VS_YUV) != 0; + unsigned input_slot = 0; + + ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + if (ureg == NULL) + return 0; + + const0 = ureg_DECL_constant(ureg, 0); + const1 = ureg_DECL_constant(ureg, 1); + + /* it has to be either a fill or a composite op */ + debug_assert((is_fill ^ is_composite) ^ is_yuv); + + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); + src = vs_normalize_coords(ureg, src, const0, const1); + ureg_MOV(ureg, dst, src); + + if (is_yuv) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0); + ureg_MOV(ureg, dst, src); + } + + if (is_composite) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0); + ureg_MOV(ureg, dst, src); + } + + if (is_fill) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + ureg_MOV(ureg, dst, src); + } + + if (has_mask) { + src = ureg_DECL_vs_input(ureg, input_slot++); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1); + ureg_MOV(ureg, dst, src); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +static void * +create_yuv_shader(struct pipe_context *pipe, struct ureg_program *ureg) +{ + struct ureg_src y_sampler, u_sampler, v_sampler; + struct ureg_src pos; + struct ureg_src matrow0, matrow1, matrow2; + struct ureg_dst y, u, v, rgb; + struct ureg_dst out = ureg_DECL_output(ureg, + TGSI_SEMANTIC_COLOR, + 0); + + pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_GENERIC, 0, + TGSI_INTERPOLATE_PERSPECTIVE); + + rgb = ureg_DECL_temporary(ureg); + y = ureg_DECL_temporary(ureg); + u = ureg_DECL_temporary(ureg); + v = ureg_DECL_temporary(ureg); + + y_sampler = ureg_DECL_sampler(ureg, 0); + u_sampler = ureg_DECL_sampler(ureg, 1); + v_sampler = ureg_DECL_sampler(ureg, 2); + + matrow0 = ureg_DECL_constant(ureg, 0); + matrow1 = ureg_DECL_constant(ureg, 1); + matrow2 = ureg_DECL_constant(ureg, 2); + + ureg_TEX(ureg, y, TGSI_TEXTURE_2D, pos, y_sampler); + ureg_TEX(ureg, u, TGSI_TEXTURE_2D, pos, u_sampler); + ureg_TEX(ureg, v, TGSI_TEXTURE_2D, pos, v_sampler); + + ureg_SUB(ureg, u, ureg_src(u), ureg_scalar(matrow0, TGSI_SWIZZLE_W)); + ureg_SUB(ureg, v, ureg_src(v), ureg_scalar(matrow0, TGSI_SWIZZLE_W)); + + ureg_MUL(ureg, rgb, ureg_scalar(ureg_src(y), TGSI_SWIZZLE_X), matrow0); + ureg_MAD(ureg, rgb, + ureg_scalar(ureg_src(u), TGSI_SWIZZLE_X), matrow1, ureg_src(rgb)); + ureg_MAD(ureg, rgb, + ureg_scalar(ureg_src(v), TGSI_SWIZZLE_X), matrow2, ureg_src(rgb)); + + /* rgb.a = 1; */ + ureg_MOV(ureg, ureg_writemask(rgb, TGSI_WRITEMASK_W), + ureg_scalar(matrow0, TGSI_SWIZZLE_X)); + + ureg_MOV(ureg, out, ureg_src(rgb)); + + ureg_release_temporary(ureg, rgb); + ureg_release_temporary(ureg, y); + ureg_release_temporary(ureg, u); + ureg_release_temporary(ureg, v); + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +static INLINE void +xrender_tex(struct ureg_program *ureg, + struct ureg_dst dst, + struct ureg_src coords, + struct ureg_src sampler, + struct ureg_src imm0, + boolean repeat_none, boolean swizzle, boolean set_alpha) +{ + if (repeat_none) { + struct ureg_dst tmp0 = ureg_DECL_temporary(ureg); + struct ureg_dst tmp1 = ureg_DECL_temporary(ureg); + + ureg_SGT(ureg, tmp1, ureg_swizzle(coords, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_X, + TGSI_SWIZZLE_Y), ureg_scalar(imm0, + TGSI_SWIZZLE_X)); + ureg_SLT(ureg, tmp0, + ureg_swizzle(coords, TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, + TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y), ureg_scalar(imm0, + TGSI_SWIZZLE_W)); + ureg_MIN(ureg, tmp0, ureg_src(tmp0), ureg_src(tmp1)); + ureg_MIN(ureg, tmp0, ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_Y)); + ureg_TEX(ureg, tmp1, TGSI_TEXTURE_2D, coords, sampler); + if (swizzle) + ureg_MOV(ureg, tmp1, ureg_swizzle(ureg_src(tmp1), + TGSI_SWIZZLE_Z, + TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_W)); + if (set_alpha) + ureg_MOV(ureg, + ureg_writemask(tmp1, TGSI_WRITEMASK_W), + ureg_scalar(imm0, TGSI_SWIZZLE_W)); + ureg_MUL(ureg, dst, ureg_src(tmp1), ureg_src(tmp0)); + ureg_release_temporary(ureg, tmp0); + ureg_release_temporary(ureg, tmp1); + } else { + if (swizzle) { + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + + ureg_TEX(ureg, tmp, TGSI_TEXTURE_2D, coords, sampler); + ureg_MOV(ureg, dst, ureg_swizzle(ureg_src(tmp), + TGSI_SWIZZLE_Z, + TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, + TGSI_SWIZZLE_W)); + ureg_release_temporary(ureg, tmp); + } else { + ureg_TEX(ureg, dst, TGSI_TEXTURE_2D, coords, sampler); + } + if (set_alpha) + ureg_MOV(ureg, + ureg_writemask(dst, TGSI_WRITEMASK_W), + ureg_scalar(imm0, TGSI_SWIZZLE_W)); + } +} + +static void * +create_fs(struct pipe_context *pipe, unsigned fs_traits) +{ + struct ureg_program *ureg; + struct ureg_src /*dst_sampler, */ src_sampler, mask_sampler; + struct ureg_src /*dst_pos, */ src_input, mask_pos; + struct ureg_dst src, mask; + struct ureg_dst out; + struct ureg_src imm0 = { 0 }; + unsigned has_mask = (fs_traits & FS_MASK) != 0; + unsigned is_fill = (fs_traits & FS_FILL) != 0; + unsigned is_composite = (fs_traits & FS_COMPOSITE) != 0; + unsigned is_solid = (fs_traits & FS_SOLID_FILL) != 0; + unsigned is_lingrad = (fs_traits & FS_LINGRAD_FILL) != 0; + unsigned is_radgrad = (fs_traits & FS_RADGRAD_FILL) != 0; + unsigned comp_alpha_mask = fs_traits & FS_COMPONENT_ALPHA; + unsigned is_yuv = (fs_traits & FS_YUV) != 0; + unsigned src_repeat_none = (fs_traits & FS_SRC_REPEAT_NONE) != 0; + unsigned mask_repeat_none = (fs_traits & FS_MASK_REPEAT_NONE) != 0; + unsigned src_swizzle = (fs_traits & FS_SRC_SWIZZLE_RGB) != 0; + unsigned mask_swizzle = (fs_traits & FS_MASK_SWIZZLE_RGB) != 0; + unsigned src_set_alpha = (fs_traits & FS_SRC_SET_ALPHA) != 0; + unsigned mask_set_alpha = (fs_traits & FS_MASK_SET_ALPHA) != 0; + unsigned src_luminance = (fs_traits & FS_SRC_LUMINANCE) != 0; + unsigned mask_luminance = (fs_traits & FS_MASK_LUMINANCE) != 0; + unsigned dst_luminance = (fs_traits & FS_DST_LUMINANCE) != 0; + +#if 0 + print_fs_traits(fs_traits); +#else + (void)print_fs_traits; +#endif + + ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (ureg == NULL) + return 0; + + /* it has to be either a fill, a composite op or a yuv conversion */ + debug_assert((is_fill ^ is_composite) ^ is_yuv); + (void)is_yuv; + + out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + + if (src_repeat_none || mask_repeat_none || + src_set_alpha || mask_set_alpha || src_luminance) { + imm0 = ureg_imm4f(ureg, 0, 0, 0, 1); + } + if (is_composite) { + src_sampler = ureg_DECL_sampler(ureg, 0); + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_GENERIC, 0, + TGSI_INTERPOLATE_PERSPECTIVE); + } else if (is_fill) { + if (is_solid) + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_COLOR, 0, + TGSI_INTERPOLATE_PERSPECTIVE); + else + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, 0, + TGSI_INTERPOLATE_PERSPECTIVE); + } else { + debug_assert(is_yuv); + return create_yuv_shader(pipe, ureg); + } + + if (has_mask) { + mask_sampler = ureg_DECL_sampler(ureg, 1); + mask_pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_GENERIC, 1, + TGSI_INTERPOLATE_PERSPECTIVE); + } +#if 0 /* unused right now */ + dst_sampler = ureg_DECL_sampler(ureg, 2); + dst_pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, 2, + TGSI_INTERPOLATE_PERSPECTIVE); +#endif + + if (is_composite) { + if (has_mask || src_luminance || dst_luminance) + src = ureg_DECL_temporary(ureg); + else + src = out; + xrender_tex(ureg, src, src_input, src_sampler, imm0, + src_repeat_none, src_swizzle, src_set_alpha); + } else if (is_fill) { + if (is_solid) { + if (has_mask || src_luminance || dst_luminance) + src = ureg_dst(src_input); + else + ureg_MOV(ureg, out, src_input); + } else if (is_lingrad || is_radgrad) { + struct ureg_src coords, const0124, matrow0, matrow1, matrow2; + + if (has_mask || src_luminance || dst_luminance) + src = ureg_DECL_temporary(ureg); + else + src = out; + + coords = ureg_DECL_constant(ureg, 0); + const0124 = ureg_DECL_constant(ureg, 1); + matrow0 = ureg_DECL_constant(ureg, 2); + matrow1 = ureg_DECL_constant(ureg, 3); + matrow2 = ureg_DECL_constant(ureg, 4); + + if (is_lingrad) { + linear_gradient(ureg, src, + src_input, src_sampler, + coords, const0124, matrow0, matrow1, matrow2); + } else if (is_radgrad) { + radial_gradient(ureg, src, + src_input, src_sampler, + coords, const0124, matrow0, matrow1, matrow2); + } + } else + debug_assert(!"Unknown fill type!"); + } + if (src_luminance) { + ureg_MOV(ureg, src, ureg_scalar(ureg_src(src), TGSI_SWIZZLE_X)); + ureg_MOV(ureg, ureg_writemask(src, TGSI_WRITEMASK_XYZ), + ureg_scalar(imm0, TGSI_SWIZZLE_X)); + if (!has_mask && !dst_luminance) + ureg_MOV(ureg, out, ureg_src(src)); + } + + if (has_mask) { + mask = ureg_DECL_temporary(ureg); + xrender_tex(ureg, mask, mask_pos, mask_sampler, imm0, + mask_repeat_none, mask_swizzle, mask_set_alpha); + /* src IN mask */ + + src_in_mask(ureg, (dst_luminance) ? src : out, ureg_src(src), + ureg_src(mask), + comp_alpha_mask, mask_luminance); + + ureg_release_temporary(ureg, mask); + } + + if (dst_luminance) { + /* + * Make sure the alpha channel goes into the output L8 surface. + */ + ureg_MOV(ureg, out, ureg_scalar(ureg_src(src), TGSI_SWIZZLE_W)); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +struct xa_shaders * +xa_shaders_create(struct xa_context *r) +{ + struct xa_shaders *sc = CALLOC_STRUCT(xa_shaders); + + sc->r = r; + sc->vs_hash = cso_hash_create(); + sc->fs_hash = cso_hash_create(); + + return sc; +} + +static void +cache_destroy(struct cso_context *cso, + struct cso_hash *hash, unsigned processor) +{ + struct cso_hash_iter iter = cso_hash_first_node(hash); + + while (!cso_hash_iter_is_null(iter)) { + void *shader = (void *)cso_hash_iter_data(iter); + + if (processor == PIPE_SHADER_FRAGMENT) { + cso_delete_fragment_shader(cso, shader); + } else if (processor == PIPE_SHADER_VERTEX) { + cso_delete_vertex_shader(cso, shader); + } + iter = cso_hash_erase(hash, iter); + } + cso_hash_delete(hash); +} + +void +xa_shaders_destroy(struct xa_shaders *sc) +{ + cache_destroy(sc->r->cso, sc->vs_hash, PIPE_SHADER_VERTEX); + cache_destroy(sc->r->cso, sc->fs_hash, PIPE_SHADER_FRAGMENT); + + FREE(sc); +} + +static INLINE void * +shader_from_cache(struct pipe_context *pipe, + unsigned type, struct cso_hash *hash, unsigned key) +{ + void *shader = 0; + + struct cso_hash_iter iter = cso_hash_find(hash, key); + + if (cso_hash_iter_is_null(iter)) { + if (type == PIPE_SHADER_VERTEX) + shader = create_vs(pipe, key); + else + shader = create_fs(pipe, key); + cso_hash_insert(hash, key, shader); + } else + shader = (void *)cso_hash_iter_data(iter); + + return shader; +} + +struct xa_shader +xa_shaders_get(struct xa_shaders *sc, unsigned vs_traits, unsigned fs_traits) +{ + struct xa_shader shader = { NULL, NULL }; + void *vs, *fs; + + vs = shader_from_cache(sc->r->pipe, PIPE_SHADER_VERTEX, + sc->vs_hash, vs_traits); + fs = shader_from_cache(sc->r->pipe, PIPE_SHADER_FRAGMENT, + sc->fs_hash, fs_traits); + + debug_assert(vs && fs); + if (!vs || !fs) + return shader; + + shader.vs = vs; + shader.fs = fs; + + return shader; +} diff --git a/src/gallium/state_trackers/xa/xa_tracker.c b/src/gallium/state_trackers/xa/xa_tracker.c new file mode 100644 index 00000000000..50922d38378 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_tracker.c @@ -0,0 +1,448 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#include "xa_tracker.h" +#include "xa_priv.h" +#include "pipe/p_state.h" +#include "pipe/p_format.h" +#include "state_tracker/drm_driver.h" +#include "util/u_inlines.h" + +/* + * format_map [xa_surface_type][first..last in list]. + * Needs to be updated when enum xa_formats is updated. + */ + +static const enum xa_formats preferred_a[] = { xa_format_a8 }; + +static const enum xa_formats preferred_argb[] = + { xa_format_a8r8g8b8, xa_format_x8r8g8b8, xa_format_r5g6b5, + xa_format_x1r5g5b5 +}; +static const enum xa_formats preferred_z[] = + { xa_format_z32, xa_format_z24, xa_format_z16 }; +static const enum xa_formats preferred_sz[] = + { xa_format_x8z24, xa_format_s8z24 }; +static const enum xa_formats preferred_zs[] = + { xa_format_z24x8, xa_format_z24s8 }; +static const enum xa_formats preferred_yuv[] = { xa_format_yuv8 }; + +static const enum xa_formats *preferred[] = + { NULL, preferred_a, preferred_argb, NULL, NULL, + preferred_z, preferred_zs, preferred_sz, preferred_yuv +}; + +static const unsigned int num_preferred[] = { 0, + sizeof(preferred_a) / sizeof(enum xa_formats), + sizeof(preferred_argb) / sizeof(enum xa_formats), + 0, + 0, + sizeof(preferred_z) / sizeof(enum xa_formats), + sizeof(preferred_zs) / sizeof(enum xa_formats), + sizeof(preferred_sz) / sizeof(enum xa_formats), + sizeof(preferred_yuv) / sizeof(enum xa_formats) +}; + +static const unsigned int stype_bind[XA_LAST_SURFACE_TYPE] = { 0, + PIPE_BIND_SAMPLER_VIEW, + PIPE_BIND_SAMPLER_VIEW, + PIPE_BIND_SAMPLER_VIEW, + PIPE_BIND_SAMPLER_VIEW, + PIPE_BIND_DEPTH_STENCIL, + PIPE_BIND_DEPTH_STENCIL, + PIPE_BIND_DEPTH_STENCIL, + PIPE_BIND_SAMPLER_VIEW +}; + +static struct xa_format_descriptor +xa_get_pipe_format(enum xa_formats xa_format) +{ + struct xa_format_descriptor fdesc; + + fdesc.xa_format = xa_format; + + switch (xa_format) { + case xa_format_a8r8g8b8: + fdesc.format = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + case xa_format_x8r8g8b8: + fdesc.format = PIPE_FORMAT_B8G8R8X8_UNORM; + break; + case xa_format_r5g6b5: + fdesc.format = PIPE_FORMAT_B5G6R5_UNORM; + break; + case xa_format_x1r5g5b5: + fdesc.format = PIPE_FORMAT_B5G5R5A1_UNORM; + break; + case xa_format_a8: + fdesc.format = PIPE_FORMAT_L8_UNORM; + break; + case xa_format_z24: + fdesc.format = PIPE_FORMAT_Z24X8_UNORM; + break; + case xa_format_z16: + fdesc.format = PIPE_FORMAT_Z16_UNORM; + break; + case xa_format_z32: + fdesc.format = PIPE_FORMAT_Z32_UNORM; + break; + case xa_format_x8z24: + fdesc.format = PIPE_FORMAT_Z24X8_UNORM; + break; + case xa_format_z24x8: + fdesc.format = PIPE_FORMAT_X8Z24_UNORM; + break; + case xa_format_s8z24: + fdesc.format = PIPE_FORMAT_Z24_UNORM_S8_USCALED; + break; + case xa_format_z24s8: + fdesc.format = PIPE_FORMAT_S8_USCALED_Z24_UNORM; + break; + case xa_format_yuv8: + fdesc.format = PIPE_FORMAT_L8_UNORM; + break; + default: + fdesc.xa_format = xa_format_unknown; + break; + } + return fdesc; +} + +struct xa_tracker * +xa_tracker_create(int drm_fd) +{ + struct xa_tracker *xa = calloc(1, sizeof(struct xa_tracker)); + enum xa_surface_type stype; + unsigned int num_formats; + + if (!xa) + return NULL; + + xa->screen = driver_descriptor.create_screen(drm_fd); + if (!xa->screen) + goto out_no_screen; + + xa->default_ctx = xa_context_create(xa); + if (!xa->default_ctx) + goto out_no_pipe; + + num_formats = 0; + for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype) + num_formats += num_preferred[stype]; + + num_formats += 1; + xa->supported_formats = calloc(num_formats, sizeof(*xa->supported_formats)); + if (!xa->supported_formats) + goto out_sf_alloc_fail; + + xa->supported_formats[0] = xa_format_unknown; + num_formats = 1; + memset(xa->format_map, 0, sizeof(xa->format_map)); + + for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype) { + unsigned int bind = stype_bind[stype]; + enum xa_formats xa_format; + int i; + + for (i = 0; i < num_preferred[stype]; ++i) { + xa_format = preferred[stype][i]; + + struct xa_format_descriptor fdesc = xa_get_pipe_format(xa_format); + + if (xa->screen->is_format_supported(xa->screen, fdesc.format, + PIPE_TEXTURE_2D, 0, bind)) { + if (xa->format_map[stype][0] == 0) + xa->format_map[stype][0] = num_formats; + xa->format_map[stype][1] = num_formats; + xa->supported_formats[num_formats++] = xa_format; + } + } + } + return xa; + + out_sf_alloc_fail: + xa_context_destroy(xa->default_ctx); + out_no_pipe: + xa->screen->destroy(xa->screen); + out_no_screen: + free(xa); + return NULL; +} + +void +xa_tracker_destroy(struct xa_tracker *xa) +{ + free(xa->supported_formats); + xa_context_destroy(xa->default_ctx); + xa->screen->destroy(xa->screen); + free(xa); +} + +static int +xa_flags_compat(unsigned int old_flags, unsigned int new_flags) +{ + unsigned int flag_diff = (old_flags ^ new_flags); + + if (flag_diff == 0) + return 1; + + if (flag_diff & XA_FLAG_SHARED) + return 0; + /* + * Don't recreate if we're dropping the render target flag. + */ + if (flag_diff & XA_FLAG_RENDER_TARGET) + return ((new_flags & XA_FLAG_RENDER_TARGET) == 0); + + /* + * Always recreate for unknown / unimplemented flags. + */ + return 0; +} + +static struct xa_format_descriptor +xa_get_format_stype_depth(struct xa_tracker *xa, + enum xa_surface_type stype, unsigned int depth) +{ + unsigned int i; + struct xa_format_descriptor fdesc; + int found = 0; + + for (i = xa->format_map[stype][0]; i <= xa->format_map[stype][1]; ++i) { + fdesc = xa_get_pipe_format(xa->supported_formats[i]); + if (fdesc.xa_format != xa_format_unknown && + xa_format_depth(fdesc.xa_format) == depth) { + found = 1; + break; + } + } + + if (!found) + fdesc.xa_format = xa_format_unknown; + + return fdesc; +} + +int +xa_format_check_supported(struct xa_tracker *xa, + enum xa_formats xa_format, unsigned int flags) +{ + struct xa_format_descriptor fdesc = xa_get_pipe_format(xa_format); + unsigned int bind; + + if (fdesc.xa_format == xa_format_unknown) + return -XA_ERR_INVAL; + + bind = stype_bind[xa_format_type(fdesc.xa_format)]; + if (flags & XA_FLAG_SHARED) + bind |= PIPE_BIND_SHARED; + if (flags & XA_FLAG_RENDER_TARGET) + bind |= PIPE_BIND_RENDER_TARGET; + + if (!xa->screen->is_format_supported(xa->screen, fdesc.format, + PIPE_TEXTURE_2D, 0, bind)) + return -XA_ERR_INVAL; + + return XA_ERR_NONE; +} + +struct xa_surface * +xa_surface_create(struct xa_tracker *xa, + int width, + int height, + int depth, + enum xa_surface_type stype, + enum xa_formats xa_format, unsigned int flags) +{ + struct pipe_resource *template; + struct xa_surface *srf; + struct xa_format_descriptor fdesc; + + if (xa_format == xa_format_unknown) + fdesc = xa_get_format_stype_depth(xa, stype, depth); + else + fdesc = xa_get_pipe_format(xa_format); + + if (fdesc.xa_format == xa_format_unknown) + return NULL; + + srf = calloc(1, sizeof(*srf)); + if (!srf) + return NULL; + + template = &srf->template; + template->format = fdesc.format; + template->target = PIPE_TEXTURE_2D; + template->width0 = width; + template->height0 = height; + template->depth0 = 1; + template->array_size = 1; + template->last_level = 0; + template->bind = stype_bind[xa_format_type(fdesc.xa_format)]; + + if (flags & XA_FLAG_SHARED) + template->bind |= PIPE_BIND_SHARED; + if (flags & XA_FLAG_RENDER_TARGET) + template->bind |= PIPE_BIND_RENDER_TARGET; + + srf->tex = xa->screen->resource_create(xa->screen, template); + if (!srf->tex) + goto out_no_tex; + + srf->srf = NULL; + srf->xa = xa; + srf->flags = flags; + srf->fdesc = fdesc; + + return srf; + out_no_tex: + free(srf); + return NULL; +} + +int +xa_surface_redefine(struct xa_surface *srf, + int width, + int height, + int depth, + enum xa_surface_type stype, + enum xa_formats xa_format, + unsigned int new_flags, + int copy_contents) +{ + struct pipe_resource *template = &srf->template; + struct pipe_resource *texture; + struct pipe_box src_box; + struct xa_tracker *xa = srf->xa; + int save_width; + int save_height; + struct xa_format_descriptor fdesc; + + if (xa_format == xa_format_unknown) + fdesc = xa_get_format_stype_depth(xa, stype, depth); + else + fdesc = xa_get_pipe_format(xa_format); + + if (width == template->width0 && height == template->height0 && + template->format == fdesc.format && + xa_flags_compat(srf->flags, new_flags)) + return XA_ERR_NONE; + + template->bind = stype_bind[xa_format_type(fdesc.xa_format)]; + if (new_flags & XA_FLAG_SHARED) + template->bind |= PIPE_BIND_SHARED; + if (new_flags & XA_FLAG_RENDER_TARGET) + template->bind |= PIPE_BIND_RENDER_TARGET; + + if (copy_contents) { + if (!xa_format_type_is_color(fdesc.xa_format) || + xa_format_type(fdesc.xa_format) == xa_type_a) + return -XA_ERR_INVAL; + + if (!xa->screen->is_format_supported(xa->screen, fdesc.format, + PIPE_TEXTURE_2D, 0, + template->bind | + PIPE_BIND_RENDER_TARGET)) + return -XA_ERR_INVAL; + } + + save_width = template->width0; + save_height = template->height0; + + template->width0 = width; + template->height0 = height; + + texture = xa->screen->resource_create(xa->screen, template); + if (!texture) { + template->width0 = save_width; + template->height0 = save_height; + return -XA_ERR_NORES; + } + + pipe_surface_reference(&srf->srf, NULL); + + if (copy_contents) { + struct pipe_context *pipe = xa->default_ctx->pipe; + + u_box_origin_2d(xa_min(save_width, template->width0), + xa_min(save_height, template->height0), &src_box); + pipe->resource_copy_region(pipe, texture, + 0, 0, 0, 0, srf->tex, 0, &src_box); + pipe->flush(pipe, &xa->default_ctx->last_fence); + } + + pipe_resource_reference(&srf->tex, texture); + pipe_resource_reference(&texture, NULL); + srf->fdesc = fdesc; + srf->flags = new_flags; + + return XA_ERR_NONE; +} + +void +xa_surface_destroy(struct xa_surface *srf) +{ + pipe_surface_reference(&srf->srf, NULL); + pipe_resource_reference(&srf->tex, NULL); + free(srf); +} + +extern void +xa_tracker_version(int *major, int *minor, int *patch) +{ + *major = XA_TRACKER_VERSION_MAJOR; + *minor = XA_TRACKER_VERSION_MINOR; + *patch = XA_TRACKER_VERSION_PATCH; +} + +extern int +xa_surface_handle(struct xa_surface *srf, + uint32_t * handle, unsigned int *stride) +{ + struct winsys_handle whandle; + + struct pipe_screen *screen = srf->xa->screen; + boolean res; + + memset(&whandle, 0, sizeof(whandle)); + whandle.type = DRM_API_HANDLE_TYPE_SHARED; + res = screen->resource_get_handle(screen, srf->tex, &whandle); + if (!res) + return -XA_ERR_INVAL; + + *handle = whandle.handle; + *stride = whandle.stride; + + return XA_ERR_NONE; +} + +enum xa_formats +xa_surface_format(const struct xa_surface *srf) +{ + return srf->fdesc.xa_format; +} diff --git a/src/gallium/state_trackers/xa/xa_tracker.h b/src/gallium/state_trackers/xa/xa_tracker.h new file mode 100644 index 00000000000..62f8a210fb6 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_tracker.h @@ -0,0 +1,178 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + * The format encoding idea is partially borrowed from libpixman, but it is not + * considered a "substantial part of the software", so the pixman copyright + * is left out for simplicity, and acknowledgment is instead given in this way. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#ifndef _XA_TRACKER_H_ +#define _XA_TRACKER_H_ + +#include <stdint.h> + +#define XA_TRACKER_VERSION_MAJOR 0 +#define XA_TRACKER_VERSION_MINOR 4 +#define XA_TRACKER_VERSION_PATCH 0 + +#define XA_FLAG_SHARED (1 << 0) +#define XA_FLAG_RENDER_TARGET (1 << 1) + +#define XA_MAP_READ (1 << 0) +#define XA_MAP_WRITE (1 << 1) + +#define XA_ERR_NONE 0 +#define XA_ERR_NORES 1 +#define XA_ERR_INVAL 2 +#define XA_ERR_BUSY 3 + +enum xa_surface_type { + xa_type_other, + xa_type_a, + xa_type_argb, + xa_type_abgr, + xa_type_bgra, + xa_type_z, + xa_type_zs, + xa_type_sz, + xa_type_yuv_component +}; + +/* + * Note that these formats should not be assumed to be binary compatible with + * pixman formats, but with the below macros and a format type map, + * conversion should be simple. Macros for now. We might replace with + * inline functions. + */ + +#define xa_format(bpp,type,a,r,g,b) (((bpp) << 24) | \ + ((type) << 16) | \ + ((a) << 12) | \ + ((r) << 8) | \ + ((g) << 4) | \ + ((b))) +/* + * Non-RGBA one- and two component formats. + */ + +#define xa_format_c(bpp,type,c1,c2) (((bpp) << 24) | \ + ((type) << 16) | \ + ((c1) << 8) | \ + ((c2))) +#define xa_format_bpp(f) (((f) >> 24) ) +#define xa_format_type(f) (((f) >> 16) & 0xff) +#define xa_format_a(f) (((f) >> 12) & 0x0f) +#define xa_format_r(f) (((f) >> 8) & 0x0f) +#define xa_format_g(f) (((f) >> 4) & 0x0f) +#define xa_format_b(f) (((f) ) & 0x0f) +#define xa_format_rgb(f) (((f) ) & 0xfff) +#define xa_format_c1(f) (((f) >> 8 ) & 0xff) +#define xa_format_c2(f) (((f) ) & 0xff) +#define xa_format_argb_depth(f) (xa_format_a(f) + \ + xa_format_r(f) + \ + xa_format_g(f) + \ + xa_format_b(f)) +#define xa_format_c_depth(f) (xa_format_c1(f) + \ + xa_format_c2(f)) + +static inline int +xa_format_type_is_color(uint32_t xa_format) +{ + return (xa_format_type(xa_format) < xa_type_z); +} + +static inline unsigned int +xa_format_depth(uint32_t xa_format) +{ + return ((xa_format_type_is_color(xa_format)) ? + xa_format_argb_depth(xa_format) : xa_format_c_depth(xa_format)); +} + +enum xa_formats { + xa_format_unknown = 0, + xa_format_a8 = xa_format(8, xa_type_a, 8, 0, 0, 0), + + xa_format_a8r8g8b8 = xa_format(32, xa_type_argb, 8, 8, 8, 8), + xa_format_x8r8g8b8 = xa_format(32, xa_type_argb, 0, 8, 8, 8), + xa_format_r5g6b5 = xa_format(16, xa_type_argb, 0, 5, 6, 5), + xa_format_x1r5g5b5 = xa_format(16, xa_type_argb, 0, 5, 5, 5), + + xa_format_z16 = xa_format_c(16, xa_type_z, 16, 0), + xa_format_z32 = xa_format_c(32, xa_type_z, 32, 0), + xa_format_z24 = xa_format_c(32, xa_type_z, 24, 0), + + xa_format_x8z24 = xa_format_c(32, xa_type_sz, 24, 0), + xa_format_s8z24 = xa_format_c(32, xa_type_sz, 24, 8), + xa_format_z24x8 = xa_format_c(32, xa_type_zs, 24, 0), + xa_format_z24s8 = xa_format_c(32, xa_type_zs, 24, 8), + + xa_format_yuv8 = xa_format_c(8, xa_type_yuv_component, 8, 0) +}; + +struct xa_tracker; +struct xa_surface; + +struct xa_box { + uint16_t x1, y1, x2, y2; +}; + +extern void xa_tracker_version(int *major, int *minor, int *patch); + +extern struct xa_tracker *xa_tracker_create(int drm_fd); + +extern void xa_tracker_destroy(struct xa_tracker *xa); + +extern int xa_format_check_supported(struct xa_tracker *xa, + enum xa_formats xa_format, + unsigned int flags); + +extern struct xa_surface *xa_surface_create(struct xa_tracker *xa, + int width, + int height, + int depth, + enum xa_surface_type stype, + enum xa_formats pform, + unsigned int flags); + +enum xa_formats xa_surface_format(const struct xa_surface *srf); + +extern void xa_surface_destroy(struct xa_surface *srf); + +extern int xa_surface_redefine(struct xa_surface *srf, + int width, + int height, + int depth, + enum xa_surface_type stype, + enum xa_formats rgb_format, + unsigned int new_flags, + int copy_contents); + +extern int xa_surface_handle(struct xa_surface *srf, + uint32_t * handle, unsigned int *byte_stride); + +#endif diff --git a/src/gallium/state_trackers/xa/xa_yuv.c b/src/gallium/state_trackers/xa/xa_yuv.c new file mode 100644 index 00000000000..66cbc5393b5 --- /dev/null +++ b/src/gallium/state_trackers/xa/xa_yuv.c @@ -0,0 +1,179 @@ +/********************************************************** + * Copyright 2009-2011 VMware, 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, 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. + * + ********************************************************* + * Authors: + * Zack Rusin <zackr-at-vmware-dot-com> + * Thomas Hellstrom <thellstrom-at-vmware-dot-com> + */ + +#include "xa_context.h" +#include "xa_priv.h" +#include "util/u_inlines.h" +#include "util/u_sampler.h" +#include "util/u_surface.h" +#include "cso_cache/cso_context.h" + +static void +xa_yuv_bind_blend_state(struct xa_context *r) +{ + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.rt[0].blend_enable = 0; + blend.rt[0].colormask = PIPE_MASK_RGBA; + + /* porter&duff src */ + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + + cso_set_blend(r->cso, &blend); +} + +static void +xa_yuv_bind_shaders(struct xa_context *r) +{ + unsigned vs_traits = 0, fs_traits = 0; + struct xa_shader shader; + + vs_traits |= VS_YUV; + fs_traits |= FS_YUV; + + shader = xa_shaders_get(r->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(r->cso, shader.vs); + cso_set_fragment_shader_handle(r->cso, shader.fs); +} + +static void +xa_yuv_bind_samplers(struct xa_context *r, struct xa_surface *yuv[]) +{ + struct pipe_sampler_state *samplers[3]; + struct pipe_sampler_state sampler; + struct pipe_sampler_view *views[3]; + struct pipe_sampler_view view_templ; + unsigned int i; + + memset(&sampler, 0, sizeof(struct pipe_sampler_state)); + + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + sampler.normalized_coords = 1; + + for (i = 0; i < 3; ++i) { + samplers[i] = &sampler; + if (!yuv[i]->view) { + u_sampler_view_default_template(&view_templ, + yuv[i]->tex, yuv[i]->tex->format); + + yuv[i]->view = r->pipe->create_sampler_view(r->pipe, + yuv[i]->tex, + &view_templ); + } + views[i] = yuv[i]->view; + } + + cso_set_samplers(r->cso, 3, (const struct pipe_sampler_state **)samplers); + cso_set_fragment_sampler_views(r->cso, 3, views); +} + +static void +xa_yuv_fs_constants(struct xa_context *r, const float conversion_matrix[]) +{ + const int param_bytes = 12 * sizeof(float); + + renderer_set_constants(r, PIPE_SHADER_FRAGMENT, + conversion_matrix, param_bytes); +} + +static void +xa_yuv_destroy_sampler_views(struct xa_surface *yuv[]) +{ + unsigned int i; + + for (i = 0; i < 3; ++i) { + pipe_sampler_view_reference(&yuv[i]->view, NULL); + } +} + +extern int +xa_yuv_planar_blit(struct xa_context *r, + int src_x, + int src_y, + int src_w, + int src_h, + int dst_x, + int dst_y, + int dst_w, + int dst_h, + struct xa_box *box, + unsigned int num_boxes, + const float conversion_matrix[], + struct xa_surface *dst, struct xa_surface *yuv[]) +{ + float scale_x; + float scale_y; + struct pipe_surface srf_templ; + + if (dst_w == 0 || dst_h == 0) + return XA_ERR_NONE; + + memset(&srf_templ, 0, sizeof(srf_templ)); + u_surface_default_template(&srf_templ, dst->tex, PIPE_BIND_RENDER_TARGET); + dst->srf = r->pipe->create_surface(r->pipe, dst->tex, &srf_templ); + if (!dst->srf) + return -XA_ERR_NORES; + + renderer_bind_destination(r, dst->srf, dst->srf->width, dst->srf->height); + xa_yuv_bind_blend_state(r); + xa_yuv_bind_shaders(r); + xa_yuv_bind_samplers(r, yuv); + xa_yuv_fs_constants(r, conversion_matrix); + + scale_x = (float)src_w / (float)dst_w; + scale_y = (float)src_h / (float)dst_h; + + while (num_boxes--) { + int x = box->x1; + int y = box->y1; + int w = box->x2 - box->x1; + int h = box->y2 - box->y1; + + renderer_draw_yuv(r, + (float)src_x + scale_x * (x - dst_x), + (float)src_y + scale_y * (y - dst_y), + scale_x * w, scale_y * h, x, y, w, h, yuv); + box++; + } + + r->pipe->flush(r->pipe, &r->last_fence); + + xa_yuv_destroy_sampler_views(yuv); + pipe_surface_reference(&dst->srf, NULL); + + return XA_ERR_NONE; +} diff --git a/src/gallium/state_trackers/xorg/SConscript b/src/gallium/state_trackers/xorg/SConscript index 19315694b7c..4ea4ec4ee8b 100644 --- a/src/gallium/state_trackers/xorg/SConscript +++ b/src/gallium/state_trackers/xorg/SConscript @@ -9,10 +9,11 @@ env.Append(CPPPATH = [ '#/src/mesa', ]) -env.ParseConfig('pkg-config --cflags --libs libdrm xorg-server') +env.PkgUseModules(['DRM', 'XORG']) -if env['kms']: +if env['HAVE_KMS']: env.Append(CPPDEFINES = ['HAVE_LIBKMS']) + env.PkgUseModules(['KMS']) conf = env.Configure() diff --git a/src/gallium/state_trackers/xorg/xorg_composite.c b/src/gallium/state_trackers/xorg/xorg_composite.c index d4dc84a122b..f696b72e1e3 100644 --- a/src/gallium/state_trackers/xorg/xorg_composite.c +++ b/src/gallium/state_trackers/xorg/xorg_composite.c @@ -237,7 +237,7 @@ picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, bool boolean swizzle = FALSE; unsigned ret = 0; - if (pSrc->picture_format == pSrcPicture->format) { + if (pSrc && pSrc->picture_format == pSrcPicture->format) { if (pSrc->picture_format == PICT_a8) { if (mask) return FS_MASK_LUMINANCE; @@ -252,7 +252,7 @@ picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, bool return 0; } - if (pSrc->picture_format != PICT_a8r8g8b8) { + if (pSrc && pSrc->picture_format != PICT_a8r8g8b8) { assert(!"can not handle formats"); return 0; } @@ -355,7 +355,7 @@ bind_samplers(struct exa_context *exa, int op, struct exa_pixmap_priv *pMask, struct exa_pixmap_priv *pDst) { - struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS] = {0}; struct pipe_sampler_state src_sampler, mask_sampler; struct pipe_sampler_view view_templ; struct pipe_sampler_view *src_view; diff --git a/src/gallium/state_trackers/xorg/xorg_crtc.c b/src/gallium/state_trackers/xorg/xorg_crtc.c index 0499ed1ea0b..22e61cf7081 100644 --- a/src/gallium/state_trackers/xorg/xorg_crtc.c +++ b/src/gallium/state_trackers/xorg/xorg_crtc.c @@ -122,6 +122,7 @@ crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, drm_mode.hskew = mode->HSkew; drm_mode.vscan = mode->VScan; drm_mode.vrefresh = mode->VRefresh; + drm_mode.type = 0; if (!mode->name) xf86SetModeDefaultName(mode); strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1); diff --git a/src/gallium/state_trackers/xorg/xvmc/Makefile b/src/gallium/state_trackers/xorg/xvmc/Makefile new file mode 100644 index 00000000000..126dc6d58f1 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/Makefile @@ -0,0 +1,16 @@ +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = xvmctracker + +LIBRARY_INCLUDES = \ + $(shell pkg-config --cflags-only-I xvmc) \ + -I$(TOP)/src/gallium/winsys/g3dvl + +C_SOURCES = block.c \ + surface.c \ + context.c \ + subpicture.c \ + attributes.c + +include ../../../Makefile.template diff --git a/src/gallium/state_trackers/xorg/xvmc/attributes.c b/src/gallium/state_trackers/xorg/xvmc/attributes.c new file mode 100644 index 00000000000..817af531a32 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/attributes.c @@ -0,0 +1,156 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <stdlib.h> + +#include <X11/Xlib.h> +#include <X11/extensions/Xvlib.h> +#include <X11/extensions/XvMClib.h> + +#include <vl/vl_compositor.h> + +#include "xvmc_private.h" + +#define XV_BRIGHTNESS "XV_BRIGHTNESS" +#define XV_CONTRAST "XV_CONTRAST" +#define XV_SATURATION "XV_SATURATION" +#define XV_HUE "XV_HUE" +#define XV_COLORSPACE "XV_COLORSPACE" + +static const XvAttribute attributes[] = { + { XvGettable | XvSettable, -1000, 1000, XV_BRIGHTNESS }, + { XvGettable | XvSettable, -1000, 1000, XV_CONTRAST }, + { XvGettable | XvSettable, -1000, 1000, XV_SATURATION }, + { XvGettable | XvSettable, -1000, 1000, XV_HUE }, + { XvGettable | XvSettable, 0, 1, XV_COLORSPACE } +}; + +PUBLIC +XvAttribute* XvMCQueryAttributes(Display *dpy, XvMCContext *context, int *number) +{ + XvMCContextPrivate *context_priv; + XvAttribute *result; + + assert(dpy && number); + + if (!context || !context->privData) + return NULL; + + context_priv = context->privData; + + result = malloc(sizeof(attributes)); + if (!result) + return NULL; + + memcpy(result, attributes, sizeof(attributes)); + *number = sizeof(attributes) / sizeof(XvAttribute); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Returning %d attributes for context %p.\n", *number, context); + + return result; +} + +PUBLIC +Status XvMCSetAttribute(Display *dpy, XvMCContext *context, Atom attribute, int value) +{ + XvMCContextPrivate *context_priv; + const char *attr; + float csc[16]; + + assert(dpy); + + if (!context || !context->privData) + return XvMCBadContext; + + context_priv = context->privData; + + attr = XGetAtomName(dpy, attribute); + if (!attr) + return XvMCBadContext; + + if (strcmp(attr, XV_BRIGHTNESS)) + context_priv->procamp.brightness = value / 1000.0f; + else if (strcmp(attr, XV_CONTRAST)) + context_priv->procamp.contrast = value / 1000.0f + 1.0f; + else if (strcmp(attr, XV_SATURATION)) + context_priv->procamp.saturation = value / 1000.0f + 1.0f; + else if (strcmp(attr, XV_HUE)) + context_priv->procamp.hue = value / 1000.0f; + else if (strcmp(attr, XV_COLORSPACE)) + context_priv->color_standard = value ? + VL_CSC_COLOR_STANDARD_BT_601 : + VL_CSC_COLOR_STANDARD_BT_709; + else + return BadName; + + vl_csc_get_matrix + ( + context_priv->color_standard, + &context_priv->procamp, true, csc + ); + vl_compositor_set_csc_matrix(&context_priv->compositor, csc); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Set attribute %s to value %d.\n", attr, value); + + return Success; +} + +PUBLIC +Status XvMCGetAttribute(Display *dpy, XvMCContext *context, Atom attribute, int *value) +{ + XvMCContextPrivate *context_priv; + const char *attr; + + assert(dpy); + + if (!context || !context->privData) + return XvMCBadContext; + + context_priv = context->privData; + + attr = XGetAtomName(dpy, attribute); + if (!attr) + return XvMCBadContext; + + if (strcmp(attr, XV_BRIGHTNESS)) + *value = context_priv->procamp.brightness * 1000; + else if (strcmp(attr, XV_CONTRAST)) + *value = context_priv->procamp.contrast * 1000 - 1000; + else if (strcmp(attr, XV_SATURATION)) + *value = context_priv->procamp.saturation * 1000 + 1000; + else if (strcmp(attr, XV_HUE)) + *value = context_priv->procamp.hue * 1000; + else if (strcmp(attr, XV_COLORSPACE)) + *value = context_priv->color_standard == VL_CSC_COLOR_STANDARD_BT_709; + else + return BadName; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Got value %d for attribute %s.\n", *value, attr); + + return Success; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/block.c b/src/gallium/state_trackers/xorg/xvmc/block.c new file mode 100644 index 00000000000..6b0b21273f5 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/block.c @@ -0,0 +1,95 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <X11/Xlib.h> +#include <X11/extensions/XvMClib.h> + +#include <util/u_memory.h> + +#include "xvmc_private.h" + +PUBLIC +Status XvMCCreateBlocks(Display *dpy, XvMCContext *context, unsigned int num_blocks, XvMCBlockArray *blocks) +{ + assert(dpy); + + if (!context) + return XvMCBadContext; + if (num_blocks == 0) + return BadValue; + + assert(blocks); + + blocks->context_id = context->context_id; + blocks->num_blocks = num_blocks; + blocks->blocks = MALLOC(BLOCK_SIZE_BYTES * num_blocks); + blocks->privData = NULL; + + return Success; +} + +PUBLIC +Status XvMCDestroyBlocks(Display *dpy, XvMCBlockArray *blocks) +{ + assert(dpy); + assert(blocks); + FREE(blocks->blocks); + + return Success; +} + +PUBLIC +Status XvMCCreateMacroBlocks(Display *dpy, XvMCContext *context, unsigned int num_blocks, XvMCMacroBlockArray *blocks) +{ + assert(dpy); + + if (!context) + return XvMCBadContext; + if (num_blocks == 0) + return BadValue; + + assert(blocks); + + blocks->context_id = context->context_id; + blocks->num_blocks = num_blocks; + blocks->macro_blocks = MALLOC(sizeof(XvMCMacroBlock) * num_blocks); + blocks->privData = NULL; + + return Success; +} + +PUBLIC +Status XvMCDestroyMacroBlocks(Display *dpy, XvMCMacroBlockArray *blocks) +{ + assert(dpy); + assert(blocks); + FREE(blocks->macro_blocks); + + return Success; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/context.c b/src/gallium/state_trackers/xorg/xvmc/context.c new file mode 100644 index 00000000000..f21ebda76d3 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/context.c @@ -0,0 +1,332 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <X11/Xlibint.h> +#include <X11/extensions/XvMClib.h> + +#include <pipe/p_screen.h> +#include <pipe/p_video_decoder.h> +#include <pipe/p_video_state.h> +#include <pipe/p_state.h> + +#include <util/u_memory.h> + +#include <vl/vl_csc.h> +#include <vl_winsys.h> + +#include "xvmc_private.h" + +static Status Validate(Display *dpy, XvPortID port, int surface_type_id, + unsigned int width, unsigned int height, int flags, + bool *found_port, int *screen, int *chroma_format, + int *mc_type, int *surface_flags, + unsigned short *subpic_max_w, + unsigned short *subpic_max_h) +{ + bool found_surface = false; + XvAdaptorInfo *adaptor_info; + unsigned int num_adaptors; + int num_types; + unsigned int max_width = 0, max_height = 0; + Status ret; + + assert(dpy); + assert(found_port); + assert(screen); + assert(chroma_format); + assert(mc_type); + assert(surface_flags); + assert(subpic_max_w); + assert(subpic_max_h); + + *found_port = false; + + for (unsigned int i = 0; i < XScreenCount(dpy); ++i) { + ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info); + if (ret != Success) + return ret; + + for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) { + for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) { + XvMCSurfaceInfo *surface_info; + + if (adaptor_info[j].base_id + k != port) + continue; + + *found_port = true; + + surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types); + if (!surface_info) { + XvFreeAdaptorInfo(adaptor_info); + return BadAlloc; + } + + for (unsigned int l = 0; l < num_types && !found_surface; ++l) { + if (surface_info[l].surface_type_id != surface_type_id) + continue; + + found_surface = true; + max_width = surface_info[l].max_width; + max_height = surface_info[l].max_height; + *chroma_format = surface_info[l].chroma_format; + *mc_type = surface_info[l].mc_type; + *surface_flags = surface_info[l].flags; + *subpic_max_w = surface_info[l].subpicture_max_width; + *subpic_max_h = surface_info[l].subpicture_max_height; + *screen = i; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \ + "[XvMC] screen=%u, port=%u\n" \ + "[XvMC] id=0x%08X\n" \ + "[XvMC] max width=%u, max height=%u\n" \ + "[XvMC] chroma format=0x%08X\n" \ + "[XvMC] acceleration level=0x%08X\n" \ + "[XvMC] flags=0x%08X\n" \ + "[XvMC] subpicture max width=%u, max height=%u\n", + i, port, surface_type_id, max_width, max_height, *chroma_format, + *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h); + } + + XFree(surface_info); + } + } + + XvFreeAdaptorInfo(adaptor_info); + } + + if (!*found_port) { + XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n"); + return XvBadPort; + } + if (!found_surface) { + XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n"); + return BadMatch; + } + if (width > max_width || height > max_height) { + XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n", + width, height, max_width, max_height); + return BadValue; + } + if (flags != XVMC_DIRECT && flags != 0) { + XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags); + return BadValue; + } + + return Success; +} + +static enum pipe_video_profile ProfileToPipe(int xvmc_profile) +{ + if (xvmc_profile & XVMC_MPEG_1) + assert(0); + if (xvmc_profile & XVMC_MPEG_2) + return PIPE_VIDEO_PROFILE_MPEG2_MAIN; + if (xvmc_profile & XVMC_H263) + assert(0); + if (xvmc_profile & XVMC_MPEG_4) + assert(0); + + assert(0); + + XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile); + + return -1; +} + +static enum pipe_video_chroma_format FormatToPipe(int xvmc_format) +{ + switch (xvmc_format) { + case XVMC_CHROMA_FORMAT_420: + return PIPE_VIDEO_CHROMA_FORMAT_420; + case XVMC_CHROMA_FORMAT_422: + return PIPE_VIDEO_CHROMA_FORMAT_422; + case XVMC_CHROMA_FORMAT_444: + return PIPE_VIDEO_CHROMA_FORMAT_444; + default: + assert(0); + } + + XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format); + + return -1; +} + +PUBLIC +Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id, + int width, int height, int flags, XvMCContext *context) +{ + bool found_port; + int scrn = 0; + int chroma_format = 0; + int mc_type = 0; + int surface_flags = 0; + unsigned short subpic_max_w = 0; + unsigned short subpic_max_h = 0; + Status ret; + struct vl_screen *vscreen; + struct vl_context *vctx; + XvMCContextPrivate *context_priv; + float csc[16]; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context); + + assert(dpy); + + if (!context) + return XvMCBadContext; + + ret = Validate(dpy, port, surface_type_id, width, height, flags, + &found_port, &scrn, &chroma_format, &mc_type, &surface_flags, + &subpic_max_w, &subpic_max_h); + + /* Success and XvBadPort have the same value */ + if (ret != Success || !found_port) + return ret; + + /* XXX: Current limits */ + if (chroma_format != XVMC_CHROMA_FORMAT_420) { + XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n"); + return BadImplementation; + } + if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) { + XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n"); + return BadImplementation; + } + if (surface_flags & XVMC_INTRA_UNSIGNED) { + XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n"); + return BadImplementation; + } + + context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); + if (!context_priv) + return BadAlloc; + + /* TODO: Reuse screen if process creates another context */ + vscreen = vl_screen_create(dpy, scrn); + + if (!vscreen) { + XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n"); + FREE(context_priv); + return BadAlloc; + } + + vctx = vl_video_create(vscreen); + if (!vctx) { + XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n"); + vl_screen_destroy(vscreen); + FREE(context_priv); + return BadAlloc; + } + + context_priv->decoder = vctx->pipe->create_video_decoder + ( + vctx->pipe, + ProfileToPipe(mc_type), + (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC, + FormatToPipe(chroma_format), + width, height + ); + + if (!context_priv->decoder) { + XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n"); + vl_video_destroy(vctx); + vl_screen_destroy(vscreen); + FREE(context_priv); + return BadAlloc; + } + + if (!vl_compositor_init(&context_priv->compositor, vctx->pipe)) { + XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n"); + context_priv->decoder->destroy(context_priv->decoder); + vl_video_destroy(vctx); + vl_screen_destroy(vscreen); + FREE(context_priv); + return BadAlloc; + } + + context_priv->color_standard = + debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? + VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601; + context_priv->procamp = vl_default_procamp; + + vl_csc_get_matrix + ( + context_priv->color_standard, + &context_priv->procamp, true, csc + ); + vl_compositor_set_csc_matrix(&context_priv->compositor, csc); + + context_priv->vctx = vctx; + context_priv->subpicture_max_width = subpic_max_w; + context_priv->subpicture_max_height = subpic_max_h; + + context->context_id = XAllocID(dpy); + context->surface_type_id = surface_type_id; + context->width = width; + context->height = height; + context->flags = flags; + context->port = port; + context->privData = context_priv; + + SyncHandle(); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context); + + return Success; +} + +PUBLIC +Status XvMCDestroyContext(Display *dpy, XvMCContext *context) +{ + struct vl_screen *vscreen; + struct vl_context *vctx; + XvMCContextPrivate *context_priv; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context); + + assert(dpy); + + if (!context || !context->privData) + return XvMCBadContext; + + context_priv = context->privData; + vctx = context_priv->vctx; + vscreen = vctx->vscreen; + pipe_surface_reference(&context_priv->drawable_surface, NULL); + context_priv->decoder->destroy(context_priv->decoder); + vl_compositor_cleanup(&context_priv->compositor); + vl_video_destroy(vctx); + vl_screen_destroy(vscreen); + FREE(context_priv); + context->privData = NULL; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context); + + return Success; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/subpicture.c b/src/gallium/state_trackers/xorg/xvmc/subpicture.c new file mode 100644 index 00000000000..7d6ff061eb7 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/subpicture.c @@ -0,0 +1,561 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> + +#include <X11/Xlibint.h> +#include <X11/extensions/XvMClib.h> +#include <xorg/fourcc.h> + +#include <pipe/p_screen.h> +#include <pipe/p_video_decoder.h> +#include <pipe/p_state.h> + +#include <util/u_memory.h> +#include <util/u_math.h> +#include <util/u_format.h> +#include <util/u_sampler.h> +#include <util/u_rect.h> + +#include <vl_winsys.h> + +#include "xvmc_private.h" + +#define FOURCC_RGB 0x0000003 + +static enum pipe_format XvIDToPipe(int xvimage_id) +{ + switch (xvimage_id) { + case FOURCC_RGB: + return PIPE_FORMAT_B8G8R8X8_UNORM; + + case FOURCC_AI44: + case FOURCC_IA44: + return PIPE_FORMAT_L4A4_UNORM; + + default: + XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); + return PIPE_FORMAT_NONE; + } +} + +static unsigned NumPaletteEntries4XvID(int xvimage_id) +{ + switch (xvimage_id) { + case FOURCC_RGB: + return 0; + + case FOURCC_AI44: + case FOURCC_IA44: + return 16; + + default: + XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); + return 0; + } +} + +static void XvIDToSwizzle(int xvimage_id, struct pipe_sampler_view *tmpl) +{ + switch (xvimage_id) { + default: + XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); + + /* fall through */ + case FOURCC_RGB: + tmpl->swizzle_r = PIPE_SWIZZLE_BLUE; + tmpl->swizzle_g = PIPE_SWIZZLE_GREEN; + tmpl->swizzle_b = PIPE_SWIZZLE_RED; + tmpl->swizzle_a = PIPE_SWIZZLE_ONE; + break; + + case FOURCC_IA44: + tmpl->swizzle_r = PIPE_SWIZZLE_ALPHA; + tmpl->swizzle_g = PIPE_SWIZZLE_ZERO; + tmpl->swizzle_b = PIPE_SWIZZLE_ZERO; + tmpl->swizzle_a = PIPE_SWIZZLE_RED; + break; + + case FOURCC_AI44: + tmpl->swizzle_r = PIPE_SWIZZLE_RED; + tmpl->swizzle_g = PIPE_SWIZZLE_ZERO; + tmpl->swizzle_b = PIPE_SWIZZLE_ZERO; + tmpl->swizzle_a = PIPE_SWIZZLE_ALPHA; + break; + } +} + +static int PipeToComponentOrder(enum pipe_format format, char *component_order) +{ + assert(component_order); + + switch (format) { + case PIPE_FORMAT_B8G8R8X8_UNORM: + return 0; + + case PIPE_FORMAT_L4A4_UNORM: + component_order[0] = 'Y'; + component_order[1] = 'U'; + component_order[2] = 'V'; + component_order[3] = 'A'; + return 4; + + default: + XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized PIPE_FORMAT 0x%08X.\n", format); + component_order[0] = 0; + component_order[1] = 0; + component_order[2] = 0; + component_order[3] = 0; + return 0; + } +} + +static Status Validate(Display *dpy, XvPortID port, int surface_type_id, int xvimage_id) +{ + XvImageFormatValues *subpictures; + int num_subpics; + unsigned int i; + + subpictures = XvMCListSubpictureTypes(dpy, port, surface_type_id, &num_subpics); + if (num_subpics < 1) { + if (subpictures) + XFree(subpictures); + return BadMatch; + } + if (!subpictures) + return BadAlloc; + + for (i = 0; i < num_subpics; ++i) { + if (subpictures[i].id == xvimage_id) { + XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested subpicture format.\n" \ + "[XvMC] port=%u\n" \ + "[XvMC] surface id=0x%08X\n" \ + "[XvMC] image id=0x%08X\n" \ + "[XvMC] type=%08X\n" \ + "[XvMC] byte order=%08X\n" \ + "[XvMC] bits per pixel=%u\n" \ + "[XvMC] format=%08X\n" \ + "[XvMC] num planes=%d\n", + port, surface_type_id, xvimage_id, subpictures[i].type, subpictures[i].byte_order, + subpictures[i].bits_per_pixel, subpictures[i].format, subpictures[i].num_planes); + if (subpictures[i].type == XvRGB) { + XVMC_MSG(XVMC_TRACE, "[XvMC] depth=%d\n" \ + "[XvMC] red mask=0x%08X\n" \ + "[XvMC] green mask=0x%08X\n" \ + "[XvMC] blue mask=0x%08X\n", + subpictures[i].depth, subpictures[i].red_mask, + subpictures[i].green_mask, subpictures[i].blue_mask); + } + else if (subpictures[i].type == XvYUV) { + XVMC_MSG(XVMC_TRACE, "[XvMC] y sample bits=0x%08X\n" \ + "[XvMC] u sample bits=0x%08X\n" \ + "[XvMC] v sample bits=0x%08X\n" \ + "[XvMC] horz y period=%u\n" \ + "[XvMC] horz u period=%u\n" \ + "[XvMC] horz v period=%u\n" \ + "[XvMC] vert y period=%u\n" \ + "[XvMC] vert u period=%u\n" \ + "[XvMC] vert v period=%u\n", + subpictures[i].y_sample_bits, subpictures[i].u_sample_bits, subpictures[i].v_sample_bits, + subpictures[i].horz_y_period, subpictures[i].horz_u_period, subpictures[i].horz_v_period, + subpictures[i].vert_y_period, subpictures[i].vert_u_period, subpictures[i].vert_v_period); + } + break; + } + } + + XFree(subpictures); + + return i < num_subpics ? Success : BadMatch; +} + +static void +upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst, + const struct pipe_box *dst_box, const void *src, unsigned src_stride, + unsigned src_x, unsigned src_y) +{ + struct pipe_transfer *transfer; + void *map; + + transfer = pipe->get_transfer(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, dst_box); + if (!transfer) + return; + + map = pipe->transfer_map(pipe, transfer); + if (map) { + util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0, + dst_box->width, dst_box->height, + src, src_stride, src_x, src_y); + + pipe->transfer_unmap(pipe, transfer); + } + + pipe->transfer_destroy(pipe, transfer); +} + +PUBLIC +Status XvMCCreateSubpicture(Display *dpy, XvMCContext *context, XvMCSubpicture *subpicture, + unsigned short width, unsigned short height, int xvimage_id) +{ + XvMCContextPrivate *context_priv; + XvMCSubpicturePrivate *subpicture_priv; + struct pipe_context *pipe; + struct pipe_resource tex_templ, *tex; + struct pipe_sampler_view sampler_templ; + Status ret; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Creating subpicture %p.\n", subpicture); + + assert(dpy); + + if (!context) + return XvMCBadContext; + + context_priv = context->privData; + pipe = context_priv->vctx->pipe; + + if (!subpicture) + return XvMCBadSubpicture; + + if (width > context_priv->subpicture_max_width || + height > context_priv->subpicture_max_height) + return BadValue; + + ret = Validate(dpy, context->port, context->surface_type_id, xvimage_id); + if (ret != Success) + return ret; + + subpicture_priv = CALLOC(1, sizeof(XvMCSubpicturePrivate)); + if (!subpicture_priv) + return BadAlloc; + + memset(&tex_templ, 0, sizeof(tex_templ)); + tex_templ.target = PIPE_TEXTURE_2D; + tex_templ.format = XvIDToPipe(xvimage_id); + tex_templ.last_level = 0; + if (pipe->screen->get_video_param(pipe->screen, + PIPE_VIDEO_PROFILE_UNKNOWN, + PIPE_VIDEO_CAP_NPOT_TEXTURES)) { + tex_templ.width0 = width; + tex_templ.height0 = height; + } + else { + tex_templ.width0 = util_next_power_of_two(width); + tex_templ.height0 = util_next_power_of_two(height); + } + tex_templ.depth0 = 1; + tex_templ.array_size = 1; + tex_templ.usage = PIPE_USAGE_DYNAMIC; + tex_templ.bind = PIPE_BIND_SAMPLER_VIEW; + tex_templ.flags = 0; + + tex = pipe->screen->resource_create(pipe->screen, &tex_templ); + + memset(&sampler_templ, 0, sizeof(sampler_templ)); + u_sampler_view_default_template(&sampler_templ, tex, tex->format); + XvIDToSwizzle(xvimage_id, &sampler_templ); + + subpicture_priv->sampler = pipe->create_sampler_view(pipe, tex, &sampler_templ); + pipe_resource_reference(&tex, NULL); + if (!subpicture_priv->sampler) { + FREE(subpicture_priv); + return BadAlloc; + } + + subpicture_priv->context = context; + subpicture->subpicture_id = XAllocID(dpy); + subpicture->context_id = context->context_id; + subpicture->xvimage_id = xvimage_id; + subpicture->width = width; + subpicture->height = height; + subpicture->num_palette_entries = NumPaletteEntries4XvID(xvimage_id); + subpicture->entry_bytes = PipeToComponentOrder(tex_templ.format, subpicture->component_order); + subpicture->privData = subpicture_priv; + + if (subpicture->num_palette_entries > 0) { + tex_templ.target = PIPE_TEXTURE_1D; + tex_templ.format = PIPE_FORMAT_R8G8B8A8_UNORM; + tex_templ.width0 = subpicture->num_palette_entries; + tex_templ.height0 = 1; + tex_templ.usage = PIPE_USAGE_STATIC; + + tex = pipe->screen->resource_create(pipe->screen, &tex_templ); + + memset(&sampler_templ, 0, sizeof(sampler_templ)); + u_sampler_view_default_template(&sampler_templ, tex, tex->format); + sampler_templ.swizzle_a = PIPE_SWIZZLE_ONE; + subpicture_priv->palette = pipe->create_sampler_view(pipe, tex, &sampler_templ); + pipe_resource_reference(&tex, NULL); + if (!subpicture_priv->sampler) { + FREE(subpicture_priv); + return BadAlloc; + } + } + + SyncHandle(); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p created.\n", subpicture); + + return Success; +} + +PUBLIC +Status XvMCClearSubpicture(Display *dpy, XvMCSubpicture *subpicture, short x, short y, + unsigned short width, unsigned short height, unsigned int color) +{ + XvMCSubpicturePrivate *subpicture_priv; + XvMCContextPrivate *context_priv; + struct pipe_context *pipe; + struct pipe_sampler_view *dst; + struct pipe_box dst_box = {x, y, 0, width, height, 1}; + struct pipe_transfer *transfer; + union util_color uc; + void *map; + + assert(dpy); + + if (!subpicture) + return XvMCBadSubpicture; + + /* Convert color to float */ + util_format_read_4f(PIPE_FORMAT_B8G8R8A8_UNORM, + uc.f, 1, &color, 4, + 0, 0, 1, 1); + + subpicture_priv = subpicture->privData; + context_priv = subpicture_priv->context->privData; + pipe = context_priv->vctx->pipe; + dst = subpicture_priv->sampler; + + /* TODO: Assert clear rect is within bounds? Or clip? */ + transfer = pipe->get_transfer(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE, &dst_box); + if (!transfer) + return XvMCBadSubpicture; + + map = pipe->transfer_map(pipe, transfer); + if (map) { + util_fill_rect(map, dst->texture->format, transfer->stride, 0, 0, + dst_box.width, dst_box.height, &uc); + + pipe->transfer_unmap(pipe, transfer); + } + + pipe->transfer_destroy(pipe, transfer); + + return Success; +} + +PUBLIC +Status XvMCCompositeSubpicture(Display *dpy, XvMCSubpicture *subpicture, XvImage *image, + short srcx, short srcy, unsigned short width, unsigned short height, + short dstx, short dsty) +{ + XvMCSubpicturePrivate *subpicture_priv; + XvMCContextPrivate *context_priv; + struct pipe_context *pipe; + struct pipe_box dst_box = {dstx, dsty, 0, width, height, 1}; + unsigned src_stride; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Compositing subpicture %p.\n", subpicture); + + assert(dpy); + + if (!subpicture) + return XvMCBadSubpicture; + + assert(image); + + if (subpicture->xvimage_id != image->id) + return BadMatch; + + /* No planar support for now */ + if (image->num_planes != 1) + return BadMatch; + + subpicture_priv = subpicture->privData; + context_priv = subpicture_priv->context->privData; + pipe = context_priv->vctx->pipe; + + /* clipping should be done by upload_sampler and regardles what the documentation + says image->pitches[0] doesn't seems to be in bytes, so don't use it */ + src_stride = image->width * util_format_get_blocksize(subpicture_priv->sampler->texture->format); + upload_sampler(pipe, subpicture_priv->sampler, &dst_box, image->data, src_stride, srcx, srcy); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p composited.\n", subpicture); + + return Success; +} + +PUBLIC +Status XvMCDestroySubpicture(Display *dpy, XvMCSubpicture *subpicture) +{ + XvMCSubpicturePrivate *subpicture_priv; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying subpicture %p.\n", subpicture); + + assert(dpy); + + if (!subpicture) + return XvMCBadSubpicture; + + subpicture_priv = subpicture->privData; + pipe_sampler_view_reference(&subpicture_priv->sampler, NULL); + pipe_sampler_view_reference(&subpicture_priv->palette, NULL); + FREE(subpicture_priv); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p destroyed.\n", subpicture); + + return Success; +} + +PUBLIC +Status XvMCSetSubpicturePalette(Display *dpy, XvMCSubpicture *subpicture, unsigned char *palette) +{ + XvMCSubpicturePrivate *subpicture_priv; + XvMCContextPrivate *context_priv; + struct pipe_context *pipe; + struct pipe_box dst_box = {0, 0, 0, 0, 1, 1}; + + assert(dpy); + assert(palette); + + if (!subpicture) + return XvMCBadSubpicture; + + subpicture_priv = subpicture->privData; + context_priv = subpicture_priv->context->privData; + pipe = context_priv->vctx->pipe; + + dst_box.width = subpicture->num_palette_entries; + + upload_sampler(pipe, subpicture_priv->palette, &dst_box, palette, 0, 0, 0); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Palette of Subpicture %p set.\n", subpicture); + + return Success; +} + +PUBLIC +Status XvMCBlendSubpicture(Display *dpy, XvMCSurface *target_surface, XvMCSubpicture *subpicture, + short subx, short suby, unsigned short subw, unsigned short subh, + short surfx, short surfy, unsigned short surfw, unsigned short surfh) +{ + struct pipe_video_rect src_rect = {subx, suby, subw, subh}; + struct pipe_video_rect dst_rect = {surfx, surfy, surfw, surfh}; + + XvMCSurfacePrivate *surface_priv; + XvMCSubpicturePrivate *subpicture_priv; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Associating subpicture %p with surface %p.\n", subpicture, target_surface); + + assert(dpy); + + if (!target_surface) + return XvMCBadSurface; + + if (!subpicture) + return XvMCBadSubpicture; + + if (target_surface->context_id != subpicture->context_id) + return BadMatch; + + /* TODO: Verify against subpicture independent scaling */ + + surface_priv = target_surface->privData; + subpicture_priv = subpicture->privData; + + /* TODO: Assert rects are within bounds? Or clip? */ + subpicture_priv->src_rect = src_rect; + subpicture_priv->dst_rect = dst_rect; + + surface_priv->subpicture = subpicture; + subpicture_priv->surface = target_surface; + + return Success; +} + +PUBLIC +Status XvMCBlendSubpicture2(Display *dpy, XvMCSurface *source_surface, XvMCSurface *target_surface, + XvMCSubpicture *subpicture, short subx, short suby, unsigned short subw, unsigned short subh, + short surfx, short surfy, unsigned short surfw, unsigned short surfh) +{ + assert(dpy); + + if (!source_surface || !target_surface) + return XvMCBadSurface; + + if (!subpicture) + return XvMCBadSubpicture; + + if (source_surface->context_id != subpicture->context_id) + return BadMatch; + + if (source_surface->context_id != subpicture->context_id) + return BadMatch; + + /* TODO: Assert rects are within bounds? Or clip? */ + + return Success; +} + +PUBLIC +Status XvMCSyncSubpicture(Display *dpy, XvMCSubpicture *subpicture) +{ + assert(dpy); + + if (!subpicture) + return XvMCBadSubpicture; + + return Success; +} + +PUBLIC +Status XvMCFlushSubpicture(Display *dpy, XvMCSubpicture *subpicture) +{ + assert(dpy); + + if (!subpicture) + return XvMCBadSubpicture; + + return Success; +} + +PUBLIC +Status XvMCGetSubpictureStatus(Display *dpy, XvMCSubpicture *subpicture, int *status) +{ + assert(dpy); + + if (!subpicture) + return XvMCBadSubpicture; + + assert(status); + + /* TODO */ + *status = 0; + + return Success; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/surface.c b/src/gallium/state_trackers/xorg/xvmc/surface.c new file mode 100644 index 00000000000..0c53b730287 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/surface.c @@ -0,0 +1,666 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <stdio.h> + +#include <X11/Xlibint.h> + +#include <pipe/p_video_decoder.h> +#include <pipe/p_video_state.h> +#include <pipe/p_state.h> + +#include <util/u_inlines.h> +#include <util/u_memory.h> +#include <util/u_math.h> + +#include <vl_winsys.h> + +#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, + const XvMCMacroBlock *xvmc_mb, + const XvMCBlockArray *xvmc_blocks) +{ + enum pipe_mpeg12_dct_intra intra; + enum pipe_mpeg12_dct_type coding; + + unsigned tb, x, y, luma_blocks; + short *blocks; + + assert(surface); + assert(xvmc_mb); + + 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]) { + + 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; + + surface->ycbcr[0].num_blocks_added++; + surface->ycbcr[0].stream++; + + luma_blocks++; + } + } + } + + 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]) { + + 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; + + memcpy(surface->ycbcr[tb].buffer, blocks, BLOCK_SIZE_BYTES); + + surface->ycbcr[tb].num_blocks_added++; + surface->ycbcr[tb].stream++; + surface->ycbcr[tb].buffer += BLOCK_SIZE_SAMPLES; + blocks += BLOCK_SIZE_SAMPLES; + } + } + +} + +static void +MacroBlocksToPipe(XvMCSurfacePrivate *surface, + unsigned int xvmc_picture_structure, + const XvMCMacroBlock *xvmc_mb, + const XvMCBlockArray *xvmc_blocks, + unsigned int num_macroblocks) +{ + unsigned int i, j; + + assert(xvmc_mb); + assert(xvmc_blocks); + assert(num_macroblocks); + + for (i = 0; i < num_macroblocks; ++i) { + unsigned mv_pos = xvmc_mb->x + surface->mv_stride * xvmc_mb->y; + unsigned mv_weights[2]; + + if (xvmc_mb->macroblock_type & (XVMC_MB_TYPE_PATTERN | XVMC_MB_TYPE_INTRA)) + UploadYcbcrBlocks(surface, xvmc_mb, xvmc_blocks); + + MacroBlockTypeToPipeWeights(xvmc_mb, mv_weights); + + for (j = 0; j < 2; ++j) { + if (!surface->ref[j].mv) continue; + + surface->ref[j].mv[mv_pos] = MotionVectorToPipe + ( + xvmc_mb, j, + j ? XVMC_SELECT_FIRST_BACKWARD : XVMC_SELECT_FIRST_FORWARD, + mv_weights[j] + ); + } + + ++xvmc_mb; + } +} + +static void +unmap_and_flush_surface(XvMCSurfacePrivate *surface) +{ + struct pipe_video_buffer *ref_frames[2]; + XvMCContextPrivate *context_priv; + unsigned i, num_ycbcr_blocks[3]; + + 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; + + assert(ref); + + unmap_and_flush_surface(ref); + surface->ref[i].surface = NULL; + ref_frames[i] = ref->video_buffer; + } else { + ref_frames[i] = NULL; + } + } + + 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; + } +} + +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; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface); + + assert(dpy); + + if (!context) + return XvMCBadContext; + if (!surface) + return XvMCBadSurface; + + context_priv = context->privData; + pipe = context_priv->vctx->pipe; + + surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate)); + if (!surface_priv) + 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, + context_priv->decoder->width, context_priv->decoder->height + ); + + surface_priv->context = context; + + surface->surface_id = XAllocID(dpy); + surface->context_id = context->context_id; + surface->surface_type_id = context->surface_type_id; + surface->width = context->width; + surface->height = context->height; + surface->privData = surface_priv; + + SyncHandle(); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface); + + return Success; +} + +PUBLIC +Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure, + XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface, + unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock, + XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks +) +{ + struct pipe_video_decode_buffer *t_buffer; + + 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); + + assert(dpy); + + if (!context || !context->privData) + return XvMCBadContext; + if (!target_surface || !target_surface->privData) + return XvMCBadSurface; + + if (picture_structure != XVMC_TOP_FIELD && + picture_structure != XVMC_BOTTOM_FIELD && + picture_structure != XVMC_FRAME_PICTURE) + return BadValue; + /* Bkwd pred equivalent to fwd (past && !future) */ + if (future_surface && !past_surface) + return BadMatch; + + assert(context->context_id == target_surface->context_id); + assert(!past_surface || context->context_id == past_surface->context_id); + assert(!future_surface || context->context_id == future_surface->context_id); + + assert(macroblocks); + assert(blocks); + + assert(macroblocks->context_id == context->context_id); + assert(blocks->context_id == context->context_id); + + assert(flags == 0 || flags == XVMC_SECOND_FIELD); + + target_surface_priv = target_surface->privData; + past_surface_priv = past_surface ? past_surface->privData : NULL; + future_surface_priv = future_surface ? future_surface->privData : NULL; + + assert(target_surface_priv->context == context); + 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 + if (past_surface) + unmap_and_flush_surface(past_surface->privData); + + if (future_surface) + unmap_and_flush_surface(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 || + (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 (!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); + } + + 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; + } + + target_surface_priv->mapped = 1; + } + + MacroBlocksToPipe(target_surface_priv, picture_structure, xvmc_mb, blocks, num_macroblocks); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface); + + return Success; +} + +PUBLIC +Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface) +{ + assert(dpy); + + if (!surface) + return XvMCBadSurface; + + // don't call flush here, because this is usually + // called once for every slice instead of every frame + + XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface); + + return Success; +} + +PUBLIC +Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface) +{ + assert(dpy); + + if (!surface) + return XvMCBadSurface; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface); + + return Success; +} + +PUBLIC +Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable, + short srcx, short srcy, unsigned short srcw, unsigned short srch, + short destx, short desty, unsigned short destw, unsigned short desth, + int flags) +{ + static int dump_window = -1; + + struct pipe_context *pipe; + struct vl_compositor *compositor; + + XvMCSurfacePrivate *surface_priv; + XvMCContextPrivate *context_priv; + XvMCSubpicturePrivate *subpicture_priv; + XvMCContext *context; + struct pipe_video_rect src_rect = {srcx, srcy, srcw, srch}; + struct pipe_video_rect dst_rect = {destx, desty, destw, desth}; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface); + + assert(dpy); + + if (!surface || !surface->privData) + return XvMCBadSurface; + + surface_priv = surface->privData; + context = surface_priv->context; + context_priv = context->privData; + + assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE); + assert(srcx + srcw - 1 < surface->width); + assert(srcy + srch - 1 < surface->height); + + subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL; + pipe = context_priv->vctx->pipe; + compositor = &context_priv->compositor; + + if (!context_priv->drawable_surface || + context_priv->dst_rect.x != dst_rect.x || context_priv->dst_rect.y != dst_rect.y || + context_priv->dst_rect.w != dst_rect.w || context_priv->dst_rect.h != dst_rect.h) { + + pipe_surface_reference(&context_priv->drawable_surface, NULL); + context_priv->drawable_surface = vl_drawable_surface_get(context_priv->vctx, drawable); + context_priv->dst_rect = dst_rect; + vl_compositor_reset_dirty_area(compositor); + } + + if (!context_priv->drawable_surface) + return BadDrawable; + + /* + * Some apps (mplayer) hit these asserts because they call + * this function after the window has been resized by the WM + * but before they've handled the corresponding XEvent and + * know about the new dimensions. The output should be clipped + * until the app updates destw and desth. + */ + /* + assert(destx + destw - 1 < drawable_surface->width); + assert(desty + desth - 1 < drawable_surface->height); + */ + + unmap_and_flush_surface(surface_priv); + + vl_compositor_clear_layers(compositor); + vl_compositor_set_buffer_layer(compositor, 0, surface_priv->video_buffer, &src_rect, NULL); + + if (subpicture_priv) { + XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture); + + assert(subpicture_priv->surface == surface); + + if (subpicture_priv->palette) + vl_compositor_set_palette_layer(compositor, 1, subpicture_priv->sampler, subpicture_priv->palette, + &subpicture_priv->src_rect, &subpicture_priv->dst_rect); + else + vl_compositor_set_rgba_layer(compositor, 1, subpicture_priv->sampler, + &subpicture_priv->src_rect, &subpicture_priv->dst_rect); + + surface_priv->subpicture = NULL; + subpicture_priv->surface = NULL; + } + + // 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); + + pipe->flush(pipe, &surface_priv->fence); + + XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface); + + pipe->screen->flush_frontbuffer + ( + pipe->screen, + context_priv->drawable_surface->texture, + 0, 0, + vl_contextprivate_get(context_priv->vctx, context_priv->drawable_surface) + ); + + if(dump_window == -1) { + dump_window = debug_get_num_option("XVMC_DUMP", 0); + } + + if(dump_window) { + static unsigned int framenum = 0; + char cmd[256]; + + sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum); + if (system(cmd) != 0) + XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface); + } + + XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface); + + return Success; +} + +PUBLIC +Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status) +{ + struct pipe_context *pipe; + XvMCSurfacePrivate *surface_priv; + XvMCContextPrivate *context_priv; + + assert(dpy); + + if (!surface) + return XvMCBadSurface; + + assert(status); + + surface_priv = surface->privData; + context_priv = surface_priv->context->privData; + pipe = context_priv->vctx->pipe; + + *status = 0; + + if (surface_priv->fence) + if (!pipe->screen->fence_signalled(pipe->screen, surface_priv->fence)) + *status |= XVMC_RENDERING; + + return Success; +} + +PUBLIC +Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface) +{ + XvMCSurfacePrivate *surface_priv; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface); + + assert(dpy); + + if (!surface || !surface->privData) + return XvMCBadSurface; + + surface_priv = surface->privData; + + if (surface_priv->mapped) + surface_priv->decode_buffer->end_frame(surface_priv->decode_buffer); + surface_priv->decode_buffer->destroy(surface_priv->decode_buffer); + surface_priv->video_buffer->destroy(surface_priv->video_buffer); + FREE(surface_priv); + surface->privData = NULL; + + XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface); + + return Success; +} + +PUBLIC +Status XvMCHideSurface(Display *dpy, XvMCSurface *surface) +{ + assert(dpy); + + if (!surface || !surface->privData) + return XvMCBadSurface; + + /* No op, only for overlaid rendering */ + + return Success; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/.gitignore b/src/gallium/state_trackers/xorg/xvmc/tests/.gitignore new file mode 100644 index 00000000000..9a8e05d9472 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/.gitignore @@ -0,0 +1,6 @@ +test_context +test_surface +test_subpicture +test_blocks +test_rendering +xvmc_bench diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/Makefile b/src/gallium/state_trackers/xorg/xvmc/tests/Makefile new file mode 100644 index 00000000000..88b03763563 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/Makefile @@ -0,0 +1,31 @@ +TOP = ../../../../../.. +include $(TOP)/configs/current + +LIBS = -lXvMCW -lXvMC -lXv -lX11 + +############################################# + +.PHONY: default clean + +default: test_context test_surface test_subpicture test_blocks test_rendering xvmc_bench + +test_context: test_context.o testlib.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +test_surface: test_surface.o testlib.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +test_subpicture: test_subpicture.o testlib.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +test_blocks: test_blocks.o testlib.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +test_rendering: test_rendering.o testlib.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +xvmc_bench: xvmc_bench.o testlib.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) -rf *.o test_context test_surface test_subpicture test_blocks test_rendering xvmc_bench diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c new file mode 100644 index 00000000000..994e3ca4d14 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c @@ -0,0 +1,111 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <error.h> +#include "testlib.h" + +int main(int argc, char **argv) +{ + const unsigned int width = 16, height = 16; + const unsigned int min_required_blocks = 1, min_required_macroblocks = 1; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + + Display *display; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvMCSurface surface; + XvMCBlockArray blocks = {0}; + XvMCMacroBlockArray macroblocks = {0}; + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + width, + height, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); + assert(XvMCCreateSurface(display, &context, &surface) == Success); + + /* Test NULL context */ + assert(XvMCCreateBlocks(display, NULL, 1, &blocks) == XvMCBadContext); + /* Test 0 blocks */ + assert(XvMCCreateBlocks(display, &context, 0, &blocks) == BadValue); + /* Test valid params */ + assert(XvMCCreateBlocks(display, &context, min_required_blocks, &blocks) == Success); + /* Test context id assigned and correct */ + assert(blocks.context_id == context.context_id); + /* Test number of blocks assigned and correct */ + assert(blocks.num_blocks == min_required_blocks); + /* Test block pointer valid */ + assert(blocks.blocks != NULL); + /* Test NULL context */ + assert(XvMCCreateMacroBlocks(display, NULL, 1, ¯oblocks) == XvMCBadContext); + /* Test 0 macroblocks */ + assert(XvMCCreateMacroBlocks(display, &context, 0, ¯oblocks) == BadValue); + /* Test valid params */ + assert(XvMCCreateMacroBlocks(display, &context, min_required_macroblocks, ¯oblocks) == Success); + /* Test context id assigned and correct */ + assert(macroblocks.context_id == context.context_id); + /* Test macroblock pointer valid */ + assert(macroblocks.macro_blocks != NULL); + /* Test valid params */ + assert(XvMCDestroyMacroBlocks(display, ¯oblocks) == Success); + /* Test valid params */ + assert(XvMCDestroyBlocks(display, &blocks) == Success); + + assert(XvMCDestroySurface(display, &surface) == Success); + assert(XvMCDestroyContext(display, &context) == Success); + + XvUngrabPort(display, port_num, CurrentTime); + XCloseDisplay(display); + + return 0; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_context.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_context.c new file mode 100644 index 00000000000..3da957c9330 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_context.c @@ -0,0 +1,119 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <error.h> +#include "testlib.h" + +int main(int argc, char **argv) +{ + const unsigned int width = 16, height = 16; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + + Display *display; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context = {0}; + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + width, + height, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + /* Test NULL context */ + /* XXX: XvMCBadContext not a valid return for XvMCCreateContext in the XvMC API, but openChrome driver returns it */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, NULL) == XvMCBadContext); + /* Test invalid port */ + /* XXX: Success and XvBadPort have the same value, if this call actually gets passed the validation step as of now we'll crash later */ + assert(XvMCCreateContext(display, -1, surface_type_id, width, height, XVMC_DIRECT, &context) == XvBadPort); + /* Test invalid surface */ + assert(XvMCCreateContext(display, port_num, -1, width, height, XVMC_DIRECT, &context) == BadMatch); + /* Test invalid flags */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, -1, &context) == BadValue); + /* Test huge width */ + assert(XvMCCreateContext(display, port_num, surface_type_id, 16384, height, XVMC_DIRECT, &context) == BadValue); + /* Test huge height */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width, 16384, XVMC_DIRECT, &context) == BadValue); + /* Test huge width & height */ + assert(XvMCCreateContext(display, port_num, surface_type_id, 16384, 16384, XVMC_DIRECT, &context) == BadValue); + /* Test valid params */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); + /* Test context id assigned */ + assert(context.context_id != 0); + /* Test surface type id assigned and correct */ + assert(context.surface_type_id == surface_type_id); + /* Test width & height assigned and correct */ + assert(context.width == width && context.height == height); + /* Test port assigned and correct */ + assert(context.port == port_num); + /* Test flags assigned and correct */ + assert(context.flags == XVMC_DIRECT); + /* Test NULL context */ + assert(XvMCDestroyContext(display, NULL) == XvMCBadContext); + /* Test valid params */ + assert(XvMCDestroyContext(display, &context) == Success); + /* Test awkward but valid width */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height, XVMC_DIRECT, &context) == Success); + assert(context.width >= width + 1); + assert(XvMCDestroyContext(display, &context) == Success); + /* Test awkward but valid height */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height + 1, XVMC_DIRECT, &context) == Success); + assert(context.height >= height + 1); + assert(XvMCDestroyContext(display, &context) == Success); + /* Test awkward but valid width & height */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height + 1, XVMC_DIRECT, &context) == Success); + assert(context.width >= width + 1 && context.height >= height + 1); + assert(XvMCDestroyContext(display, &context) == Success); + + XvUngrabPort(display, port_num, CurrentTime); + XCloseDisplay(display); + + return 0; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c new file mode 100644 index 00000000000..6058783a798 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c @@ -0,0 +1,317 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <error.h> +#include "testlib.h" + +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 8 +#define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT) +#define MACROBLOCK_WIDTH 16 +#define MACROBLOCK_HEIGHT 16 +#define MACROBLOCK_WIDTH_IN_BLOCKS (MACROBLOCK_WIDTH / BLOCK_WIDTH) +#define MACROBLOCK_HEIGHT_IN_BLOCKS (MACROBLOCK_HEIGHT / BLOCK_HEIGHT) +#define BLOCKS_PER_MACROBLOCK 6 + +#define INPUT_WIDTH 16 +#define INPUT_HEIGHT 16 +#define INPUT_WIDTH_IN_MACROBLOCKS (INPUT_WIDTH / MACROBLOCK_WIDTH) +#define INPUT_HEIGHT_IN_MACROBLOCKS (INPUT_HEIGHT / MACROBLOCK_HEIGHT) +#define NUM_MACROBLOCKS (INPUT_WIDTH_IN_MACROBLOCKS * INPUT_HEIGHT_IN_MACROBLOCKS) + +#define DEFAULT_OUTPUT_WIDTH INPUT_WIDTH +#define DEFAULT_OUTPUT_HEIGHT INPUT_HEIGHT +#define DEFAULT_ACCEPTABLE_ERR 0.01 + +void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt); +void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal); + +void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt) +{ + int fail = 0; + int i; + + *output_width = DEFAULT_OUTPUT_WIDTH; + *output_height = DEFAULT_OUTPUT_WIDTH; + *acceptable_error = DEFAULT_ACCEPTABLE_ERR; + *prompt = 1; + + for (i = 1; i < argc && !fail; ++i) + { + if (!strcmp(argv[i], "-w")) + { + if (sscanf(argv[++i], "%u", output_width) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-h")) + { + if (sscanf(argv[++i], "%u", output_height) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-e")) + { + if (sscanf(argv[++i], "%lf", acceptable_error) != 1) + fail = 1; + } + else if (strcmp(argv[i], "-n")) + *prompt = 0; + else + fail = 1; + } + + if (fail) + error + ( + 1, 0, + "Bad argument.\n" + "\n" + "Usage: %s [options]\n" + "\t-w <width>\tOutput width\n" + "\t-h <height>\tOutput height\n" + "\t-e <error>\tAcceptable margin of error per pixel, from 0 to 1\n" + "\t-n\tDon't prompt for quit\n", + argv[0] + ); +} + +void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal) +{ + unsigned int x, y; + unsigned int range = stop - start; + + if (horizontal) + { + for (y = 0; y < BLOCK_HEIGHT; ++y) + for (x = 0; x < BLOCK_WIDTH; ++x) + block[y * BLOCK_WIDTH + x] = (short)(start + range * (x / (float)(BLOCK_WIDTH - 1))); + } + else + { + for (y = 0; y < BLOCK_HEIGHT; ++y) + for (x = 0; x < BLOCK_WIDTH; ++x) + block[y * BLOCK_WIDTH + x] = (short)(start + range * (y / (float)(BLOCK_HEIGHT - 1))); + } +} + +int main(int argc, char **argv) +{ + unsigned int output_width; + unsigned int output_height; + double acceptable_error; + int prompt; + Display *display; + Window root, window; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvMCSurface surface; + XvMCBlockArray block_array; + XvMCMacroBlockArray mb_array; + int mbx, mby, bx, by; + XvMCMacroBlock *mb; + short *blocks; + int quit = 0; + + ParseArgs(argc, argv, &output_width, &output_height, &acceptable_error, &prompt); + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + INPUT_WIDTH, + INPUT_HEIGHT, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, output_width, output_height, 0, 0, colorkey); + + assert(XvMCCreateContext(display, port_num, surface_type_id, INPUT_WIDTH, INPUT_HEIGHT, XVMC_DIRECT, &context) == Success); + assert(XvMCCreateSurface(display, &context, &surface) == Success); + assert(XvMCCreateBlocks(display, &context, NUM_MACROBLOCKS * BLOCKS_PER_MACROBLOCK, &block_array) == Success); + assert(XvMCCreateMacroBlocks(display, &context, NUM_MACROBLOCKS, &mb_array) == Success); + + mb = mb_array.macro_blocks; + blocks = block_array.blocks; + + for (mby = 0; mby < INPUT_HEIGHT_IN_MACROBLOCKS; ++mby) + for (mbx = 0; mbx < INPUT_WIDTH_IN_MACROBLOCKS; ++mbx) + { + mb->x = mbx; + mb->y = mby; + mb->macroblock_type = XVMC_MB_TYPE_INTRA; + /*mb->motion_type = ;*/ + /*mb->motion_vertical_field_select = ;*/ + mb->dct_type = XVMC_DCT_TYPE_FRAME; + /*mb->PMV[0][0][0] = ; + mb->PMV[0][0][1] = ; + mb->PMV[0][1][0] = ; + mb->PMV[0][1][1] = ; + mb->PMV[1][0][0] = ; + mb->PMV[1][0][1] = ; + mb->PMV[1][1][0] = ; + mb->PMV[1][1][1] = ;*/ + mb->index = (mby * INPUT_WIDTH_IN_MACROBLOCKS + mbx) * BLOCKS_PER_MACROBLOCK; + mb->coded_block_pattern = 0x3F; + + mb++; + + for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS; ++by) + for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS; ++bx) + { + const int start = 16, stop = 235, range = stop - start; + + Gradient + ( + blocks, + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), + 1 + ); + + blocks += BLOCK_SIZE; + } + + for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS / 2; ++by) + for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS / 2; ++bx) + { + const int start = 16, stop = 240, range = stop - start; + + Gradient + ( + blocks, + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), + 1 + ); + + blocks += BLOCK_SIZE; + + Gradient + ( + blocks, + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), + 1 + ); + + blocks += BLOCK_SIZE; + } + } + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + /* Test NULL context */ + assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadContext); + /* Test NULL surface */ + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadSurface); + /* Test bad picture structure */ + assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == BadValue); + /* Test valid params */ + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == Success); + + /* Test NULL surface */ + assert(XvMCPutSurface(display, NULL, window, 0, 0, INPUT_WIDTH, INPUT_HEIGHT, 0, 0, output_width, output_height, XVMC_FRAME_PICTURE) == XvMCBadSurface); + /* Test bad window */ + /* XXX: X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */ + /*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/ + + if (prompt) + { + puts("Press any button to quit..."); + + while (!quit) + { + if (XPending(display) > 0) + { + XEvent event; + + XNextEvent(display, &event); + + switch (event.type) + { + case Expose: + { + /* Test valid params */ + assert + ( + XvMCPutSurface + ( + display, &surface, window, + 0, 0, INPUT_WIDTH, INPUT_HEIGHT, + 0, 0, output_width, output_height, + XVMC_FRAME_PICTURE + ) == Success + ); + break; + } + case KeyPress: + { + quit = 1; + break; + } + } + } + } + } + + assert(XvMCDestroyBlocks(display, &block_array) == Success); + assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success); + assert(XvMCDestroySurface(display, &surface) == Success); + assert(XvMCDestroyContext(display, &context) == Success); + + XvUngrabPort(display, port_num, CurrentTime); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c new file mode 100644 index 00000000000..20d0907a07f --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c @@ -0,0 +1,182 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <error.h> +#include <stdio.h> +#include "testlib.h" + +static void PrintGUID(const char *guid) +{ + int i; + printf("\tguid: "); + for (i = 0; i < 4; ++i) + printf("%C,", guid[i] == 0 ? '0' : guid[i]); + for (; i < 15; ++i) + printf("%x,", (unsigned char)guid[i]); + printf("%x\n", (unsigned int)guid[15]); +} + +static void PrintComponentOrder(const char *co) +{ + int i; + printf("\tcomponent_order:\n\t "); + for (i = 0; i < 4; ++i) + printf("%C,", co[i] == 0 ? '0' : co[i]); + for (; i < 31; ++i) + printf("%x,", (unsigned int)co[i]); + printf("%x\n", (unsigned int)co[31]); +} + +int main(int argc, char **argv) +{ + const unsigned int width = 16, height = 16; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + const unsigned int subpic_width = 16, subpic_height = 16; + + Display *display; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvImageFormatValues *subpics; + int num_subpics; + XvMCSubpicture subpicture = {0}; + int i; + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + width, + height, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); + + subpics = XvMCListSubpictureTypes(display, port_num, surface_type_id, &num_subpics); + assert((subpics && num_subpics) > 0 || (!subpics && num_subpics == 0)); + + for (i = 0; i < num_subpics; ++i) + { + printf("Subpicture %d:\n", i); + printf("\tid: 0x%08x\n", subpics[i].id); + printf("\ttype: %s\n", subpics[i].type == XvRGB ? "XvRGB" : (subpics[i].type == XvYUV ? "XvYUV" : "Unknown")); + printf("\tbyte_order: %s\n", subpics[i].byte_order == LSBFirst ? "LSB First" : (subpics[i].byte_order == MSBFirst ? "MSB First" : "Unknown")); + PrintGUID(subpics[i].guid); + printf("\tbpp: %u\n", subpics[i].bits_per_pixel); + printf("\tformat: %s\n", subpics[i].format == XvPacked ? "XvPacked" : (subpics[i].format == XvPlanar ? "XvPlanar" : "Unknown")); + printf("\tnum_planes: %u\n", subpics[i].num_planes); + + if (subpics[i].type == XvRGB) + { + printf("\tdepth: %u\n", subpics[i].depth); + printf("\tred_mask: 0x%08x\n", subpics[i].red_mask); + printf("\tgreen_mask: 0x%08x\n", subpics[i].green_mask); + printf("\tblue_mask: 0x%08x\n", subpics[i].blue_mask); + } + else if (subpics[i].type == XvYUV) + { + printf("\ty_sample_bits: %u\n", subpics[i].y_sample_bits); + printf("\tu_sample_bits: %u\n", subpics[i].u_sample_bits); + printf("\tv_sample_bits: %u\n", subpics[i].v_sample_bits); + printf("\thorz_y_period: %u\n", subpics[i].horz_y_period); + printf("\thorz_u_period: %u\n", subpics[i].horz_u_period); + printf("\thorz_v_period: %u\n", subpics[i].horz_v_period); + printf("\tvert_y_period: %u\n", subpics[i].vert_y_period); + printf("\tvert_u_period: %u\n", subpics[i].vert_u_period); + printf("\tvert_v_period: %u\n", subpics[i].vert_v_period); + } + PrintComponentOrder(subpics[i].component_order); + printf("\tscanline_order: %s\n", subpics[i].scanline_order == XvTopToBottom ? "XvTopToBottom" : (subpics[i].scanline_order == XvBottomToTop ? "XvBottomToTop" : "Unknown")); + } + + if (num_subpics == 0) + { + printf("Subpictures not supported, nothing to test.\n"); + return 0; + } + + /* Test NULL context */ + assert(XvMCCreateSubpicture(display, NULL, &subpicture, subpic_width, subpic_height, subpics[0].id) == XvMCBadContext); + /* Test NULL subpicture */ + assert(XvMCCreateSubpicture(display, &context, NULL, subpic_width, subpic_height, subpics[0].id) == XvMCBadSubpicture); + /* Test invalid subpicture */ + assert(XvMCCreateSubpicture(display, &context, &subpicture, subpic_width, subpic_height, -1) == BadMatch); + /* Test huge width */ + assert(XvMCCreateSubpicture(display, &context, &subpicture, 16384, subpic_height, subpics[0].id) == BadValue); + /* Test huge height */ + assert(XvMCCreateSubpicture(display, &context, &subpicture, subpic_width, 16384, subpics[0].id) == BadValue); + /* Test huge width & height */ + assert(XvMCCreateSubpicture(display, &context, &subpicture, 16384, 16384, subpics[0].id) == BadValue); + for (i = 0; i < num_subpics; ++i) + { + /* Test valid params */ + assert(XvMCCreateSubpicture(display, &context, &subpicture, subpic_width, subpic_height, subpics[i].id) == Success); + /* Test subpicture id assigned */ + assert(subpicture.subpicture_id != 0); + /* Test context id assigned and correct */ + assert(subpicture.context_id == context.context_id); + /* Test subpicture type id assigned and correct */ + assert(subpicture.xvimage_id == subpics[i].id); + /* Test width & height assigned and correct */ + assert(subpicture.width == width && subpicture.height == height); + /* Test no palette support */ + assert(subpicture.num_palette_entries == 0 && subpicture.entry_bytes == 0); + /* Test valid params */ + assert(XvMCDestroySubpicture(display, &subpicture) == Success); + } + /* Test NULL surface */ + assert(XvMCDestroySubpicture(display, NULL) == XvMCBadSubpicture); + + assert(XvMCDestroyContext(display, &context) == Success); + + XFree(subpics); + XvUngrabPort(display, port_num, CurrentTime); + XCloseDisplay(display); + + return 0; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c new file mode 100644 index 00000000000..b65eb265c0a --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c @@ -0,0 +1,98 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <error.h> +#include "testlib.h" + +int main(int argc, char **argv) +{ + const unsigned int width = 16, height = 16; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + + Display *display; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvMCSurface surface = {0}; + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + width, + height, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); + + /* Test NULL context */ + assert(XvMCCreateSurface(display, NULL, &surface) == XvMCBadContext); + /* Test NULL surface */ + assert(XvMCCreateSurface(display, &context, NULL) == XvMCBadSurface); + /* Test valid params */ + assert(XvMCCreateSurface(display, &context, &surface) == Success); + /* Test surface id assigned */ + assert(surface.surface_id != 0); + /* Test context id assigned and correct */ + assert(surface.context_id == context.context_id); + /* Test surface type id assigned and correct */ + assert(surface.surface_type_id == surface_type_id); + /* Test width & height assigned and correct */ + assert(surface.width == width && surface.height == height); + /* Test valid params */ + assert(XvMCDestroySurface(display, &surface) == Success); + /* Test NULL surface */ + assert(XvMCDestroySurface(display, NULL) == XvMCBadSurface); + + assert(XvMCDestroyContext(display, &context) == Success); + + XvUngrabPort(display, port_num, CurrentTime); + XCloseDisplay(display); + + return 0; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/testlib.c b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.c new file mode 100644 index 00000000000..142c09bb590 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.c @@ -0,0 +1,146 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include "testlib.h" +#include <stdio.h> + +/* +void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line) +{ + fputs(doc_string, stderr); + if (!pred) + fprintf(stderr, " FAIL!\n\t\"%s\" at %s:%u\n", pred_string, file, line); + else + fputs(" PASS!\n", stderr); +} +*/ + +int GetPort +( + Display *display, + unsigned int width, + unsigned int height, + unsigned int chroma_format, + const unsigned int *mc_types, + unsigned int num_mc_types, + XvPortID *port_id, + int *surface_type_id, + unsigned int *is_overlay, + unsigned int *intra_unsigned +) +{ + unsigned int found_port = 0; + XvAdaptorInfo *adaptor_info; + unsigned int num_adaptors; + int num_types; + int ev_base, err_base; + unsigned int i, j, k, l; + + if (!XvMCQueryExtension(display, &ev_base, &err_base)) + return 0; + if (XvQueryAdaptors(display, XDefaultRootWindow(display), &num_adaptors, &adaptor_info) != Success) + return 0; + + for (i = 0; i < num_adaptors && !found_port; ++i) + { + if (adaptor_info[i].type & XvImageMask) + { + XvMCSurfaceInfo *surface_info = XvMCListSurfaceTypes(display, adaptor_info[i].base_id, &num_types); + + if (surface_info) + { + for (j = 0; j < num_types && !found_port; ++j) + { + if + ( + surface_info[j].chroma_format == chroma_format && + surface_info[j].max_width >= width && + surface_info[j].max_height >= height + ) + { + for (k = 0; k < num_mc_types && !found_port; ++k) + { + if (surface_info[j].mc_type == mc_types[k]) + { + for (l = 0; l < adaptor_info[i].num_ports && !found_port; ++l) + { + if (XvGrabPort(display, adaptor_info[i].base_id + l, CurrentTime) == Success) + { + *port_id = adaptor_info[i].base_id + l; + *surface_type_id = surface_info[j].surface_type_id; + *is_overlay = surface_info[j].flags & XVMC_OVERLAID_SURFACE; + *intra_unsigned = surface_info[j].flags & XVMC_INTRA_UNSIGNED; + found_port = 1; + } + } + } + } + } + } + + XFree(surface_info); + } + } + } + + XvFreeAdaptorInfo(adaptor_info); + + return found_port; +} + +unsigned int align(unsigned int value, unsigned int alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +/* From the glibc manual */ +int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_usec < y->tv_usec) + { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) + { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* + * Compute the time remaining to wait. + * tv_usec is certainly positive. + */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/testlib.h b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.h new file mode 100644 index 00000000000..0438e52928b --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.h @@ -0,0 +1,69 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef testlib_h +#define testlib_h + +/* +#define TEST(pred, doc) test(pred, #pred, doc, __FILE__, __LINE__) + +void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line); +*/ + +#include <sys/time.h> +#include <X11/Xlib.h> +#include <X11/extensions/XvMClib.h> + +/* + * display: IN A valid X display + * width, height: IN Surface size that the port must display + * chroma_format: IN Chroma format that the port must display + * mc_types, num_mc_types: IN List of MC types that the port must support, first port that matches the first mc_type will be returned + * port_id: OUT Your port's ID + * surface_type_id: OUT Your port's surface ID + * is_overlay: OUT If 1, port uses overlay surfaces, you need to set a colorkey + * intra_unsigned: OUT If 1, port uses unsigned values for intra-coded blocks + */ +int GetPort +( + Display *display, + unsigned int width, + unsigned int height, + unsigned int chroma_format, + const unsigned int *mc_types, + unsigned int num_mc_types, + XvPortID *port_id, + int *surface_type_id, + unsigned int *is_overlay, + unsigned int *intra_unsigned +); + +unsigned int align(unsigned int value, unsigned int alignment); + +int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); + +#endif diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c b/src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c new file mode 100644 index 00000000000..bf94d856234 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c @@ -0,0 +1,300 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <error.h> +#include <sys/time.h> +#include "testlib.h" + +#define MACROBLOCK_WIDTH 16 +#define MACROBLOCK_HEIGHT 16 +#define BLOCKS_PER_MACROBLOCK 6 + +#define DEFAULT_INPUT_WIDTH 720 +#define DEFAULT_INPUT_HEIGHT 480 +#define DEFAULT_REPS 100 + +#define PIPELINE_STEP_MC 1 +#define PIPELINE_STEP_CSC 2 +#define PIPELINE_STEP_SWAP 4 + +#define MB_TYPE_I 1 +#define MB_TYPE_P 2 +#define MB_TYPE_B 4 + +struct Config +{ + unsigned int input_width; + unsigned int input_height; + unsigned int output_width; + unsigned int output_height; + unsigned int pipeline; + unsigned int mb_types; + unsigned int reps; +}; + +void ParseArgs(int argc, char **argv, struct Config *config); + +void ParseArgs(int argc, char **argv, struct Config *config) +{ + int fail = 0; + int i; + + config->input_width = DEFAULT_INPUT_WIDTH; + config->input_height = DEFAULT_INPUT_HEIGHT; + config->output_width = 0; + config->output_height = 0; + config->pipeline = 0; + config->mb_types = 0; + config->reps = DEFAULT_REPS; + + for (i = 1; i < argc && !fail; ++i) + { + if (!strcmp(argv[i], "-iw")) + { + if (sscanf(argv[++i], "%u", &config->input_width) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-ih")) + { + if (sscanf(argv[++i], "%u", &config->input_height) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-ow")) + { + if (sscanf(argv[++i], "%u", &config->output_width) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-oh")) + { + if (sscanf(argv[++i], "%u", &config->output_height) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-p")) + { + char *token = strtok(argv[++i], ","); + + while (token && !fail) + { + if (!strcmp(token, "mc")) + config->pipeline |= PIPELINE_STEP_MC; + else if (!strcmp(token, "csc")) + config->pipeline |= PIPELINE_STEP_CSC; + else if (!strcmp(token, "swp")) + config->pipeline |= PIPELINE_STEP_SWAP; + else + fail = 1; + + if (!fail) + token = strtok(NULL, ","); + } + } + else if (!strcmp(argv[i], "-mb")) + { + char *token = strtok(argv[++i], ","); + + while (token && !fail) + { + if (strcmp(token, "i")) + config->mb_types |= MB_TYPE_I; + else if (strcmp(token, "p")) + config->mb_types |= MB_TYPE_P; + else if (strcmp(token, "b")) + config->mb_types |= MB_TYPE_B; + else + fail = 1; + + if (!fail) + token = strtok(NULL, ","); + } + } + else if (!strcmp(argv[i], "-r")) + { + if (sscanf(argv[++i], "%u", &config->reps) != 1) + fail = 1; + } + else + fail = 1; + } + + if (fail) + error + ( + 1, 0, + "Bad argument.\n" + "\n" + "Usage: %s [options]\n" + "\t-iw <width>\tInput width\n" + "\t-ih <height>\tInput height\n" + "\t-ow <width>\tOutput width\n" + "\t-oh <height>\tOutput height\n" + "\t-p <pipeline>\tPipeline to test\n" + "\t-mb <mb type>\tMacroBlock types to use\n" + "\t-r <reps>\tRepetitions\n\n" + "\tPipeline steps: mc,csc,swap\n" + "\tMB types: i,p,b\n", + argv[0] + ); + + if (config->output_width == 0) + config->output_width = config->input_width; + if (config->output_height == 0) + config->output_height = config->input_height; + if (!config->pipeline) + config->pipeline = PIPELINE_STEP_MC | PIPELINE_STEP_CSC | PIPELINE_STEP_SWAP; + if (!config->mb_types) + config->mb_types = MB_TYPE_I | MB_TYPE_P | MB_TYPE_B; +} + +int main(int argc, char **argv) +{ + struct Config config; + Display *display; + Window root, window; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvMCSurface surface; + XvMCBlockArray block_array; + XvMCMacroBlockArray mb_array; + unsigned int mbw, mbh; + unsigned int mbx, mby; + unsigned int reps; + struct timeval start, stop, diff; + double diff_secs; + + ParseArgs(argc, argv, &config); + + mbw = align(config.input_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH; + mbh = align(config.input_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT; + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + config.input_width, + config.input_height, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, config.output_width, config.output_height, 0, 0, colorkey); + + assert(XvMCCreateContext(display, port_num, surface_type_id, config.input_width, config.input_height, XVMC_DIRECT, &context) == Success); + assert(XvMCCreateSurface(display, &context, &surface) == Success); + assert(XvMCCreateBlocks(display, &context, mbw * mbh * BLOCKS_PER_MACROBLOCK, &block_array) == Success); + assert(XvMCCreateMacroBlocks(display, &context, mbw * mbh, &mb_array) == Success); + + for (mby = 0; mby < mbh; ++mby) + for (mbx = 0; mbx < mbw; ++mbx) + { + mb_array.macro_blocks[mby * mbw + mbx].x = mbx; + mb_array.macro_blocks[mby * mbw + mbx].y = mby; + mb_array.macro_blocks[mby * mbw + mbx].macroblock_type = XVMC_MB_TYPE_INTRA; + /*mb->motion_type = ;*/ + /*mb->motion_vertical_field_select = ;*/ + mb_array.macro_blocks[mby * mbw + mbx].dct_type = XVMC_DCT_TYPE_FRAME; + /*mb->PMV[0][0][0] = ; + mb->PMV[0][0][1] = ; + mb->PMV[0][1][0] = ; + mb->PMV[0][1][1] = ; + mb->PMV[1][0][0] = ; + mb->PMV[1][0][1] = ; + mb->PMV[1][1][0] = ; + mb->PMV[1][1][1] = ;*/ + mb_array.macro_blocks[mby * mbw + mbx].index = (mby * mbw + mbx) * BLOCKS_PER_MACROBLOCK; + mb_array.macro_blocks[mby * mbw + mbx].coded_block_pattern = 0x3F; + } + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + gettimeofday(&start, NULL); + + for (reps = 0; reps < config.reps; ++reps) + { + if (config.pipeline & PIPELINE_STEP_MC) + { + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, mbw * mbh, 0, &mb_array, &block_array) == Success); + assert(XvMCFlushSurface(display, &surface) == Success); + } + if (config.pipeline & PIPELINE_STEP_CSC) + assert(XvMCPutSurface(display, &surface, window, 0, 0, config.input_width, config.input_height, 0, 0, config.output_width, config.output_height, XVMC_FRAME_PICTURE) == Success); + } + + gettimeofday(&stop, NULL); + + timeval_subtract(&diff, &stop, &start); + diff_secs = (double)diff.tv_sec + (double)diff.tv_usec / 1000000.0; + + printf("XvMC Benchmark\n"); + printf("Input: %u,%u\nOutput: %u,%u\n", config.input_width, config.input_height, config.output_width, config.output_height); + printf("Pipeline: "); + if (config.pipeline & PIPELINE_STEP_MC) + printf("|mc|"); + if (config.pipeline & PIPELINE_STEP_CSC) + printf("|csc|"); + if (config.pipeline & PIPELINE_STEP_SWAP) + printf("|swap|"); + printf("\n"); + printf("Reps: %u\n", config.reps); + printf("Total time: %.2lf (%.2lf reps / sec)\n", diff_secs, config.reps / diff_secs); + + assert(XvMCDestroyBlocks(display, &block_array) == Success); + assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success); + assert(XvMCDestroySurface(display, &surface) == Success); + assert(XvMCDestroyContext(display, &context) == Success); + + XvUngrabPort(display, port_num, CurrentTime); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} diff --git a/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h b/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h new file mode 100644 index 00000000000..5f8d9d13cb3 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h @@ -0,0 +1,139 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef xvmc_private_h +#define xvmc_private_h + +#include <X11/Xlib.h> +#include <X11/extensions/XvMClib.h> + +#include <pipe/p_video_state.h> + +#include <util/u_debug.h> +#include <util/u_math.h> + +#include <vl/vl_csc.h> +#include <vl/vl_compositor.h> + +#define BLOCK_SIZE_SAMPLES 64 +#define BLOCK_SIZE_BYTES (BLOCK_SIZE_SAMPLES * 2) + +struct vl_context; + +struct pipe_video_decoder; +struct pipe_video_decode_buffer; +struct pipe_video_buffer; + +struct pipe_sampler_view; +struct pipe_fence_handle; + +typedef struct +{ + struct vl_context *vctx; + struct pipe_video_decoder *decoder; + + enum VL_CSC_COLOR_STANDARD color_standard; + struct vl_procamp procamp; + struct vl_compositor compositor; + + unsigned short subpicture_max_width; + unsigned short subpicture_max_height; + + struct pipe_video_rect dst_rect; + struct pipe_surface *drawable_surface; + +} XvMCContextPrivate; + +typedef struct +{ + struct pipe_video_decode_buffer *decode_buffer; + struct pipe_video_buffer *video_buffer; + + bool mapped; // are we still mapped to memory? + + 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]; + + struct pipe_fence_handle *fence; + + /* The subpicture associated with this surface, if any. */ + XvMCSubpicture *subpicture; + + /* Some XvMC functions take a surface but not a context, + so we keep track of which context each surface belongs to. */ + XvMCContext *context; +} XvMCSurfacePrivate; + +typedef struct +{ + struct pipe_sampler_view *sampler; + + /* optional palette for this subpicture */ + struct pipe_sampler_view *palette; + + struct pipe_video_rect src_rect; + struct pipe_video_rect dst_rect; + + /* The surface this subpicture is currently associated with, if any. */ + XvMCSurface *surface; + + /* Some XvMC functions take a subpicture but not a context, + so we keep track of which context each subpicture belongs to. */ + XvMCContext *context; +} XvMCSubpicturePrivate; + +#define XVMC_OUT 0 +#define XVMC_ERR 1 +#define XVMC_WARN 2 +#define XVMC_TRACE 3 + +static INLINE void XVMC_MSG(unsigned int level, const char *fmt, ...) +{ + static int debug_level = -1; + + if (debug_level == -1) { + debug_level = MAX2(debug_get_num_option("XVMC_DEBUG", 0), 0); + } + + if (level <= debug_level) { + va_list ap; + va_start(ap, fmt); + _debug_vprintf(fmt, ap); + va_end(ap); + } +} + +#endif /* xvmc_private_h */ diff --git a/src/gallium/targets/Makefile.dri b/src/gallium/targets/Makefile.dri index 6c6ad184fab..857ebfeac84 100644 --- a/src/gallium/targets/Makefile.dri +++ b/src/gallium/targets/Makefile.dri @@ -2,7 +2,6 @@ ifeq ($(MESA_LLVM),1) -PIPE_DRIVERS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a LDFLAGS += $(LLVM_LDFLAGS) DRIVER_EXTRAS = $(LLVM_LIBS) else diff --git a/src/gallium/targets/Makefile.va b/src/gallium/targets/Makefile.va new file mode 100644 index 00000000000..7ced430f690 --- /dev/null +++ b/src/gallium/targets/Makefile.va @@ -0,0 +1,69 @@ +# This makefile template is used to build "driver"_drv_video.so + +LIBNAME = lib$(LIBBASENAME).so +VA_LIB_GLOB= lib$(LIBBASENAME).*so* +VA_MAJOR = 0 +VA_MINOR = 3 +INCLUDES = -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/winsys \ + -I$(TOP)/src/gallium/winsys/g3dvl \ + $(DRIVER_INCLUDES) +DEFINES = -DGALLIUM_TRACE -DVER_MAJOR=$(VA_MAJOR) -DVER_MINOR=$(VA_MINOR) $(DRIVER_DEFINES) +LIBS = $(EXTRA_LIB_PATH) $(DRIVER_LIBS) -lva -lXext -lX11 -lm +STATE_TRACKER_LIB = $(TOP)/src/gallium/state_trackers/va/libvatracker.a + +ifeq ($(MESA_LLVM),1) +LDFLAGS += $(LLVM_LDFLAGS) +DRIVER_EXTRAS = $(LLVM_LIBS) +else +LDFLAGS += -lstdc++ +endif + +# XXX: Hack, VA public funcs aren't exported +OBJECTS = $(C_SOURCES:.c=.o) \ + $(ASM_SOURCES:.S=.o) \ + $(TOP)/src/gallium/state_trackers/va/*.o + +##### RULES ##### + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +##### TARGETS ##### + +default: depend symlinks $(TOP)/$(LIB_DIR)/gallium/$(LIBNAME) + +$(TOP)/$(LIB_DIR)/gallium/$(LIBNAME): $(OBJECTS) $(PIPE_DRIVERS) $(STATE_TRACKER_LIB) $(TOP)/$(LIB_DIR)/gallium Makefile + $(MKLIB) -o $(LIBBASENAME) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + -major $(VA_MAJOR) -minor $(VA_MINOR) $(MKLIB_OPTIONS) \ + -install $(TOP)/$(LIB_DIR)/gallium \ + $(OBJECTS) $(STATE_TRACKER_LIB) $(PIPE_DRIVERS) $(LIBS) $(DRIVER_EXTRAS) + +$(TOP)/$(LIB_DIR)/gallium: + mkdir -p $@ + +depend: $(C_SOURCES) $(ASM_SOURCES) $(SYMLINKS) + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDES) $(C_SOURCES) \ + $(ASM_SOURCES) 2> /dev/null + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + +# Remove .o and backup files +clean: + -rm -f *.o *~ *.so $(SYMLINKS) + -rm -f depend depend.bak + +install: default + $(INSTALL) -d $(DESTDIR)$(VA_LIB_INSTALL_DIR) + $(MINSTALL) -m 755 $(TOP)/$(LIB_DIR)/gallium/$(VA_LIB_GLOB) $(DESTDIR)$(VA_LIB_INSTALL_DIR) + +include depend diff --git a/src/gallium/targets/Makefile.vdpau b/src/gallium/targets/Makefile.vdpau new file mode 100644 index 00000000000..c0937ff1aa5 --- /dev/null +++ b/src/gallium/targets/Makefile.vdpau @@ -0,0 +1,69 @@ +# This makefile template is used to build libvdpau_g3dvl.so + +LIBNAME = lib$(LIBBASENAME).so +VDPAU_LIB_GLOB=lib$(LIBBASENAME).*so* +VDPAU_MAJOR = 1 +VDPAU_MINOR = 0 +INCLUDES = -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/winsys \ + -I$(TOP)/src/gallium/winsys/g3dvl \ + $(DRIVER_INCLUDES) +DEFINES = -DGALLIUM_TRACE -DVER_MAJOR=$(VDPAU_MAJOR) -DVER_MINOR=$(VDPAU_MINOR) $(DRIVER_DEFINES) +LIBS = $(EXTRA_LIB_PATH) $(DRIVER_LIBS) -lvdpau -lXext -lX11 -lm +STATE_TRACKER_LIB = $(TOP)/src/gallium/state_trackers/vdpau/libvdpautracker.a + +ifeq ($(MESA_LLVM),1) +LDFLAGS += $(LLVM_LDFLAGS) +DRIVER_EXTRAS = $(LLVM_LIBS) +else +LDFLAGS += -lstdc++ +endif + +# XXX: Hack, VDPAU public funcs aren't exported if we link to libvdpautracker.a :( +OBJECTS = $(C_SOURCES:.c=.o) \ + $(ASM_SOURCES:.S=.o) \ + $(TOP)/src/gallium/state_trackers/vdpau/*.o + +##### RULES ##### + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +##### TARGETS ##### + +default: depend symlinks $(TOP)/$(LIB_DIR)/gallium/$(LIBNAME) + +$(TOP)/$(LIB_DIR)/gallium/$(LIBNAME): $(OBJECTS) $(PIPE_DRIVERS) $(STATE_TRACKER_LIB) $(TOP)/$(LIB_DIR)/gallium Makefile + $(MKLIB) -o $(LIBBASENAME) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + -major $(VDPAU_MAJOR) -minor $(VDPAU_MINOR) $(MKLIB_OPTIONS) \ + -install $(TOP)/$(LIB_DIR)/gallium \ + $(OBJECTS) $(STATE_TRACKER_LIB) $(PIPE_DRIVERS) $(LIBS) $(DRIVER_EXTRAS) + +$(TOP)/$(LIB_DIR)/gallium: + mkdir -p $@ + +depend: $(C_SOURCES) $(ASM_SOURCES) $(SYMLINKS) + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDES) $(C_SOURCES) \ + $(ASM_SOURCES) 2> /dev/null + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + +# Remove .o and backup files +clean: + -rm -f *.o *~ *.so $(SYMLINKS) + -rm -f depend depend.bak + +install: default + $(INSTALL) -d $(DESTDIR)$(VDPAU_LIB_INSTALL_DIR) + $(MINSTALL) -m 755 $(TOP)/$(LIB_DIR)/gallium/$(VDPAU_LIB_GLOB) $(DESTDIR)$(VDPAU_LIB_INSTALL_DIR) + +include depend diff --git a/src/gallium/targets/Makefile.xorg b/src/gallium/targets/Makefile.xorg index 47040bb14c8..025f7426f85 100644 --- a/src/gallium/targets/Makefile.xorg +++ b/src/gallium/targets/Makefile.xorg @@ -32,7 +32,6 @@ ifeq ($(MESA_LLVM),1) LD = $(CXX) LDFLAGS += $(LLVM_LDFLAGS) USE_CXX=1 -DRIVER_PIPES += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a DRIVER_LINKS += $(LLVM_LIBS) -lm -ldl endif @@ -41,7 +40,7 @@ endif default: depend $(TOP)/$(LIB_DIR)/gallium $(LIBNAME) $(LIBNAME_STAGING) -$(LIBNAME): $(OBJECTS) Makefile ../Makefile.xorg $(LIBS) $(DRIVER_PIPES) +$(LIBNAME): $(OBJECTS) Makefile ../Makefile.xorg $(LIBS) $(DRIVER_PIPES) $(GALLIUM_AUXILIARIES) $(MKLIB) -linker '$(CC)' -noprefix -o $@ $(LDFLAGS) $(OBJECTS) $(DRIVER_PIPES) $(GALLIUM_AUXILIARIES) $(DRIVER_LINKS) depend: $(C_SOURCES) $(CPP_SOURCES) $(ASM_SOURCES) $(SYMLINKS) $(GENERATED_SOURCES) diff --git a/src/gallium/targets/Makefile.xvmc b/src/gallium/targets/Makefile.xvmc new file mode 100644 index 00000000000..7182356ed6f --- /dev/null +++ b/src/gallium/targets/Makefile.xvmc @@ -0,0 +1,70 @@ +# This makefile template is used to build libXvMCg3dvl.so + +LIBNAME = lib$(LIBBASENAME).so +LIB_GLOB=lib$(LIBBASENAME).*so* +XVMC_MAJOR = 1 +XVMC_MINOR = 0 +INCLUDES = -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/winsys \ + -I$(TOP)/src/gallium/winsys/g3dvl \ + $(DRIVER_INCLUDES) +DEFINES = -DGALLIUM_TRACE $(DRIVER_DEFINES) +LIBS = $(EXTRA_LIB_PATH) $(DRIVER_LIBS) -lXv -lX11 -lm +STATE_TRACKER_LIB = $(TOP)/src/gallium/state_trackers/xorg/xvmc/libxvmctracker.a + +ifeq ($(MESA_LLVM),1) +LDFLAGS += $(LLVM_LDFLAGS) +DRIVER_EXTRAS = $(LLVM_LIBS) +else +LDFLAGS += -lstdc++ +endif + + +# XXX: Hack, XvMC public funcs aren't exported if we link to libxvmctracker.a :( +OBJECTS = $(C_SOURCES:.c=.o) \ + $(ASM_SOURCES:.S=.o) \ + $(TOP)/src/gallium/state_trackers/xorg/xvmc/*.o + +##### RULES ##### + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +##### TARGETS ##### + +default: depend symlinks $(TOP)/$(LIB_DIR)/gallium/$(LIBNAME) + +$(TOP)/$(LIB_DIR)/gallium/$(LIBNAME): $(OBJECTS) $(PIPE_DRIVERS) $(STATE_TRACKER_LIB) $(TOP)/$(LIB_DIR)/gallium Makefile + $(MKLIB) -o $(LIBBASENAME) -linker '$(CC)' -ldflags '$(LDFLAGS)' \ + -major $(XVMC_MAJOR) -minor $(XVMC_MINOR) $(MKLIB_OPTIONS) \ + -install $(TOP)/$(LIB_DIR)/gallium \ + $(OBJECTS) $(STATE_TRACKER_LIB) $(PIPE_DRIVERS) $(LIBS) $(DRIVER_EXTRAS) + +$(TOP)/$(LIB_DIR)/gallium: + mkdir -p $@ + +depend: $(C_SOURCES) $(ASM_SOURCES) $(SYMLINKS) + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDES) $(C_SOURCES) \ + $(ASM_SOURCES) 2> /dev/null + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + +# Remove .o and backup files +clean: + -rm -f *.o *~ *.so $(SYMLINKS) + -rm -f depend depend.bak + +install: default + $(INSTALL) -d $(DESTDIR)$(INSTALL_DIR)/$(LIB_DIR) + $(MINSTALL) -m 755 $(TOP)/$(LIB_DIR)/gallium/$(LIB_GLOB) $(DESTDIR)$(INSTALL_DIR)/$(LIB_DIR) + +include depend diff --git a/src/gallium/targets/SConscript.dri b/src/gallium/targets/SConscript.dri index 101863a6848..5ad17f8b3ae 100644 --- a/src/gallium/targets/SConscript.dri +++ b/src/gallium/targets/SConscript.dri @@ -29,7 +29,7 @@ drienv.Replace(CPPPATH = [ '#src/egl/drivers/dri', ]) -drienv.ParseConfig('pkg-config --cflags --libs libdrm') +drienv.PkgUseModules('DRM') dri_common_utils = drienv.SharedObject( target = 'utils.o', diff --git a/src/gallium/targets/dri-i915/Makefile b/src/gallium/targets/dri-i915/Makefile index 9c10d71a4a6..2ba3eb6e4e6 100644 --- a/src/gallium/targets/dri-i915/Makefile +++ b/src/gallium/targets/dri-i915/Makefile @@ -22,6 +22,7 @@ DRIVER_DEFINES = \ -DGALLIUM_RBUG -DGALLIUM_TRACE -DGALLIUM_GALAHAD -DGALLIUM_SOFTPIPE ifeq ($(MESA_LLVM),1) +PIPE_DRIVERS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a DRIVER_DEFINES += -DGALLIUM_LLVMPIPE endif diff --git a/src/gallium/targets/dri-i915/SConscript b/src/gallium/targets/dri-i915/SConscript index ab60013830e..b3bd3dd5826 100644 --- a/src/gallium/targets/dri-i915/SConscript +++ b/src/gallium/targets/dri-i915/SConscript @@ -2,7 +2,7 @@ Import('*') env = drienv.Clone() -env.ParseConfig('pkg-config --cflags --libs libdrm_intel') +env.PkgUseModules('DRM_INTEL') env.Append(CPPDEFINES = ['GALLIUM_RBUG', 'GALLIUM_TRACE', 'GALLIUM_GALAHAD']) @@ -26,4 +26,4 @@ module = env.LoadableModule( SHLIBPREFIX = '', ) -env.Alias('dri-i915', module)
\ No newline at end of file +env.Alias('dri-i915', module) diff --git a/src/gallium/targets/dri-i965/Makefile b/src/gallium/targets/dri-i965/Makefile index 4b50d04255f..9e75bfe0831 100644 --- a/src/gallium/targets/dri-i965/Makefile +++ b/src/gallium/targets/dri-i965/Makefile @@ -22,6 +22,7 @@ DRIVER_DEFINES = \ -DGALLIUM_RBUG -DGALLIUM_TRACE -DGALLIUM_GALAHAD -DGALLIUM_SOFTPIPE ifeq ($(MESA_LLVM),1) +PIPE_DRIVERS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a DRIVER_DEFINES += -DGALLIUM_LLVMPIPE endif diff --git a/src/gallium/targets/dri-i965/SConscript b/src/gallium/targets/dri-i965/SConscript index 669f70d6b8d..01a458db228 100644 --- a/src/gallium/targets/dri-i965/SConscript +++ b/src/gallium/targets/dri-i965/SConscript @@ -2,7 +2,7 @@ Import('*') env = drienv.Clone() -env.ParseConfig('pkg-config --cflags --libs libdrm_intel') +env.PkgUseModules('DRM_INTEL') env.Append(CPPDEFINES = [ 'GALLIUM_SOFTPIPE', @@ -29,4 +29,4 @@ module = env.LoadableModule( SHLIBPREFIX = '', ) -env.Alias('dri-i965', module)
\ No newline at end of file +env.Alias('dri-i965', module) diff --git a/src/gallium/targets/dri-r300/target.c b/src/gallium/targets/dri-r300/target.c index b48bcad3710..9b6d816fb62 100644 --- a/src/gallium/targets/dri-r300/target.c +++ b/src/gallium/targets/dri-r300/target.c @@ -1,4 +1,3 @@ - #include "target-helpers/inline_debug_helper.h" #include "state_tracker/drm_driver.h" #include "radeon/drm/radeon_drm_public.h" diff --git a/src/gallium/targets/dri-swrast/Makefile b/src/gallium/targets/dri-swrast/Makefile index 948c45abe5c..e83e0248b03 100644 --- a/src/gallium/targets/dri-swrast/Makefile +++ b/src/gallium/targets/dri-swrast/Makefile @@ -1,7 +1,7 @@ TOP = ../../../.. include $(TOP)/configs/current -LIBNAME = swrastg_dri.so +LIBNAME = swrast_dri.so DRIVER_DEFINES = \ -D__NOT_HAVE_DRM_H -DGALLIUM_SOFTPIPE \ @@ -14,6 +14,11 @@ PIPE_DRIVERS = \ $(TOP)/src/gallium/drivers/trace/libtrace.a \ $(TOP)/src/gallium/drivers/rbug/librbug.a +ifeq ($(MESA_LLVM),1) +PIPE_DRIVERS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a +DRIVER_DEFINES += -DGALLIUM_LLVMPIPE +endif + SWRAST_COMMON_GALLIUM_SOURCES = \ $(TOP)/src/mesa/drivers/dri/common/utils.c \ $(TOP)/src/mesa/drivers/dri/common/drisw_util.c \ diff --git a/src/gallium/targets/dri-swrast/SConscript b/src/gallium/targets/dri-swrast/SConscript index b67483800e4..6b64c56413c 100644 --- a/src/gallium/targets/dri-swrast/SConscript +++ b/src/gallium/targets/dri-swrast/SConscript @@ -29,14 +29,16 @@ if env['llvm']: env.Append(CPPDEFINES = 'GALLIUM_LLVMPIPE') env.Prepend(LIBS = [llvmpipe]) -swrastg_sources = [ +swrast_sources = [ 'swrast_drm_api.c' ] module = env.LoadableModule( - target ='swrastg_dri.so', - source = swrastg_sources, + target ='swrast_dri.so', + source = swrast_sources, SHLIBPREFIX = '', ) +module = env.InstallSharedLibrary(module) + env.Alias('dri-swrast', module) diff --git a/src/gallium/targets/dri-vmwgfx/target.c b/src/gallium/targets/dri-vmwgfx/target.c index 1362851d6be..da50b8b8bda 100644 --- a/src/gallium/targets/dri-vmwgfx/target.c +++ b/src/gallium/targets/dri-vmwgfx/target.c @@ -19,6 +19,7 @@ create_screen(int fd) if (!screen) return NULL; + vmw_winsys_screen_set_throttling(screen, 10); screen = sw_screen_wrap(screen); screen = debug_screen_wrap(screen); diff --git a/src/gallium/targets/egl-static/Makefile b/src/gallium/targets/egl-static/Makefile new file mode 100644 index 00000000000..42d34b8eda1 --- /dev/null +++ b/src/gallium/targets/egl-static/Makefile @@ -0,0 +1,205 @@ +# src/gallium/targets/egl-static/Makefile +# +# This is Makefile for egl_gallium.so. It is static in that all state trackers +# and pipe drivers are linked statically when possible. +# +# The following variables are examined +# +# EGL_PLATFORMS - platforms to support +# EGL_CLIENT_APIS - state trackers to support +# GALLIUM_WINSYS_DIRS - pipe drivers to support +# SHARED_GLAPI - st/mesa can be statically linked or not +# + +TOP = ../../../.. +include $(TOP)/configs/current + +OUTPUTS := egl_gallium + +egl_CPPFLAGS := \ + -I$(TOP)/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/winsys +egl_LIBS := \ + $(TOP)/src/gallium/drivers/identity/libidentity.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/drivers/rbug/librbug.a \ + $(GALLIUM_AUXILIARIES) +egl_SYS := + +egl_SOURCES := \ + egl.c \ + egl_pipe.c \ + egl_st.c + +egl_OBJECTS := $(egl_SOURCES:%.c=%.o) + +# st/egl +egl_CPPFLAGS += \ + -I$(TOP)/src/gallium/state_trackers/egl \ + -I$(TOP)/src/egl/main \ + -D_EGL_MAIN=_eglMain +egl_LIBS += $(TOP)/src/gallium/state_trackers/egl/libegl.a +egl_SYS += $(LIBUDEV_LIBS) $(DLOPEN_LIBS) -lEGL -lm -lpthread + +# EGL platforms +ifneq ($(findstring x11, $(EGL_PLATFORMS)),) +egl_CPPFLAGS += $(LIBDRM_CFLAGS) +egl_LIBS += $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a +egl_SYS += -lX11 -lXext -lXfixes $(LIBDRM_LIB) +endif +ifneq ($(findstring wayland, $(EGL_PLATFORMS)),) +egl_CPPFLAGS += $(LIBDRM_CFLAGS) +egl_LIBS += $(TOP)/src/gallium/winsys/sw/wayland/libws_wayland.a +egl_LIBS += $(TOP)/src/egl/wayland/wayland-drm/libwayland-drm.a +egl_SYS += $(LIBDRM_LIB) $(WAYLAND_LIBS) +endif +ifneq ($(findstring drm, $(EGL_PLATFORMS)),) +egl_CPPFLAGS += $(LIBDRM_CFLAGS) +egl_SYS += $(LIBDRM_LIB) -lgbm +endif +ifneq ($(findstring fbdev, $(EGL_PLATFORMS)),) +egl_LIBS += $(TOP)/src/gallium/winsys/sw/fbdev/libfbdev.a +endif + +# st/mesa +ifneq ($(filter $(GL_LIB), $(EGL_CLIENT_APIS)),) +egl_CPPFLAGS += -I$(TOP)/src/mesa $(API_DEFINES) +# make st/mesa built-in when there is a single glapi provider +ifeq ($(SHARED_GLAPI),1) +egl_LIBS += $(TOP)/src/mesa/libmesagallium.a +egl_SYS += -lm -lpthread $(DLOPEN_LIBS) -l$(GLAPI_LIB) +else +egl_CPPFLAGS += -D_EGL_EXTERNAL_GL=1 +OUTPUTS += st_GL +endif # SHARED_GLAPI +endif + +# st/vega +ifneq ($(filter $(VG_LIB), $(EGL_CLIENT_APIS)),) +egl_CPPFLAGS += -I$(TOP)/src/gallium/state_trackers/vega -DFEATURE_VG=1 +egl_LIBS += $(TOP)/src/gallium/state_trackers/vega/libvega.a +egl_SYS += -lm -l$(VG_LIB) +endif + +# i915 +ifneq ($(findstring i915/drm,$(GALLIUM_WINSYS_DIRS)),) +egl_CPPFLAGS += -D_EGL_PIPE_I915=1 +egl_LIBS += \ + $(TOP)/src/gallium/winsys/i915/drm/libi915drm.a \ + $(TOP)/src/gallium/drivers/i915/libi915.a +egl_SYS += -ldrm_intel +endif + +# i965 +ifneq ($(findstring i965/drm,$(GALLIUM_WINSYS_DIRS)),) +egl_CPPFLAGS += -D_EGL_PIPE_I995=1 +egl_LIBS += \ + $(TOP)/src/gallium/winsys/i965/drm/libi965drm.a \ + $(TOP)/src/gallium/drivers/i965/libi965.a \ + $(TOP)/src/gallium/winsys/sw/wrapper/libwsw.a +egl_SYS += -ldrm_intel +endif + +# nouveau +ifneq ($(findstring nouveau/drm,$(GALLIUM_WINSYS_DIRS)),) +egl_CPPFLAGS += -D_EGL_PIPE_NOUVEAU=1 +egl_LIBS += \ + $(TOP)/src/gallium/winsys/nouveau/drm/libnouveaudrm.a \ + $(TOP)/src/gallium/drivers/nvfx/libnvfx.a \ + $(TOP)/src/gallium/drivers/nv50/libnv50.a \ + $(TOP)/src/gallium/drivers/nvc0/libnvc0.a \ + $(TOP)/src/gallium/drivers/nouveau/libnouveau.a +egl_SYS += -ldrm_nouveau +endif + +# r300 +ifneq ($(findstring radeon/drm,$(GALLIUM_WINSYS_DIRS)),) +egl_CPPFLAGS += -D_EGL_PIPE_R300=1 +egl_LIBS += \ + $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ + $(TOP)/src/gallium/drivers/r300/libr300.a +endif + +# r600 +ifneq ($(findstring r600/drm,$(GALLIUM_WINSYS_DIRS)),) +egl_CPPFLAGS += -D_EGL_PIPE_R600=1 +egl_LIBS += \ + $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ + $(TOP)/src/gallium/drivers/r600/libr600.a +endif + +# vmwgfx +ifneq ($(findstring svga/drm,$(GALLIUM_WINSYS_DIRS)),) +egl_CPPFLAGS += -D_EGL_PIPE_VMWGFX=1 +egl_LIBS += \ + $(TOP)/src/gallium/winsys/svga/drm/libsvgadrm.a \ + $(TOP)/src/gallium/drivers/svga/libsvga.a +endif + +# softpipe +ifneq ($(findstring softpipe,$(GALLIUM_DRIVERS_DIRS)),) +egl_CPPFLAGS += -DGALLIUM_SOFTPIPE -DGALLIUM_RBUG -DGALLIUM_TRACE +egl_LIBS += $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a +egl_SYS += -lm +endif + +# llvmpipe +ifneq ($(findstring llvmpipe,$(GALLIUM_DRIVERS_DIRS)),) +egl_CPPFLAGS += -DGALLIUM_LLVMPIPE +egl_LIBS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a +endif + +# sort to remove duplicates +egl_CPPFLAGS := $(sort $(egl_CPPFLAGS)) +egl_LIBS := $(sort $(egl_LIBS)) +egl_SYS := $(sort $(egl_SYS)) + +# st_GL, built only when shared glapi is not enabled +st_GL_CPPFLAGS := -I $(TOP)/src/mesa -I$(TOP)/src/gallium/include +st_GL_LIBS := $(TOP)/src/mesa/libmesagallium.a $(GALLIUM_AUXILIARIES) +st_GL_SYS := -lm -lpthread $(DLOPEN_LIBS) + +# LLVM +ifeq ($(MESA_LLVM),1) +egl_SYS += $(LLVM_LIBS) +LDFLAGS += $(LLVM_LDFLAGS) + +st_GL_SYS += $(LLVM_LIBS) +endif + +OUTPUT_PATH := $(TOP)/$(LIB_DIR)/egl +OUTPUTS := $(addprefix $(OUTPUT_PATH)/, $(addsuffix .so, $(OUTPUTS))) + +default: $(OUTPUTS) + +$(OUTPUT_PATH)/egl_gallium.so: $(egl_OBJECTS) $(egl_LIBS) + $(MKLIB) -o $(notdir $@) -noprefix -linker '$(CXX)' \ + -ldflags '-L$(TOP)/$(LIB_DIR) -Wl,--no-undefined $(LDFLAGS)' \ + -cplusplus -install $(OUTPUT_PATH) $(MKLIB_OPTIONS) \ + $(egl_OBJECTS) -Wl,--start-group $(egl_LIBS) -Wl,--end-group \ + $(egl_SYS) + +$(OUTPUT_PATH)/st_GL.so: st_GL.o $(st_GL_LIBS) + $(MKLIB) -o $(notdir $@) -noprefix -linker '$(CXX)' \ + -ldflags '-L$(TOP)/$(LIB_DIR) $(LDFLAGS)' \ + -cplusplus -install $(OUTPUT_PATH) $(MKLIB_OPTIONS) \ + $< -Wl,--start-group $(st_GL_LIBS) -Wl,--end-group \ + $(st_GL_SYS) + +$(egl_OBJECTS): %.o: %.c + $(CC) -c -o $@ $< $(egl_CPPFLAGS) $(DEFINES) $(CFLAGS) + +st_GL.o: st_GL.c + $(CC) -c -o $@ $< $(st_GL_CPPFLAGS) $(DEFINES) $(CFLAGS) + +install: $(OUTPUTS) + $(INSTALL) -d $(DESTDIR)$(EGL_DRIVER_INSTALL_DIR) + for out in $(OUTPUTS); do \ + $(MINSTALL) -m 755 "$$out" $(DESTDIR)$(EGL_DRIVER_INSTALL_DIR); \ + done + +clean: + rm -f *.o diff --git a/src/gallium/targets/egl-static/SConscript b/src/gallium/targets/egl-static/SConscript index cbd98cc416a..dfd05437231 100644 --- a/src/gallium/targets/egl-static/SConscript +++ b/src/gallium/targets/egl-static/SConscript @@ -79,21 +79,17 @@ if True: openvg_name = 'OpenVG' if env['platform'] != 'windows' else 'libOpenVG' env.Prepend(LIBS = [openvg_name, st_vega]) -if env['x11']: +if env['HAVE_X11']: env.Prepend(LIBS = [ ws_xlib, - env['X11_LIBS'], ]) - -if env['dri']: - env.ParseConfig('pkg-config --cflags --libs xfixes') + env.PkgUseModules('X11') # pipe drivers -if env['drm']: - env.ParseConfig('pkg-config --cflags --libs libdrm') +if env['HAVE_DRM']: + env.PkgUseModules('DRM') - if env['drm_intel']: - env.ParseConfig('pkg-config --cflags --libs libdrm_intel') + if env['HAVE_DRM_INTEL']: env.Append(CPPDEFINES = ['_EGL_PIPE_I915', '_EGL_PIPE_I965']) env.Prepend(LIBS = [ i915drm, @@ -103,7 +99,7 @@ if env['drm']: ws_wrapper, ]) - if env['drm_radeon']: + if env['HAVE_DRM_RADEON']: env.Append(CPPDEFINES = ['_EGL_PIPE_R300', '_EGL_PIPE_R600']) env.Prepend(LIBS = [ radeonwinsys, diff --git a/src/gallium/targets/egl-static/egl.c b/src/gallium/targets/egl-static/egl.c index e617ff50208..568f5498dd4 100644 --- a/src/gallium/targets/egl-static/egl.c +++ b/src/gallium/targets/egl-static/egl.c @@ -28,6 +28,15 @@ #include "common/egl_g3d_loader.h" #include "egldriver.h" +#include "egllog.h" + +#ifdef HAVE_LIBUDEV +#include <stdio.h> /* for sscanf */ +#include <libudev.h> +#endif + +#define DRIVER_MAP_GALLIUM_ONLY +#include "pci_ids/pci_id_driver_map.h" #include "egl_pipe.h" #include "egl_st.h" @@ -52,15 +61,108 @@ get_st_api(enum st_api_type api) return stmod->stapi; } -static struct st_api * -guess_gl_api(enum st_profile_type profile) +#ifdef HAVE_LIBUDEV + +static boolean +drm_fd_get_pci_id(int fd, int *vendor_id, int *chip_id) { - return get_st_api(ST_API_OPENGL); + struct udev *udev = NULL; + struct udev_device *device = NULL, *parent; + struct stat buf; + const char *pci_id; + + *chip_id = -1; + + udev = udev_new(); + if (fstat(fd, &buf) < 0) { + _eglLog(_EGL_WARNING, "failed to stat fd %d", fd); + goto out; + } + + device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev); + if (device == NULL) { + _eglLog(_EGL_WARNING, + "could not create udev device for fd %d", fd); + goto out; + } + + parent = udev_device_get_parent(device); + if (parent == NULL) { + _eglLog(_EGL_WARNING, "could not get parent device"); + goto out; + } + + pci_id = udev_device_get_property_value(parent, "PCI_ID"); + if (pci_id == NULL || + sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2) { + _eglLog(_EGL_WARNING, "malformed or no PCI ID"); + *chip_id = -1; + goto out; + } + +out: + if (device) + udev_device_unref(device); + if (udev) + udev_unref(udev); + + return (*chip_id >= 0); +} + +#else + +static boolean +drm_fd_get_pci_id(int fd, int *vendor_id, int *chip_id) +{ + return FALSE; +} + +#endif /* HAVE_LIBUDEV */ + +static const char * +drm_fd_get_screen_name(int fd) +{ + int vendor_id, chip_id; + int idx, i; + + if (!drm_fd_get_pci_id(fd, &vendor_id, &chip_id)) { + _eglLog(_EGL_WARNING, "failed to get driver name for fd %d", fd); + return NULL; + } + + for (idx = 0; driver_map[idx].driver; idx++) { + if (vendor_id != driver_map[idx].vendor_id) + continue; + + /* done if no chip id */ + if (driver_map[idx].num_chips_ids == -1) + break; + + for (i = 0; i < driver_map[idx].num_chips_ids; i++) { + if (driver_map[idx].chip_ids[i] == chip_id) + break; + } + /* matched! */ + if (i < driver_map[idx].num_chips_ids) + break; + } + + _eglLog((driver_map[idx].driver) ? _EGL_INFO : _EGL_WARNING, + "pci id for fd %d: %04x:%04x, driver %s", + fd, vendor_id, chip_id, driver_map[idx].driver); + + return driver_map[idx].driver; } static struct pipe_screen * create_drm_screen(const char *name, int fd) { + if (!name) { + name = drm_fd_get_screen_name(fd); + if (!name) + return NULL; + } + return egl_pipe_create_drm_screen(name, fd); } @@ -79,7 +181,6 @@ loader_init(void) egl_g3d_loader.profile_masks[i] = egl_st_get_profile_mask(i); egl_g3d_loader.get_st_api = get_st_api; - egl_g3d_loader.guess_gl_api = guess_gl_api; egl_g3d_loader.create_drm_screen = create_drm_screen; egl_g3d_loader.create_sw_screen = create_sw_screen; @@ -95,7 +196,7 @@ loader_fini(void) struct st_module *stmod = &st_modules[i]; if (stmod->stapi) { - stmod->stapi->destroy(stmod->stapi); + egl_st_destroy_api(stmod->stapi); stmod->stapi = NULL; } stmod->initialized = FALSE; diff --git a/src/gallium/targets/egl-static/egl_st.c b/src/gallium/targets/egl-static/egl_st.c index 3db52621def..81d7bb47568 100644 --- a/src/gallium/targets/egl-static/egl_st.c +++ b/src/gallium/targets/egl-static/egl_st.c @@ -29,52 +29,143 @@ #include "state_tracker/st_api.h" #include "egl_st.h" -/* for st/mesa */ +#if FEATURE_GL || FEATURE_ES1 || FEATURE_ES2 #include "state_tracker/st_gl_api.h" -/* for st/vega */ +#endif + +#if FEATURE_VG #include "vg_api.h" +#endif + +#if _EGL_EXTERNAL_GL + +#include "util/u_string.h" +#include "util/u_dl.h" +#include "egldriver.h" +#include "egllog.h" + +static struct util_dl_library *egl_st_gl_lib; + +static EGLBoolean +dlopen_gl_lib_cb(const char *dir, size_t len, void *callback_data) +{ + const char *name = (const char *) callback_data; + char path[1024]; + int ret; + + if (len) { + ret = util_snprintf(path, sizeof(path), "%.*s/%s" UTIL_DL_EXT, + len, dir, name); + } + else { + ret = util_snprintf(path, sizeof(path), "%s" UTIL_DL_EXT, name); + } + + if (ret > 0 && ret < sizeof(path)) { + egl_st_gl_lib = util_dl_open(path); + if (egl_st_gl_lib) + _eglLog(_EGL_DEBUG, "loaded %s", path); + } + + return !egl_st_gl_lib; +} static struct st_api * -st_GL_create_api(void) +load_gl(const char *name, const char *procname) { -#if FEATURE_GL || FEATURE_ES1 || FEATURE_ES2 - return st_gl_api_create(); -#else - return NULL; -#endif + struct st_api *(*create_api)(void); + struct st_api *stapi = NULL; + + _eglSearchPathForEach(dlopen_gl_lib_cb, (void *) name); + if (!egl_st_gl_lib) + return NULL; + + create_api = (struct st_api *(*)(void)) + util_dl_get_proc_address(egl_st_gl_lib, procname); + if (create_api) + stapi = create_api(); + + if (!stapi) { + util_dl_close(egl_st_gl_lib); + egl_st_gl_lib = NULL; + } + + return stapi; } static struct st_api * -st_OpenVG_create_api(void) +egl_st_load_gl(void) { -#if FEATURE_VG - return (struct st_api *) vg_api_get(); -#else - return NULL; -#endif + const char module[] = "st_GL"; + const char symbol[] = "st_api_create_OpenGL"; + struct st_api *stapi; + + stapi = load_gl(module, symbol); + + /* try again with libglapi.so loaded */ + if (!stapi) { + struct util_dl_library *glapi = util_dl_open("libglapi" UTIL_DL_EXT); + + if (glapi) { + _eglLog(_EGL_DEBUG, "retry with libglapi" UTIL_DL_EXT " loaded"); + + stapi = load_gl(module, symbol); + util_dl_close(glapi); + } + } + if (!stapi) + _eglLog(_EGL_WARNING, "unable to load %s" UTIL_DL_EXT, module); + + return stapi; } +#endif /* _EGL_EXTERNAL_GL */ + struct st_api * egl_st_create_api(enum st_api_type api) { - struct st_api *stapi; + struct st_api *stapi = NULL; switch (api) { case ST_API_OPENGL: - stapi = st_GL_create_api(); +#if FEATURE_GL || FEATURE_ES1 || FEATURE_ES2 +#if _EGL_EXTERNAL_GL + stapi = egl_st_load_gl(); +#else + stapi = st_gl_api_create(); +#endif +#endif break; case ST_API_OPENVG: - stapi = st_OpenVG_create_api(); +#if FEATURE_VG + stapi = (struct st_api *) vg_api_get(); +#endif break; default: assert(!"Unknown API Type\n"); - stapi = NULL; break; } return stapi; } +void +egl_st_destroy_api(struct st_api *stapi) +{ +#if _EGL_EXTERNAL_GL + boolean is_gl = (stapi->api == ST_API_OPENGL); + + stapi->destroy(stapi); + + if (is_gl) { + util_dl_close(egl_st_gl_lib); + egl_st_gl_lib = NULL; + } +#else + stapi->destroy(stapi); +#endif +} + uint egl_st_get_profile_mask(enum st_api_type api) { diff --git a/src/gallium/targets/egl-static/egl_st.h b/src/gallium/targets/egl-static/egl_st.h index ba82faf0b0e..7a3773c6ba2 100644 --- a/src/gallium/targets/egl-static/egl_st.h +++ b/src/gallium/targets/egl-static/egl_st.h @@ -34,6 +34,9 @@ struct st_api * egl_st_create_api(enum st_api_type api); +void +egl_st_destroy_api(struct st_api *stapi); + uint egl_st_get_profile_mask(enum st_api_type api); diff --git a/src/gallium/targets/egl/egl.h b/src/gallium/targets/egl-static/st_GL.c index 5fd06785407..3f4b7a09fa4 100644 --- a/src/gallium/targets/egl/egl.h +++ b/src/gallium/targets/egl-static/st_GL.c @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 7.9 + * Version: 7.10 * - * Copyright (C) 2010 LunarG Inc. + * Copyright (C) 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"), @@ -25,20 +25,14 @@ * Authors: * Chia-I Wu <[email protected]> */ - -#ifndef _EGL_H_ -#define _EGL_H_ - +#include "state_tracker/st_gl_api.h" #include "pipe/p_compiler.h" -#include "state_tracker/st_api.h" - -#define ST_CREATE_OPENGL_SYMBOL "st_api_create_OpenGL" -#define ST_CREATE_OPENVG_SYMBOL "st_api_create_OpenVG" PUBLIC struct st_api * st_api_create_OpenGL(void); -PUBLIC struct st_api * -st_api_create_OpenVG(void); - -#endif /* _EGL_H_ */ +struct st_api * +st_api_create_OpenGL(void) +{ + return st_gl_api_create(); +} diff --git a/src/gallium/targets/egl/Makefile b/src/gallium/targets/egl/Makefile deleted file mode 100644 index dd566bd9a06..00000000000 --- a/src/gallium/targets/egl/Makefile +++ /dev/null @@ -1,242 +0,0 @@ -# src/gallium/targets/egl/Makefile -# -# This is the Makefile for EGL Gallium driver package. The package consists of -# -# egl_gallium.so - EGL driver -# pipe_<HW>.so - pipe drivers -# st_<API>.so - client API state trackers -# -# The following variables are examined -# -# EGL_PLATFORMS - platforms to support -# GALLIUM_WINSYS_DIRS - pipe drivers to support -# EGL_CLIENT_APIS - state trackers to support -# - -TOP = ../../../.. -include $(TOP)/configs/current - -ST_PREFIX := st_ -PIPE_PREFIX := pipe_ - -common_CPPFLAGS := \ - -I$(TOP)/include \ - -I$(TOP)/src/gallium/auxiliary \ - -I$(TOP)/src/gallium/drivers \ - -I$(TOP)/src/gallium/include \ - -I$(TOP)/src/gallium/winsys \ - $(LIBDRM_CFLAGS) - -common_SYS := -common_LIBS := \ - $(TOP)/src/gallium/drivers/identity/libidentity.a \ - $(TOP)/src/gallium/drivers/trace/libtrace.a \ - $(TOP)/src/gallium/drivers/rbug/librbug.a \ - $(GALLIUM_AUXILIARIES) - -# EGL driver -egl_CPPFLAGS := \ - -I$(TOP)/src/gallium/state_trackers/egl \ - -I$(TOP)/src/egl/main \ - -DPIPE_PREFIX=\"$(PIPE_PREFIX)\" -DST_PREFIX=\"$(ST_PREFIX)\" -egl_SYS := -lm $(DLOPEN_LIBS) -lEGL -egl_LIBS := $(TOP)/src/gallium/state_trackers/egl/libegl.a - -ifneq ($(findstring x11, $(EGL_PLATFORMS)),) -egl_SYS += -lX11 -lXext -lXfixes $(LIBDRM_LIB) -egl_LIBS += $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a -endif -ifneq ($(findstring wayland, $(EGL_PLATFORMS)),) -egl_SYS += $(WAYLAND_LIBS) $(LIBDRM_LIB) -egl_LIBS += $(TOP)/src/gallium/winsys/sw/wayland/libws_wayland.a -egl_LIBS += $(TOP)/src/egl/wayland/wayland-drm/libwayland-drm.a -endif -ifneq ($(findstring drm, $(EGL_PLATFORMS)),) -egl_SYS += $(LIBUDEV_LIBS) $(LIBDRM_LIB) -endif -ifneq ($(findstring fbdev, $(EGL_PLATFORMS)),) -egl_LIBS += $(TOP)/src/gallium/winsys/sw/fbdev/libfbdev.a -endif - -# EGL_RENDERABLE_TYPE is a compile time attribute -ifneq ($(filter $(GL_LIB), $(EGL_CLIENT_APIS)),) -egl_CPPFLAGS += $(API_DEFINES) -endif -ifneq ($(filter $(VG_LIB), $(EGL_CLIENT_APIS)),) -egl_CPPFLAGS += -DFEATURE_VG=1 -endif -egl_CPPFLAGS := $(sort $(egl_CPPFLAGS)) - -# i915 pipe driver -i915_CPPFLAGS := -i915_SYS := -ldrm_intel -i915_LIBS := \ - $(TOP)/src/gallium/winsys/i915/drm/libi915drm.a \ - $(TOP)/src/gallium/drivers/i915/libi915.a - -# i965 pipe driver -i965_CPPFLAGS := -i965_SYS := -ldrm_intel -i965_LIBS := \ - $(TOP)/src/gallium/winsys/i965/drm/libi965drm.a \ - $(TOP)/src/gallium/drivers/i965/libi965.a \ - $(TOP)/src/gallium/winsys/sw/wrapper/libwsw.a - -# nouveau pipe driver -nouveau_CPPFLAGS := -nouveau_SYS := -ldrm_nouveau -nouveau_LIBS := \ - $(TOP)/src/gallium/winsys/nouveau/drm/libnouveaudrm.a \ - $(TOP)/src/gallium/drivers/nvfx/libnvfx.a \ - $(TOP)/src/gallium/drivers/nv50/libnv50.a \ - $(TOP)/src/gallium/drivers/nvc0/libnvc0.a \ - $(TOP)/src/gallium/drivers/nouveau/libnouveau.a - -# r300 pipe driver -r300_CPPFLAGS := -r300_SYS := -ldrm -r300_LIBS := \ - $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ - $(TOP)/src/gallium/drivers/r300/libr300.a - -# r600 pipe driver -r600_CPPFLAGS := -r600_SYS := -ldrm -ldrm_radeon -r600_LIBS := \ - $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ - $(TOP)/src/gallium/drivers/r600/libr600.a - -# vmwgfx pipe driver -vmwgfx_CPPFLAGS := -vmwgfx_SYS := -vmwgfx_LIBS := \ - $(TOP)/src/gallium/winsys/svga/drm/libsvgadrm.a \ - $(TOP)/src/gallium/drivers/svga/libsvga.a - -# swrast (pseudo) pipe driver -swrast_CPPFLAGS := -DGALLIUM_SOFTPIPE -DGALLIUM_RBUG -DGALLIUM_TRACE -swrast_SYS := -lm -swrast_LIBS := $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a - -# LLVM -ifeq ($(MESA_LLVM),1) -common_SYS += $(LLVM_LIBS) -swrast_CPPFLAGS += -DGALLIUM_LLVMPIPE -swrast_LIBS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a -LDFLAGS += $(LLVM_LDFLAGS) -endif - -# OpenGL state tracker -GL_CPPFLAGS := -I$(TOP)/src/mesa $(API_DEFINES) -ifeq ($(SHARED_GLAPI),1) -GL_SYS := $(DRI_LIB_DEPS) -l$(GLAPI_LIB) -else -# cannot link to $(GL_LIB) as the app might want GL or GLES -GL_SYS := $(DRI_LIB_DEPS) -endif -GL_LIBS := $(TOP)/src/mesa/libmesagallium.a - -# OpenVG state tracker -OpenVG_CPPFLAGS := -I$(TOP)/src/gallium/state_trackers/vega -OpenVG_SYS := -lm -l$(VG_LIB) -OpenVG_LIBS := $(TOP)/src/gallium/state_trackers/vega/libvega.a - - -OUTPUT_PATH := $(TOP)/$(LIB_DIR)/egl - -# determine the outputs -ifneq ($(findstring i915/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += i915 -endif -ifneq ($(findstring i965/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += i965 -endif -ifneq ($(findstring nouveau/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += nouveau -endif -ifneq ($(findstring radeon/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += r300 -endif -ifneq ($(findstring r600/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += r600 -endif -ifneq ($(findstring svga/drm,$(GALLIUM_WINSYS_DIRS)),) -OUTPUTS += vmwgfx -endif -OUTPUTS += swrast -OUTPUTS := $(addprefix $(PIPE_PREFIX), $(OUTPUTS)) - -# EGL driver and state trackers -OUTPUTS += egl_gallium $(addprefix $(ST_PREFIX), $(EGL_CLIENT_APIS)) - -OUTPUTS := $(addsuffix .so, $(OUTPUTS)) -OUTPUTS := $(addprefix $(OUTPUT_PATH)/, $(OUTPUTS)) - -default: $(OUTPUTS) - -define mklib -$(MKLIB) -o $(notdir $@) -noprefix -linker '$(CC)' \ - -L$(TOP)/$(LIB_DIR) -ldflags '$(LDFLAGS)' \ - -install $(OUTPUT_PATH) $(MKLIB_OPTIONS) $< \ - -Wl,--start-group $(common_LIBS) $($(1)_LIBS) -Wl,--end-group \ - $(common_SYS) $($(1)_SYS) -endef - -define mklib-cxx -$(MKLIB) -o $(notdir $@) -noprefix -linker '$(CXX)' \ - -L$(TOP)/$(LIB_DIR) -ldflags '$(LDFLAGS)' \ - -cplusplus -install $(OUTPUT_PATH) $(MKLIB_OPTIONS) $< \ - -Wl,--start-group $(common_LIBS) $($(1)_LIBS) -Wl,--end-group \ - $(common_SYS) $($(1)_SYS) -endef - -# EGL driver -$(OUTPUT_PATH)/egl_gallium.so: egl.o $(egl_LIBS) - $(call mklib,egl) - -# pipe drivers -$(OUTPUT_PATH)/$(PIPE_PREFIX)i915.so: pipe_i915.o $(i915_LIBS) - $(call mklib,i915) - -$(OUTPUT_PATH)/$(PIPE_PREFIX)i965.so: pipe_i965.o $(i965_LIBS) - $(call mklib,i965) - -$(OUTPUT_PATH)/$(PIPE_PREFIX)nouveau.so: pipe_nouveau.o $(nouveau_LIBS) - $(call mklib,nouveau) - -$(OUTPUT_PATH)/$(PIPE_PREFIX)r300.so: pipe_r300.o $(r300_LIBS) - $(call mklib,r300) - -$(OUTPUT_PATH)/$(PIPE_PREFIX)r600.so: pipe_r600.o $(r600_LIBS) - $(call mklib,r600) - -$(OUTPUT_PATH)/$(PIPE_PREFIX)vmwgfx.so: pipe_vmwgfx.o $(vmwgfx_LIBS) - $(call mklib,vmwgfx) - -$(OUTPUT_PATH)/$(PIPE_PREFIX)swrast.so: pipe_swrast.o $(swrast_LIBS) - $(call mklib,swrast) - -# state trackers -$(OUTPUT_PATH)/$(ST_PREFIX)$(GL_LIB).so: st_GL.o $(GL_LIBS) - $(call mklib-cxx,GL) - -$(OUTPUT_PATH)/$(ST_PREFIX)$(VG_LIB).so: st_OpenVG.o $(OpenVG_LIBS) - $(call mklib,OpenVG) - -egl.o: egl.c - $(CC) -c -o $@ $< $(common_CPPFLAGS) $(egl_CPPFLAGS) $(DEFINES) $(CFLAGS) - -pipe_%.o: pipe_%.c - $(CC) -c -o $@ $< $(common_CPPFLAGS) $($*_CPPFLAGS) $(DEFINES) $(CFLAGS) - -st_%.o: st_%.c - $(CC) -c -o $@ $< $(common_CPPFLAGS) $($*_CPPFLAGS) $(DEFINES) $(CFLAGS) - -install: $(OUTPUTS) - $(INSTALL) -d $(DESTDIR)$(EGL_DRIVER_INSTALL_DIR) - for out in $(OUTPUTS); do \ - $(MINSTALL) -m 755 "$$out" $(DESTDIR)$(EGL_DRIVER_INSTALL_DIR); \ - done - -clean: - rm -f *.o diff --git a/src/gallium/targets/egl/egl.c b/src/gallium/targets/egl/egl.c deleted file mode 100644 index 3467aea9991..00000000000 --- a/src/gallium/targets/egl/egl.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 7.9 - * - * Copyright (C) 2010 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. - * - * Authors: - * Chia-I Wu <[email protected]> - */ - -#include "util/u_debug.h" -#include "util/u_string.h" -#include "util/u_memory.h" -#include "util/u_dl.h" -#include "egldriver.h" -#include "egllog.h" - -#include "state_tracker/st_api.h" -#include "state_tracker/drm_driver.h" -#include "common/egl_g3d_loader.h" - -#ifdef HAVE_LIBUDEV -#include <libudev.h> -#define DRIVER_MAP_GALLIUM_ONLY -#include "pci_ids/pci_id_driver_map.h" -#endif - -#include "egl.h" - -struct egl_g3d_loader egl_g3d_loader; - -static struct st_module { - boolean initialized; - char *name; - struct util_dl_library *lib; - struct st_api *stapi; -} st_modules[ST_API_COUNT]; - -static struct pipe_module { - boolean initialized; - char *name; - struct util_dl_library *lib; - const struct drm_driver_descriptor *drmdd; - struct pipe_screen *(*swrast_create_screen)(struct sw_winsys *); -} pipe_modules[16]; - -static char * -loader_strdup(const char *s) -{ - size_t len = (s) ? strlen(s) : 0; - char *t = MALLOC(len + 1); - if (t) { - memcpy(t, s, len); - t[len] = '\0'; - } - return t; -} - -static EGLBoolean -dlopen_st_module_cb(const char *dir, size_t len, void *callback_data) -{ - struct st_module *stmod = - (struct st_module *) callback_data; - char path[1024]; - int ret; - - if (len) { - ret = util_snprintf(path, sizeof(path), - "%.*s/" ST_PREFIX "%s" UTIL_DL_EXT, len, dir, stmod->name); - } - else { - ret = util_snprintf(path, sizeof(path), - ST_PREFIX "%s" UTIL_DL_EXT, stmod->name); - } - - if (ret > 0 && ret < sizeof(path)) { - stmod->lib = util_dl_open(path); - if (stmod->lib) - _eglLog(_EGL_DEBUG, "loaded %s", path); - } - - return !(stmod->lib); -} - -static boolean -load_st_module(struct st_module *stmod, - const char *name, const char *procname) -{ - struct st_api *(*create_api)(void); - - if (name) { - _eglLog(_EGL_DEBUG, "searching for st module %s", name); - stmod->name = loader_strdup(name); - } - else { - stmod->name = NULL; - } - - if (stmod->name) - _eglSearchPathForEach(dlopen_st_module_cb, (void *) stmod); - else - stmod->lib = util_dl_open(NULL); - - if (stmod->lib) { - create_api = (struct st_api *(*)(void)) - util_dl_get_proc_address(stmod->lib, procname); - if (create_api) - stmod->stapi = create_api(); - - if (!stmod->stapi) { - util_dl_close(stmod->lib); - stmod->lib = NULL; - } - } - - if (!stmod->stapi) { - FREE(stmod->name); - stmod->name = NULL; - } - - return (stmod->stapi != NULL); -} - -static EGLBoolean -dlopen_pipe_module_cb(const char *dir, size_t len, void *callback_data) -{ - struct pipe_module *pmod = (struct pipe_module *) callback_data; - char path[1024]; - int ret; - - if (len) { - ret = util_snprintf(path, sizeof(path), - "%.*s/" PIPE_PREFIX "%s" UTIL_DL_EXT, len, dir, pmod->name); - } - else { - ret = util_snprintf(path, sizeof(path), - PIPE_PREFIX "%s" UTIL_DL_EXT, pmod->name); - } - if (ret > 0 && ret < sizeof(path)) { - pmod->lib = util_dl_open(path); - if (pmod->lib) - _eglLog(_EGL_DEBUG, "loaded %s", path); - } - - return !(pmod->lib); -} - -static boolean -load_pipe_module(struct pipe_module *pmod, const char *name) -{ - pmod->name = loader_strdup(name); - if (!pmod->name) - return FALSE; - - _eglLog(_EGL_DEBUG, "searching for pipe module %s", pmod->name); - _eglSearchPathForEach(dlopen_pipe_module_cb, (void *) pmod); - if (pmod->lib) { - pmod->drmdd = (const struct drm_driver_descriptor *) - util_dl_get_proc_address(pmod->lib, "driver_descriptor"); - - /* sanity check on the name */ - if (pmod->drmdd && strcmp(pmod->drmdd->name, pmod->name) != 0) - pmod->drmdd = NULL; - - /* swrast */ - if (pmod->drmdd && !pmod->drmdd->driver_name) { - pmod->swrast_create_screen = - (struct pipe_screen *(*)(struct sw_winsys *)) - util_dl_get_proc_address(pmod->lib, "swrast_create_screen"); - if (!pmod->swrast_create_screen) - pmod->drmdd = NULL; - } - - if (!pmod->drmdd) { - util_dl_close(pmod->lib); - pmod->lib = NULL; - } - } - - return (pmod->drmdd != NULL); -} - -static struct st_api * -get_st_api_full(enum st_api_type api, enum st_profile_type profile) -{ - struct st_module *stmod = &st_modules[api]; - const char *names[8], *symbol; - int i, count = 0; - - if (stmod->initialized) - return stmod->stapi; - - switch (api) { - case ST_API_OPENGL: - symbol = ST_CREATE_OPENGL_SYMBOL; - names[count++] = "GL"; - break; - case ST_API_OPENVG: - symbol = ST_CREATE_OPENVG_SYMBOL; - names[count++] = "OpenVG"; - break; - default: - symbol = NULL; - assert(!"Unknown API Type\n"); - break; - } - - /* NULL means the process itself */ - names[count++] = NULL; - - for (i = 0; i < count; i++) { - if (load_st_module(stmod, names[i], symbol)) - break; - } - - /* try again with libGL.so loaded */ - if (!stmod->stapi && api == ST_API_OPENGL) { - struct util_dl_library *glapi = util_dl_open("libGL" UTIL_DL_EXT); - - if (glapi) { - _eglLog(_EGL_DEBUG, "retry with libGL" UTIL_DL_EXT " loaded"); - /* skip the last name (which is NULL) */ - for (i = 0; i < count - 1; i++) { - if (load_st_module(stmod, names[i], symbol)) - break; - } - util_dl_close(glapi); - } - } - - if (!stmod->stapi) { - EGLint level = (egl_g3d_loader.profile_masks[api]) ? - _EGL_WARNING : _EGL_DEBUG; - _eglLog(level, "unable to load " ST_PREFIX "%s" UTIL_DL_EXT, names[0]); - } - - stmod->initialized = TRUE; - - return stmod->stapi; -} - -static struct st_api * -get_st_api(enum st_api_type api) -{ - enum st_profile_type profile = ST_PROFILE_DEFAULT; - - /* determine the profile from the linked libraries */ - if (api == ST_API_OPENGL) { - struct util_dl_library *self; - - self = util_dl_open(NULL); - if (self) { - if (util_dl_get_proc_address(self, "glColor4x")) - profile = ST_PROFILE_OPENGL_ES1; - else if (util_dl_get_proc_address(self, "glShaderBinary")) - profile = ST_PROFILE_OPENGL_ES2; - util_dl_close(self); - } - } - - return get_st_api_full(api, profile); -} - -static struct st_api * -guess_gl_api(enum st_profile_type profile) -{ - return get_st_api_full(ST_API_OPENGL, profile); -} - -static struct pipe_module * -get_pipe_module(const char *name) -{ - struct pipe_module *pmod = NULL; - int i; - - if (!name) - return NULL; - - for (i = 0; i < Elements(pipe_modules); i++) { - if (!pipe_modules[i].initialized || - strcmp(pipe_modules[i].name, name) == 0) { - pmod = &pipe_modules[i]; - break; - } - } - if (!pmod) - return NULL; - - if (!pmod->initialized) { - load_pipe_module(pmod, name); - pmod->initialized = TRUE; - } - - return pmod; -} - -static char * -drm_fd_get_screen_name(int fd) -{ - char *driver = NULL; -#ifdef HAVE_LIBUDEV - struct udev *udev; - struct udev_device *device, *parent; - struct stat buf; - const char *pci_id; - int vendor_id, chip_id, i, j; - - udev = udev_new(); - if (fstat(fd, &buf) < 0) { - _eglLog(_EGL_WARNING, "failed to stat fd %d", fd); - return NULL; - } - - device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev); - if (device == NULL) { - _eglLog(_EGL_WARNING, - "could not create udev device for fd %d", fd); - return NULL; - } - - parent = udev_device_get_parent(device); - if (parent == NULL) { - _eglLog(_EGL_WARNING, "could not get parent device"); - goto out; - } - - pci_id = udev_device_get_property_value(parent, "PCI_ID"); - if (pci_id == NULL || - sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) { - _eglLog(_EGL_WARNING, "malformed or no PCI ID"); - goto out; - } - - for (i = 0; driver_map[i].driver; i++) { - if (vendor_id != driver_map[i].vendor_id) - continue; - if (driver_map[i].num_chips_ids == -1) { - driver = strdup(driver_map[i].driver); - _eglLog(_EGL_WARNING, - "pci id for %d: %04x:%04x, driver %s", - fd, vendor_id, chip_id, driver); - goto out; - } - - for (j = 0; j < driver_map[i].num_chips_ids; j++) - if (driver_map[i].chip_ids[j] == chip_id) { - driver = strdup(driver_map[i].driver); - _eglLog(_EGL_WARNING, - "pci id for %d: %04x:%04x, driver %s", - fd, vendor_id, chip_id, driver); - goto out; - } - } - -out: - udev_device_unref(device); - udev_unref(udev); - -#endif - return driver; -} - -static struct pipe_screen * -create_drm_screen(const char *name, int fd) -{ - struct pipe_module *pmod; - const char *screen_name = name; - - if (screen_name == NULL) - if ((screen_name = drm_fd_get_screen_name(fd)) == NULL) - return NULL; - pmod = get_pipe_module(screen_name); - - return (pmod && pmod->drmdd && pmod->drmdd->create_screen) ? - pmod->drmdd->create_screen(fd) : NULL; -} - -static struct pipe_screen * -create_sw_screen(struct sw_winsys *ws) -{ - struct pipe_module *pmod = get_pipe_module("swrast"); - return (pmod && pmod->swrast_create_screen) ? - pmod->swrast_create_screen(ws) : NULL; -} - -static const struct egl_g3d_loader * -loader_init(void) -{ - /* TODO detect at runtime? */ -#if FEATURE_GL - egl_g3d_loader.profile_masks[ST_API_OPENGL] |= ST_PROFILE_DEFAULT_MASK; -#endif -#if FEATURE_ES1 - egl_g3d_loader.profile_masks[ST_API_OPENGL] |= ST_PROFILE_OPENGL_ES1_MASK; -#endif -#if FEATURE_ES2 - egl_g3d_loader.profile_masks[ST_API_OPENGL] |= ST_PROFILE_OPENGL_ES2_MASK; -#endif -#if FEATURE_VG - egl_g3d_loader.profile_masks[ST_API_OPENVG] |= ST_PROFILE_DEFAULT_MASK; -#endif - - egl_g3d_loader.get_st_api = get_st_api; - egl_g3d_loader.guess_gl_api = guess_gl_api; - egl_g3d_loader.create_drm_screen = create_drm_screen; - egl_g3d_loader.create_sw_screen = create_sw_screen; - - return &egl_g3d_loader; -} - -static void -loader_fini(void) -{ - int i; - - for (i = 0; i < ST_API_COUNT; i++) { - struct st_module *stmod = &st_modules[i]; - - if (stmod->stapi) { - stmod->stapi->destroy(stmod->stapi); - stmod->stapi = NULL; - } - if (stmod->lib) { - util_dl_close(stmod->lib); - stmod->lib = NULL; - } - if (stmod->name) { - FREE(stmod->name); - stmod->name = NULL; - } - stmod->initialized = FALSE; - } - for (i = 0; i < Elements(pipe_modules); i++) { - struct pipe_module *pmod = &pipe_modules[i]; - - if (!pmod->initialized) - break; - - pmod->drmdd = NULL; - pmod->swrast_create_screen = NULL; - if (pmod->lib) { - util_dl_close(pmod->lib); - pmod->lib = NULL; - } - if (pmod->name) { - FREE(pmod->name); - pmod->name = NULL; - } - pmod->initialized = FALSE; - } -} - -static void -egl_g3d_unload(_EGLDriver *drv) -{ - egl_g3d_destroy_driver(drv); - loader_fini(); -} - -_EGLDriver * -_eglMain(const char *args) -{ - const struct egl_g3d_loader *loader; - _EGLDriver *drv; - - loader = loader_init(); - drv = egl_g3d_create_driver(loader); - if (!drv) { - loader_fini(); - return NULL; - } - - drv->Name = "Gallium"; - drv->Unload = egl_g3d_unload; - - return drv; -} diff --git a/src/gallium/targets/egl/st_GL.c b/src/gallium/targets/egl/st_GL.c deleted file mode 100644 index c1df844aa43..00000000000 --- a/src/gallium/targets/egl/st_GL.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "state_tracker/st_gl_api.h" -#include "egl.h" - -PUBLIC struct st_api * -st_api_create_OpenGL(void) -{ - return st_gl_api_create(); -} diff --git a/src/gallium/targets/egl/st_OpenVG.c b/src/gallium/targets/egl/st_OpenVG.c deleted file mode 100644 index d0bf4dbae91..00000000000 --- a/src/gallium/targets/egl/st_OpenVG.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "vg_api.h" -#include "egl.h" - -PUBLIC struct st_api * -st_api_create_OpenVG(void) -{ - return (struct st_api *) vg_api_get(); -} diff --git a/src/gallium/targets/gbm/Makefile b/src/gallium/targets/gbm/Makefile new file mode 100644 index 00000000000..b38782c4070 --- /dev/null +++ b/src/gallium/targets/gbm/Makefile @@ -0,0 +1,167 @@ +# src/gallium/targets/gbm/Makefile + +TOP = ../../../.. +include $(TOP)/configs/current + +PIPE_PREFIX := pipe_ + +GBM_BACKEND = gbm_gallium_drm +GBM_SOURCES = gbm.c pipe_loader.c + +GBM_INCLUDES = \ + -I$(TOP)/include \ + -I$(TOP)/src/gallium/state_trackers/gbm \ + -I$(TOP)/src/gbm/main \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/include \ + +GBM_LIBS = $(LIBUDEV_LIBS) $(LIBDRM_LIB) -lm \ + $(TOP)/src/gallium/state_trackers/gbm/libgbm.a \ + $(TOP)/src/gallium/drivers/identity/libidentity.a \ + $(TOP)/src/gallium/drivers/galahad/libgalahad.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/drivers/rbug/librbug.a \ + $(GALLIUM_AUXILIARIES) + + +GBM_CFLAGS = \ + -DGBM_BACKEND_SEARCH_DIR=\"$(GBM_BACKEND_INSTALL_DIR)\" \ + -DPIPE_PREFIX=\"$(PIPE_PREFIX)\" \ + $(LIBUDEV_CFLAGS) \ + $(LIBDRM_CFLAGS) + + +pipe_INCLUDES = \ + -I$(TOP)/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/winsys + +pipe_LIBS = \ + $(TOP)/src/gallium/drivers/identity/libidentity.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/drivers/rbug/librbug.a \ + $(GALLIUM_AUXILIARIES) + +# as if we are DRI modules +pipe_SYS = $(DRI_LIB_DEPS) + +pipe_CLFLAGS = \ + -DGALLIUM_RBUG -DGALLIUM_TRACE -DGALLIUM_GALAHAD \ + $(LIBDRM_CFLAGS) + +pipe_LDFLAGS = -Wl,--no-undefined + +# i915 pipe driver +i915_LIBS = \ + $(TOP)/src/gallium/winsys/i915/drm/libi915drm.a \ + $(TOP)/src/gallium/drivers/i915/libi915.a +i915_SYS = -ldrm_intel + +# i965 pipe driver +i965_LIBS = \ + $(TOP)/src/gallium/winsys/i965/drm/libi965drm.a \ + $(TOP)/src/gallium/drivers/i965/libi965.a \ + $(TOP)/src/gallium/winsys/sw/wrapper/libwsw.a +i965_SYS = -ldrm_intel + +# nouveau pipe driver +nouveau_LIBS = \ + $(TOP)/src/gallium/winsys/nouveau/drm/libnouveaudrm.a \ + $(TOP)/src/gallium/drivers/nvfx/libnvfx.a \ + $(TOP)/src/gallium/drivers/nv50/libnv50.a \ + $(TOP)/src/gallium/drivers/nvc0/libnvc0.a \ + $(TOP)/src/gallium/drivers/nouveau/libnouveau.a +nouveau_SYS = -ldrm_nouveau + +# r300 pipe driver +r300_LIBS = \ + $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ + $(TOP)/src/gallium/drivers/r300/libr300.a + +# r600 pipe driver +r600_LIBS = \ + $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ + $(TOP)/src/gallium/drivers/r600/libr600.a + +# vmwgfx pipe driver +vmwgfx_LIBS = \ + $(TOP)/src/gallium/winsys/svga/drm/libsvgadrm.a \ + $(TOP)/src/gallium/drivers/svga/libsvga.a + +# LLVM +ifeq ($(MESA_LLVM),1) +pipe_LIBS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a +pipe_SYS += $(LLVM_LIBS) +pipe_LDFLAGS += $(LLVM_LDFLAGS) +endif + +# determine the targets/sources +pipe_TARGETS = +pipe_SOURCES = + +ifneq ($(findstring i915/drm,$(GALLIUM_WINSYS_DIRS)),) +pipe_TARGETS += $(PIPE_PREFIX)i915.so +pipe_SOURCES += pipe_i915.c +endif + +ifneq ($(findstring i965/drm,$(GALLIUM_WINSYS_DIRS)),) +pipe_TARGETS += $(PIPE_PREFIX)i965.so +pipe_SOURCES += pipe_i965.c +endif + +ifneq ($(findstring nouveau/drm,$(GALLIUM_WINSYS_DIRS)),) +pipe_TARGETS += $(PIPE_PREFIX)nouveau.so +pipe_SOURCES += pipe_nouveau.c +endif + +ifneq ($(findstring radeon/drm,$(GALLIUM_WINSYS_DIRS)),) +pipe_TARGETS += $(PIPE_PREFIX)r300.so +pipe_SOURCES += pipe_r300.c +endif + +ifneq ($(findstring r600/drm,$(GALLIUM_WINSYS_DIRS)),) +pipe_TARGETS += $(PIPE_PREFIX)r600.so +pipe_SOURCES += pipe_r600.c +endif + +ifneq ($(findstring svga/drm,$(GALLIUM_WINSYS_DIRS)),) +pipe_TARGETS += $(PIPE_PREFIX)vmwgfx.so +pipe_SOURCES += pipe_vmwgfx.c +endif + +pipe_OBJECTS = $(pipe_SOURCES:.c=.o) + + +GBM_EXTRA_TARGETS = $(addprefix $(TOP)/$(LIB_DIR)/gbm/, $(pipe_TARGETS)) +GBM_EXTRA_INSTALL = install-pipes +GBM_EXTRA_CLEAN = clean-pipes +GBM_EXTRA_SOURCES = $(pipe_SOURCES) + +include $(TOP)/src/gbm/backends/Makefile.template + + +$(GBM_EXTRA_TARGETS): $(TOP)/$(LIB_DIR)/gbm/%: % + @$(INSTALL) -d $(dir $@) + $(INSTALL) $< $(dir $@) + +$(pipe_TARGETS): $(PIPE_PREFIX)%.so: pipe_%.o + $(MKLIB) -o $@ -noprefix -linker '$(CC)' \ + -ldflags '-L$(TOP)/$(LIB_DIR) $(pipe_LDFLAGS) $(LDFLAGS)' \ + $(MKLIB_OPTIONS) $< \ + -Wl,--start-group $(pipe_LIBS) $($*_LIBS) -Wl,--end-group \ + $(pipe_SYS) $($*_SYS) + +$(pipe_OBJECTS): %.o: %.c + $(CC) -c -o $@ $< $(pipe_INCLUDES) $(pipe_CFLAGS) $(CFLAGS) + +install-pipes: $(GBM_EXTRA_TARGETS) + $(INSTALL) -d $(DESTDIR)$(GBM_BACKEND_INSTALL_DIR) + for tgt in $(GBM_EXTRA_TARGETS); do \ + $(MINSTALL) "$$tgt" $(DESTDIR)$(GBM_BACKEND_INSTALL_DIR); \ + done + +clean-pipes: + rm -f $(pipe_TARGETS) + rm -f $(pipe_OBJECTS) diff --git a/src/gallium/targets/gbm/gbm.c b/src/gallium/targets/gbm/gbm.c new file mode 100644 index 00000000000..e840fc5fa1a --- /dev/null +++ b/src/gallium/targets/gbm/gbm.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 + * 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. + * + * Authors: + * Benjamin Franzke <[email protected]> + */ + +#include "util/u_inlines.h" + +#include "gbm_gallium_drmint.h" +#include "pipe_loader.h" + +static struct pipe_screen * +create_drm_screen(const char *name, int fd) +{ + struct pipe_module *pmod = get_pipe_module(name); + + return (pmod && pmod->drmdd && pmod->drmdd->create_screen) ? + pmod->drmdd->create_screen(fd) : NULL; +} + +int +gallium_screen_create(struct gbm_gallium_drm_device *gdrm) +{ + gdrm->base.driver_name = drm_fd_get_screen_name(gdrm->base.base.fd); + if (gdrm->base.driver_name == NULL) + return -1; + + gdrm->screen = create_drm_screen(gdrm->base.driver_name, gdrm->base.base.fd); + if (gdrm->screen == NULL) { + debug_printf("failed to load driver: %s\n", gdrm->base.driver_name); + return -1; + }; + + return 0; +} + +GBM_EXPORT struct gbm_backend gbm_backend = { + .backend_name = "gallium_drm", + .create_device = gbm_gallium_drm_device_create, +}; diff --git a/src/gallium/targets/egl/pipe_i915.c b/src/gallium/targets/gbm/pipe_i915.c index cd74044d8c1..cd74044d8c1 100644 --- a/src/gallium/targets/egl/pipe_i915.c +++ b/src/gallium/targets/gbm/pipe_i915.c diff --git a/src/gallium/targets/egl/pipe_i965.c b/src/gallium/targets/gbm/pipe_i965.c index f810ecffb0a..f810ecffb0a 100644 --- a/src/gallium/targets/egl/pipe_i965.c +++ b/src/gallium/targets/gbm/pipe_i965.c diff --git a/src/gallium/targets/gbm/pipe_loader.c b/src/gallium/targets/gbm/pipe_loader.c new file mode 100644 index 00000000000..6200541dbf0 --- /dev/null +++ b/src/gallium/targets/gbm/pipe_loader.c @@ -0,0 +1,192 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 + * 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. + * + * Authors: + * Kristian Høgsberg <[email protected]> + * Benjamin Franzke <[email protected]> + */ + +#include <stdio.h> +#include "util/u_string.h" +#include "util/u_memory.h" + +#include <libudev.h> + +#include "gbm_gallium_drmint.h" +#include "pipe_loader.h" +#define DRIVER_MAP_GALLIUM_ONLY +#include "pci_ids/pci_id_driver_map.h" + +static struct pipe_module pipe_modules[16]; + +static INLINE char * +loader_strdup(const char *str) +{ + return mem_dup(str, strlen(str) + 1); +} + +char * +drm_fd_get_screen_name(int fd) +{ + struct udev *udev; + struct udev_device *device, *parent; + const char *pci_id; + char *driver = NULL; + int vendor_id, chip_id, i, j; + + udev = udev_new(); + device = _gbm_udev_device_new_from_fd(udev, fd); + if (device == NULL) + return NULL; + + parent = udev_device_get_parent(device); + if (parent == NULL) { + fprintf(stderr, "gbm: could not get parent device"); + goto out; + } + + pci_id = udev_device_get_property_value(parent, "PCI_ID"); + if (pci_id == NULL || + sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) { + fprintf(stderr, "gbm: malformed or no PCI ID"); + goto out; + } + + for (i = 0; driver_map[i].driver; i++) { + if (vendor_id != driver_map[i].vendor_id) + continue; + if (driver_map[i].num_chips_ids == -1) { + driver = loader_strdup(driver_map[i].driver); + _gbm_log("pci id for %d: %04x:%04x, driver %s", + fd, vendor_id, chip_id, driver); + goto out; + } + + for (j = 0; j < driver_map[i].num_chips_ids; j++) + if (driver_map[i].chip_ids[j] == chip_id) { + driver = loader_strdup(driver_map[i].driver); + _gbm_log("pci id for %d: %04x:%04x, driver %s", + fd, vendor_id, chip_id, driver); + goto out; + } + } + +out: + udev_device_unref(device); + udev_unref(udev); + + return driver; +} + +static void +find_pipe_module(struct pipe_module *pmod, const char *name) +{ + char *search_paths, *end, *next, *p; + char path[PATH_MAX]; + int ret; + + search_paths = NULL; + if (geteuid() == getuid()) { + /* don't allow setuid apps to use GBM_BACKENDS_PATH */ + search_paths = getenv("GBM_BACKENDS_PATH"); + } + if (search_paths == NULL) + search_paths = GBM_BACKEND_SEARCH_DIR; + + end = search_paths + strlen(search_paths); + for (p = search_paths; p < end && pmod->lib == NULL; p = next + 1) { + int len; + next = strchr(p, ':'); + if (next == NULL) + next = end; + + len = next - p; + + if (len) { + ret = util_snprintf(path, sizeof(path), + "%.*s/" PIPE_PREFIX "%s" UTIL_DL_EXT, len, p, pmod->name); + } + else { + ret = util_snprintf(path, sizeof(path), + PIPE_PREFIX "%s" UTIL_DL_EXT, pmod->name); + } + if (ret > 0 && ret < sizeof(path)) { + pmod->lib = util_dl_open(path); + debug_printf("loaded %s\n", path); + } + + } +} + +static boolean +load_pipe_module(struct pipe_module *pmod, const char *name) +{ + pmod->name = loader_strdup(name); + if (!pmod->name) + return FALSE; + + find_pipe_module(pmod, name); + + if (pmod->lib) { + pmod->drmdd = (const struct drm_driver_descriptor *) + util_dl_get_proc_address(pmod->lib, "driver_descriptor"); + + /* sanity check on the name */ + if (pmod->drmdd && strcmp(pmod->drmdd->name, pmod->name) != 0) + pmod->drmdd = NULL; + + if (!pmod->drmdd) { + util_dl_close(pmod->lib); + pmod->lib = NULL; + } + } + + return (pmod->drmdd != NULL); +} + +struct pipe_module * +get_pipe_module(const char *name) +{ + struct pipe_module *pmod = NULL; + int i; + + if (!name) + return NULL; + + for (i = 0; i < Elements(pipe_modules); i++) { + if (!pipe_modules[i].initialized || + strcmp(pipe_modules[i].name, name) == 0) { + pmod = &pipe_modules[i]; + break; + } + } + if (!pmod) + return NULL; + + if (!pmod->initialized) { + load_pipe_module(pmod, name); + pmod->initialized = TRUE; + } + + return pmod; +} diff --git a/src/gallium/targets/gbm/pipe_loader.h b/src/gallium/targets/gbm/pipe_loader.h new file mode 100644 index 00000000000..2e4cd9906b7 --- /dev/null +++ b/src/gallium/targets/gbm/pipe_loader.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 + * 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. + * + * Authors: + * Benjamin Franzke <[email protected]> + */ + +#ifndef _PIPE_LOADER_H_ +#define _PIPE_LOADER_H_ + +#include "pipe/p_compiler.h" +#include "util/u_dl.h" +#include "state_tracker/drm_driver.h" + +struct pipe_module { + boolean initialized; + char *name; + struct util_dl_library *lib; + const struct drm_driver_descriptor *drmdd; +}; + +struct pipe_module * +get_pipe_module(const char *name); + +char * +drm_fd_get_screen_name(int fd); + +#endif diff --git a/src/gallium/targets/egl/pipe_nouveau.c b/src/gallium/targets/gbm/pipe_nouveau.c index 0c9081bc713..0c9081bc713 100644 --- a/src/gallium/targets/egl/pipe_nouveau.c +++ b/src/gallium/targets/gbm/pipe_nouveau.c diff --git a/src/gallium/targets/egl/pipe_r300.c b/src/gallium/targets/gbm/pipe_r300.c index 09940f0a194..09940f0a194 100644 --- a/src/gallium/targets/egl/pipe_r300.c +++ b/src/gallium/targets/gbm/pipe_r300.c diff --git a/src/gallium/targets/egl/pipe_r600.c b/src/gallium/targets/gbm/pipe_r600.c index 486a6592585..486a6592585 100644 --- a/src/gallium/targets/egl/pipe_r600.c +++ b/src/gallium/targets/gbm/pipe_r600.c diff --git a/src/gallium/targets/egl/pipe_swrast.c b/src/gallium/targets/gbm/pipe_swrast.c index b2e3289c5d3..b2e3289c5d3 100644 --- a/src/gallium/targets/egl/pipe_swrast.c +++ b/src/gallium/targets/gbm/pipe_swrast.c diff --git a/src/gallium/targets/egl/pipe_vmwgfx.c b/src/gallium/targets/gbm/pipe_vmwgfx.c index 22a28fa858a..22a28fa858a 100644 --- a/src/gallium/targets/egl/pipe_vmwgfx.c +++ b/src/gallium/targets/gbm/pipe_vmwgfx.c diff --git a/src/gallium/targets/libgl-xlib/Makefile b/src/gallium/targets/libgl-xlib/Makefile index 53a6c33ed82..f8f6c81b3f2 100644 --- a/src/gallium/targets/libgl-xlib/Makefile +++ b/src/gallium/targets/libgl-xlib/Makefile @@ -55,6 +55,7 @@ LIBS = \ # LLVM ifeq ($(MESA_LLVM),1) +PIPE_DRIVERS += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a DEFINES += -DGALLIUM_LLVMPIPE GL_LIB_DEPS += $(LLVM_LIBS) LDFLAGS += $(LLVM_LDFLAGS) diff --git a/src/gallium/targets/libgl-xlib/SConscript b/src/gallium/targets/libgl-xlib/SConscript index ca15372f1d9..ad8b0992e46 100644 --- a/src/gallium/targets/libgl-xlib/SConscript +++ b/src/gallium/targets/libgl-xlib/SConscript @@ -48,14 +48,17 @@ if False: env.Append(CPPDEFINES = 'GALLIUM_CELL') env.Prepend(LIBS = [cell]) -# TODO: write a wrapper function http://www.scons.org/wiki/WrapperFunctions -libgl = env.SharedLibrary( +# libGL.so.1.5 +libgl_1_5 = env.SharedLibrary( target ='GL', source = sources, + SHLIBSUFFIX = env['SHLIBSUFFIX'] + '.1.5', ) -if True: - # XXX: Only install this libGL.so if DRI not enabled - libgl = env.InstallSharedLibrary(libgl, version=(1, 5)) +# libGL.so.1 +libgl = env.subst('${SHLIBPREFIX}GL${SHLIBSUFFIX}') +libgl_1 = libgl + '.1' +env.Command(libgl_1, libgl_1_5, "ln -sf ${SOURCE.file} ${TARGET}") +env.Command(libgl, libgl_1, "ln -sf ${SOURCE.file} ${TARGET}") env.Alias('libgl-xlib', libgl) diff --git a/src/gallium/targets/va-r300/Makefile b/src/gallium/targets/va-r300/Makefile new file mode 100644 index 00000000000..c4b8fe770b8 --- /dev/null +++ b/src/gallium/targets/va-r300/Makefile @@ -0,0 +1,26 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = r300_drv_video + +DRIVER_DEFINES = -DGALLIUM_SOFTPIPE +DRIVER_INCLUDES = + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r300/libr300.a \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm --libs) -lXfixes + +include ../Makefile.va + +symlinks: diff --git a/src/gallium/targets/va-r300/target.c b/src/gallium/targets/va-r300/target.c new file mode 100644 index 00000000000..9f673bf17e6 --- /dev/null +++ b/src/gallium/targets/va-r300/target.c @@ -0,0 +1,24 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "radeon/drm/radeon_drm_public.h" +#include "r300/r300_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct radeon_winsys *radeon; + struct pipe_screen *screen; + + radeon = radeon_drm_winsys_create(fd); + if (!radeon) + return NULL; + + screen = r300_screen_create(radeon); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("r300", "radeon", create_screen) diff --git a/src/gallium/targets/va-r600/Makefile b/src/gallium/targets/va-r600/Makefile new file mode 100644 index 00000000000..28797ad528d --- /dev/null +++ b/src/gallium/targets/va-r600/Makefile @@ -0,0 +1,26 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = r600_drv_video + +DRIVER_DEFINES = -DGALLIUM_SOFTPIPE +DRIVER_INCLUDES = + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r600/libr600.a \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm --libs) -lXfixes + +include ../Makefile.va + +symlinks: diff --git a/src/gallium/targets/va-r600/target.c b/src/gallium/targets/va-r600/target.c new file mode 100644 index 00000000000..8753e2bab17 --- /dev/null +++ b/src/gallium/targets/va-r600/target.c @@ -0,0 +1,24 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "r600/drm/r600_drm_public.h" +#include "r600/r600_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct radeon *radeon; + struct pipe_screen *screen; + + radeon = r600_drm_winsys_create(fd); + if (!radeon) + return NULL; + + screen = r600_screen_create(radeon); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("r600", "radeon", create_screen) diff --git a/src/gallium/targets/va-softpipe/Makefile b/src/gallium/targets/va-softpipe/Makefile new file mode 100644 index 00000000000..a58df36a966 --- /dev/null +++ b/src/gallium/targets/va-softpipe/Makefile @@ -0,0 +1,21 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = softpipe_drv_video + +DRIVER_DEFINES = -DGALLIUM_SOFTPIPE +DRIVER_INCLUDES = + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + $(TOP)/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c + +DRIVER_LIBS = + +include ../Makefile.va + +symlinks: diff --git a/src/gallium/targets/vdpau-r300/Makefile b/src/gallium/targets/vdpau-r300/Makefile new file mode 100644 index 00000000000..fd4110b7855 --- /dev/null +++ b/src/gallium/targets/vdpau-r300/Makefile @@ -0,0 +1,27 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = vdpau_r300 + + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r300/libr300.a \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/gallium/drivers/rbug/librbug.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/drivers/galahad/libgalahad.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a \ + $(TOP)/src/mesa/libmesagallium.a + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm --libs) -lXfixes + +include ../Makefile.vdpau + +symlinks: diff --git a/src/gallium/targets/vdpau-r300/target.c b/src/gallium/targets/vdpau-r300/target.c new file mode 100644 index 00000000000..9f673bf17e6 --- /dev/null +++ b/src/gallium/targets/vdpau-r300/target.c @@ -0,0 +1,24 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "radeon/drm/radeon_drm_public.h" +#include "r300/r300_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct radeon_winsys *radeon; + struct pipe_screen *screen; + + radeon = radeon_drm_winsys_create(fd); + if (!radeon) + return NULL; + + screen = r300_screen_create(radeon); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("r300", "radeon", create_screen) diff --git a/src/gallium/targets/vdpau-r600/Makefile b/src/gallium/targets/vdpau-r600/Makefile new file mode 100644 index 00000000000..0fd817b8e82 --- /dev/null +++ b/src/gallium/targets/vdpau-r600/Makefile @@ -0,0 +1,22 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = vdpau_r600 + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r600/libr600.a \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm --libs) -lXfixes + +include ../Makefile.vdpau + +symlinks: diff --git a/src/gallium/targets/vdpau-r600/target.c b/src/gallium/targets/vdpau-r600/target.c new file mode 100644 index 00000000000..8753e2bab17 --- /dev/null +++ b/src/gallium/targets/vdpau-r600/target.c @@ -0,0 +1,24 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "r600/drm/r600_drm_public.h" +#include "r600/r600_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct radeon *radeon; + struct pipe_screen *screen; + + radeon = r600_drm_winsys_create(fd); + if (!radeon) + return NULL; + + screen = r600_screen_create(radeon); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("r600", "radeon", create_screen) diff --git a/src/gallium/targets/vdpau-softpipe/Makefile b/src/gallium/targets/vdpau-softpipe/Makefile new file mode 100644 index 00000000000..139b01b982a --- /dev/null +++ b/src/gallium/targets/vdpau-softpipe/Makefile @@ -0,0 +1,21 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = vdpau_softpipe + +DRIVER_DEFINES = -DGALLIUM_SOFTPIPE +DRIVER_INCLUDES = + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + $(TOP)/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c + +DRIVER_LIBS = + +include ../Makefile.vdpau + +symlinks: diff --git a/src/gallium/targets/xa-vmwgfx/Makefile b/src/gallium/targets/xa-vmwgfx/Makefile new file mode 100644 index 00000000000..fecdba695c7 --- /dev/null +++ b/src/gallium/targets/xa-vmwgfx/Makefile @@ -0,0 +1,101 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +##### MACROS ##### + +XA_MAJOR = 0 +XA_MINOR = 4 +XA_TINY = 0 +XA_CFLAGS = -g -fPIC + +XA_INCLUDES= -I$(TOP)/src/gallium/ \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/winsys \ + -I$(TOP)/src/gallium/drivers + +XA_LIB = xatracker +XA_LIB_NAME = lib$(XA_LIB).so +XA_LIB_GLOB = lib$(XA_LIB)*.so* +XA_LIB_DEPS = \ + $(TOP)/src/gallium/state_trackers/xa/libxatracker.o \ + $(TOP)/src/gallium/winsys/svga/drm/libsvgadrm.a \ + $(TOP)/src/gallium/drivers/svga/libsvga.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/drivers/rbug/librbug.a + + +COMMON_GALLIUM_SOURCES= + +SOURCES = vmw_target.c +OBJECTS = $(SOURCES:.c=.o) + +ifeq ($(MESA_LLVM),1) +LDFLAGS += $(LLVM_LDFLAGS) +GALLIUM_AUXILIARIES += $(LLVM_LIBS) +else +LDFLAGS += -lstdc++ +endif + +##### RULES ##### + +.c.o: + $(CC) -c $(XA_CFLAGS) $(XA_INCLUDES) $< + + +##### TARGETS ##### + +default: $(TOP)/$(LIB_DIR)/gallium/$(XA_LIB_NAME) + + +# Make the library +$(TOP)/$(LIB_DIR)/gallium/$(XA_LIB_NAME): depend $(OBJECTS) $(XA_LIB_DEPS) + $(MKLIB) -o $(XA_LIB) -linker $(CC) -ldflags '$(LDFLAGS)' \ + -major $(XA_MAJOR) -minor $(XA_MINOR) -patch $(XA_TINY) \ + $(MKLIB_OPTIONS) \ + -exports $(TOP)/src/gallium/state_trackers/xa/xa_symbols\ + -install $(TOP)/$(LIB_DIR)/gallium \ + $(OBJECTS) $(XA_LIB_DEPS) $(GALLIUM_AUXILIARIES) + +# xa pkgconfig file +pcedit = sed \ + -e 's,@INSTALL_DIR@,$(INSTALL_DIR),g' \ + -e 's,@INSTALL_LIB_DIR@,$(INSTALL_LIB_DIR),g' \ + -e 's,@INSTALL_INC_DIR@,$(INSTALL_INC_DIR),g' \ + -e 's,@VERSION@,$(XA_MAJOR).$(XA_MINOR).$(XA_TINY),g' \ + -e 's,@XA_PC_REQ_PRIV@,$(XA_PC_REQ_PRIV),g' \ + -e 's,@XA_PC_LIB_PRIV@,$(XA_PC_LIB_PRIV),g' \ + -e 's,@XA_PC_CFLAGS@,$(XA_PC_CFLAGS),g' \ + -e 's,@XA_LIB@,$(XA_LIB),g' +xatracker.pc: xatracker.pc.in + $(pcedit) $< > $@ + +install: xatracker.pc + $(INSTALL) -d $(DESTDIR)$(INSTALL_INC_DIR) + $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR) + $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig + $(INSTALL) -m 644 $(TOP)/src/gallium/state_trackers/xa/xa_tracker.h $(DESTDIR)$(INSTALL_INC_DIR) + $(INSTALL) -m 644 $(TOP)/src/gallium/state_trackers/xa/xa_context.h $(DESTDIR)$(INSTALL_INC_DIR) + $(INSTALL) -m 644 $(TOP)/src/gallium/state_trackers/xa/xa_composite.h $(DESTDIR)$(INSTALL_INC_DIR) + $(MINSTALL) -m 755 $(TOP)/$(LIB_DIR)/gallium/$(XA_LIB_GLOB) $(DESTDIR)$(INSTALL_LIB_DIR) + $(INSTALL) -m 644 xatracker.pc $(DESTDIR)$(INSTALL_LIB_DIR)/pkgconfig + +clean: + -rm -f *.o *~ + -rm -f *.lo + -rm -f *.la + -rm -f *.pc + -rm -rf .libs + -rm -f depend depend.bak exptmp + + +depend: $(SOURCES) + @ echo "running $(MKDEP)" + @ rm -f depend + @ touch depend + @ $(MKDEP) $(MKDEP_OPTIONS) -I$(TOP)/include $(XA_INCLUDES) $(SOURCES) \ + > /dev/null + +-include depend + +FORCE: diff --git a/src/gallium/targets/xa-vmwgfx/vmw_target.c b/src/gallium/targets/xa-vmwgfx/vmw_target.c new file mode 100644 index 00000000000..15089d6db26 --- /dev/null +++ b/src/gallium/targets/xa-vmwgfx/vmw_target.c @@ -0,0 +1,26 @@ + +#include "target-helpers/inline_debug_helper.h" +#include "state_tracker/drm_driver.h" +#include "svga/drm/svga_drm_public.h" +#include "svga/svga_public.h" + +static struct pipe_screen * +create_screen(int fd) +{ + struct svga_winsys_screen *sws; + struct pipe_screen *screen; + + sws = svga_drm_winsys_screen_create(fd); + if (!sws) + return NULL; + + screen = svga_screen_create(sws); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("vmwgfx", "vmwgfx", create_screen) diff --git a/src/gallium/targets/xa-vmwgfx/xatracker.pc.in b/src/gallium/targets/xa-vmwgfx/xatracker.pc.in new file mode 100644 index 00000000000..4ea2f4057d7 --- /dev/null +++ b/src/gallium/targets/xa-vmwgfx/xatracker.pc.in @@ -0,0 +1,13 @@ +prefix=@INSTALL_DIR@ +exec_prefix=${prefix} +libdir=@INSTALL_LIB_DIR@ +includedir=@INSTALL_INC_DIR@ + +Name: xatracker +Description: Xorg Gallium3D acceleration library +Requires: +Requires.private: @XA_PC_REQ_PRIV@ +Version: @VERSION@ +Libs: -L${libdir} -l@XA_LIB@ +Libs.private: @XA_PC_LIB_PRIV@ +Cflags: -I${includedir} @XA_PC_CFLAGS@ diff --git a/src/gallium/targets/xorg-nouveau/Makefile b/src/gallium/targets/xorg-nouveau/Makefile index 5a2cdb1b0ef..755969cae27 100644 --- a/src/gallium/targets/xorg-nouveau/Makefile +++ b/src/gallium/targets/xorg-nouveau/Makefile @@ -1,7 +1,7 @@ TOP = ../../../.. include $(TOP)/configs/current -LIBNAME = modesetting_drv.so +LIBNAME = nouveau2_drv.so C_SOURCES = \ nouveau_target.c \ @@ -23,4 +23,7 @@ DRIVER_PIPES = \ DRIVER_LINKS = \ $(shell pkg-config --libs libdrm libdrm_nouveau) +DRIVER_INCLUDES = \ + $(shell pkg-config --cflags-only-I libdrm libdrm_nouveau xf86driproto) + include ../Makefile.xorg diff --git a/src/gallium/targets/xorg-nouveau/nouveau_xorg.c b/src/gallium/targets/xorg-nouveau/nouveau_xorg.c index f0d64925c73..43470a1656b 100644 --- a/src/gallium/targets/xorg-nouveau/nouveau_xorg.c +++ b/src/gallium/targets/xorg-nouveau/nouveau_xorg.c @@ -29,6 +29,9 @@ */ #include "../../state_trackers/xorg/xorg_winsys.h" +#include <nouveau_drmif.h> +#include <xorg/dri.h> +#include <xf86drmMode.h> static void nouveau_xorg_identify(int flags); static Bool nouveau_xorg_pci_probe(DriverPtr driver, int entity_num, @@ -38,23 +41,16 @@ static Bool nouveau_xorg_pci_probe(DriverPtr driver, int entity_num, static const struct pci_id_match nouveau_xorg_device_match[] = { { 0x10de, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0x00030000, 0x00ffffff, 0 }, - { 0x12d2, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, - 0x00030000, 0x00ffffff, 0 }, {0, 0, 0}, }; -static SymTabRec nouveau_xorg_chipsets[] = { - {PCI_MATCH_ANY, "NVIDIA Graphics Device"}, - {-1, NULL} -}; - static PciChipsets nouveau_xorg_pci_devices[] = { {PCI_MATCH_ANY, PCI_MATCH_ANY, NULL}, {-1, -1, NULL} }; static XF86ModuleVersionInfo nouveau_xorg_version = { - "modesetting", + "nouveau2", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, @@ -70,9 +66,9 @@ static XF86ModuleVersionInfo nouveau_xorg_version = { * Xorg driver exported structures */ -_X_EXPORT DriverRec modesetting = { +_X_EXPORT DriverRec nouveau2 = { 1, - "modesetting", + "nouveau2", nouveau_xorg_identify, NULL, xorg_tracker_available_options, @@ -85,7 +81,7 @@ _X_EXPORT DriverRec modesetting = { static MODULESETUPPROTO(nouveau_xorg_setup); -_X_EXPORT XF86ModuleData modesettingModuleData = { +_X_EXPORT XF86ModuleData nouveau2ModuleData = { &nouveau_xorg_version, nouveau_xorg_setup, NULL @@ -104,7 +100,7 @@ nouveau_xorg_setup(pointer module, pointer opts, int *errmaj, int *errmin) */ if (!setupDone) { setupDone = 1; - xf86AddDriver(&modesetting, module, HaveDriverFuncs); + xf86AddDriver(&nouveau2, module, HaveDriverFuncs); /* * The return value must be non-NULL on success even though there @@ -121,8 +117,7 @@ nouveau_xorg_setup(pointer module, pointer opts, int *errmaj, int *errmin) static void nouveau_xorg_identify(int flags) { - xf86PrintChipsets("modesetting", "Driver for Modesetting Kernel Drivers", - nouveau_xorg_chipsets); + xf86DrvMsg(0, X_INFO, "nouveau2: Gallium3D based 2D driver for NV30+ NVIDIA chipsets\n"); } static Bool @@ -131,13 +126,63 @@ nouveau_xorg_pci_probe(DriverPtr driver, { ScrnInfoPtr scrn = NULL; EntityInfoPtr entity; + struct nouveau_device *dev = NULL; + char *busid; + int chipset, ret; + + if (device->vendor_id != 0x10DE) + return FALSE; + + if (!xf86LoaderCheckSymbol("DRICreatePCIBusID")) { + xf86DrvMsg(-1, X_ERROR, "[drm] No DRICreatePCIBusID symbol\n"); + return FALSE; + } + busid = DRICreatePCIBusID(device); + + ret = nouveau_device_open(&dev, busid); + if (ret) { + xf86DrvMsg(-1, X_ERROR, "[drm] failed to open device\n"); + free(busid); + return FALSE; + } + + chipset = dev->chipset; + nouveau_device_close(&dev); + + ret = drmCheckModesettingSupported(busid); + free(busid); + if (ret) { + xf86DrvMsg(-1, X_ERROR, "[drm] KMS not enabled\n"); + return FALSE; + } + + switch (chipset & 0xf0) { + case 0x00: + case 0x10: + case 0x20: + xf86DrvMsg(-1, X_NOTICE, "Too old chipset: NV%02x\n", chipset); + return FALSE; + case 0x30: + case 0x40: + case 0x60: + case 0x50: + case 0x80: + case 0x90: + case 0xa0: + case 0xc0: + xf86DrvMsg(-1, X_INFO, "Detected chipset: NV%02x\n", chipset); + break; + default: + xf86DrvMsg(-1, X_ERROR, "Unknown chipset: NV%02x\n", chipset); + return FALSE; + } scrn = xf86ConfigPciEntity(scrn, 0, entity_num, nouveau_xorg_pci_devices, NULL, NULL, NULL, NULL, NULL); if (scrn != NULL) { scrn->driverVersion = 1; scrn->driverName = "nouveau"; - scrn->name = "modesetting"; + scrn->name = "nouveau2"; scrn->Probe = NULL; entity = xf86GetEntityInfo(entity_num); diff --git a/src/gallium/targets/xorg-vmwgfx/SConscript b/src/gallium/targets/xorg-vmwgfx/SConscript index 099d49cf1b7..41f4326ee86 100644 --- a/src/gallium/targets/xorg-vmwgfx/SConscript +++ b/src/gallium/targets/xorg-vmwgfx/SConscript @@ -4,10 +4,10 @@ Import('*') env = env.Clone() -env.ParseConfig('pkg-config --cflags --libs libdrm xorg-server') +env.PkgUseModules(['DRM', 'XORG']) if env['kms']: - env.ParseConfig('pkg-config --cflags --libs libkms') + env.PkgUseModules(['KMS']) env.Prepend(CPPPATH = [ '#/include', diff --git a/src/gallium/targets/xvmc-nouveau/Makefile b/src/gallium/targets/xvmc-nouveau/Makefile new file mode 100644 index 00000000000..e1aadbf4259 --- /dev/null +++ b/src/gallium/targets/xvmc-nouveau/Makefile @@ -0,0 +1,26 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = XvMCnouveau + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/nouveau/drm/libnouveaudrm.a \ + $(TOP)/src/gallium/drivers/nvfx/libnvfx.a \ + $(TOP)/src/gallium/drivers/nv50/libnv50.a \ + $(TOP)/src/gallium/drivers/nvc0/libnvc0.a \ + $(TOP)/src/gallium/drivers/nouveau/libnouveau.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm_nouveau --libs) -lXfixes + +include ../Makefile.xvmc + +symlinks: diff --git a/src/gallium/targets/xvmc-nouveau/target.c b/src/gallium/targets/xvmc-nouveau/target.c new file mode 100644 index 00000000000..9b61b036d26 --- /dev/null +++ b/src/gallium/targets/xvmc-nouveau/target.c @@ -0,0 +1,18 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "nouveau/drm/nouveau_drm_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct pipe_screen *screen; + + screen = nouveau_drm_screen_create(fd); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("nouveau", "nouveau", create_screen) diff --git a/src/gallium/targets/xvmc-r300/Makefile b/src/gallium/targets/xvmc-r300/Makefile new file mode 100644 index 00000000000..a427fe1a3cb --- /dev/null +++ b/src/gallium/targets/xvmc-r300/Makefile @@ -0,0 +1,22 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = XvMCr300 + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r300/libr300.a \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/radeon/drm/libradeonwinsys.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm --libs) -lXfixes + +include ../Makefile.xvmc + +symlinks: diff --git a/src/gallium/targets/xvmc-r300/target.c b/src/gallium/targets/xvmc-r300/target.c new file mode 100644 index 00000000000..9f673bf17e6 --- /dev/null +++ b/src/gallium/targets/xvmc-r300/target.c @@ -0,0 +1,24 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "radeon/drm/radeon_drm_public.h" +#include "r300/r300_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct radeon_winsys *radeon; + struct pipe_screen *screen; + + radeon = radeon_drm_winsys_create(fd); + if (!radeon) + return NULL; + + screen = r300_screen_create(radeon); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("r300", "radeon", create_screen) diff --git a/src/gallium/targets/xvmc-r600/Makefile b/src/gallium/targets/xvmc-r600/Makefile new file mode 100644 index 00000000000..0bb72f1eff9 --- /dev/null +++ b/src/gallium/targets/xvmc-r600/Makefile @@ -0,0 +1,22 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = XvMCr600 + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/drivers/r600/libr600.a \ + $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \ + $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \ + $(TOP)/src/gallium/drivers/trace/libtrace.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + target.c \ + $(COMMON_GALLIUM_SOURCES) \ + $(DRIVER_SOURCES) + +DRIVER_LIBS = $(shell pkg-config libdrm --libs) -lXfixes + +include ../Makefile.xvmc + +symlinks: diff --git a/src/gallium/targets/xvmc-r600/target.c b/src/gallium/targets/xvmc-r600/target.c new file mode 100644 index 00000000000..8753e2bab17 --- /dev/null +++ b/src/gallium/targets/xvmc-r600/target.c @@ -0,0 +1,24 @@ +#include "state_tracker/drm_driver.h" +#include "target-helpers/inline_debug_helper.h" +#include "r600/drm/r600_drm_public.h" +#include "r600/r600_public.h" + +static struct pipe_screen *create_screen(int fd) +{ + struct radeon *radeon; + struct pipe_screen *screen; + + radeon = r600_drm_winsys_create(fd); + if (!radeon) + return NULL; + + screen = r600_screen_create(radeon); + if (!screen) + return NULL; + + screen = debug_screen_wrap(screen); + + return screen; +} + +DRM_DRIVER_DESCRIPTOR("r600", "radeon", create_screen) diff --git a/src/gallium/targets/xvmc-softpipe/Makefile b/src/gallium/targets/xvmc-softpipe/Makefile new file mode 100644 index 00000000000..5b60bede589 --- /dev/null +++ b/src/gallium/targets/xvmc-softpipe/Makefile @@ -0,0 +1,21 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBBASENAME = XvMCsoftpipe + +DRIVER_DEFINES = -DGALLIUM_SOFTPIPE +DRIVER_INCLUDES = + +PIPE_DRIVERS = \ + $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a \ + $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \ + $(TOP)/src/gallium/auxiliary/libgallium.a + +C_SOURCES = \ + $(TOP)/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c + +DRIVER_LIBS = + +include ../Makefile.xvmc + +symlinks: diff --git a/src/gallium/tests/trivial/Makefile b/src/gallium/tests/trivial/Makefile index 2ed63419c7e..4ddbb0b73dc 100644 --- a/src/gallium/tests/trivial/Makefile +++ b/src/gallium/tests/trivial/Makefile @@ -1,4 +1,4 @@ -# progs/gallium/simple/Makefile +# src/gallium/tests/trivial/Makefile TOP = ../../../.. include $(TOP)/configs/current @@ -11,7 +11,12 @@ INCLUDES = \ -I$(TOP)/src/gallium/winsys \ $(PROG_INCLUDES) -LINKS = \ +ifeq ($(MESA_LLVM),1) +LINKS = $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a +LDFLAGS += $(LLVM_LDFLAGS) +endif + +LINKS += \ $(TOP)/src/gallium/drivers/rbug/librbug.a \ $(TOP)/src/gallium/drivers/trace/libtrace.a \ $(TOP)/src/gallium/drivers/galahad/libgalahad.a \ @@ -46,4 +51,4 @@ $(OBJECTS): %.o: %.c $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $(PROG_DEFINES) $< -o $@ $(PROGS): %: %.o $(LINKS) - $(CC) $(LDFLAGS) $< $(LINKS) -lm -lpthread -ldl -o $@ + $(CXX) $(LDFLAGS) $< $(LINKS) $(LLVM_LIBS) -lm -lpthread -ldl -o $@ diff --git a/src/gallium/tests/trivial/quad-tex.c b/src/gallium/tests/trivial/quad-tex.c index 3a64b1c8d96..6c38b1096c1 100644 --- a/src/gallium/tests/trivial/quad-tex.c +++ b/src/gallium/tests/trivial/quad-tex.c @@ -212,7 +212,7 @@ static void init_prog(struct program *p) p->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR; p->sampler.normalized_coords = 1; - surf_tmpl.format = templat.format; + surf_tmpl.format = PIPE_FORMAT_B8G8R8A8_UNORM; /* All drivers support this */ surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; surf_tmpl.u.tex.level = 0; surf_tmpl.u.tex.first_layer = 0; @@ -329,7 +329,7 @@ static void draw(struct program *p) /* vertex element data */ cso_set_vertex_elements(p->cso, 2, p->velem); - util_draw_vertex_buffer(p->pipe, + util_draw_vertex_buffer(p->pipe, p->cso, p->vbuf, 0, PIPE_PRIM_QUADS, 4, /* verts */ diff --git a/src/gallium/tests/trivial/tri.c b/src/gallium/tests/trivial/tri.c index bfd2f3ca9a3..656e92ee886 100644 --- a/src/gallium/tests/trivial/tri.c +++ b/src/gallium/tests/trivial/tri.c @@ -153,7 +153,7 @@ static void init_prog(struct program *p) p->rasterizer.cull_face = PIPE_FACE_NONE; p->rasterizer.gl_rasterization_rules = 1; - surf_tmpl.format = templat.format; + surf_tmpl.format = PIPE_FORMAT_B8G8R8A8_UNORM; surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; surf_tmpl.u.tex.level = 0; surf_tmpl.u.tex.first_layer = 0; @@ -258,7 +258,7 @@ static void draw(struct program *p) /* vertex element data */ cso_set_vertex_elements(p->cso, 2, p->velem); - util_draw_vertex_buffer(p->pipe, + util_draw_vertex_buffer(p->pipe, p->cso, p->vbuf, 0, PIPE_PRIM_TRIANGLES, 3, /* verts */ diff --git a/src/gallium/winsys/g3dvl/Makefile b/src/gallium/winsys/g3dvl/Makefile new file mode 100644 index 00000000000..6c793e0f15b --- /dev/null +++ b/src/gallium/winsys/g3dvl/Makefile @@ -0,0 +1,12 @@ +# src/gallium/winsys/Makefile +TOP = ../../../.. +include $(TOP)/configs/current + +SUBDIRS = $(GALLIUM_STATE_TRACKERS_DIRS) $(GALLIUM_WINSYS_DIRS) + +default install clean: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir && $(MAKE) $@) || exit 1; \ + fi \ + done diff --git a/src/gallium/winsys/g3dvl/dri/Makefile b/src/gallium/winsys/g3dvl/dri/Makefile new file mode 100644 index 00000000000..b270e780fec --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/Makefile @@ -0,0 +1,15 @@ +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = vldri + +LIBRARY_INCLUDES = -I$(TOP)/src/gallium/winsys/g3dvl \ + $(shell pkg-config libdrm --cflags-only-I) + +C_SOURCES = \ + driclient.c \ + XF86dri.c \ + dri2.c \ + dri_winsys.c + +include ../../../Makefile.template diff --git a/src/gallium/winsys/g3dvl/dri/XF86dri.c b/src/gallium/winsys/g3dvl/dri/XF86dri.c new file mode 100644 index 00000000000..831a7603396 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/XF86dri.c @@ -0,0 +1,618 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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 PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + * Kevin E. Martin <[email protected]> + * Jens Owen <[email protected]> + * Rickard E. (Rik) Faith <[email protected]> + * + */ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +#include <X11/Xlibint.h> +#include <X11/extensions/Xext.h> +#include <X11/extensions/extutil.h> +#include "xf86dristr.h" + +static XExtensionInfo _xf86dri_info_data; +static XExtensionInfo *xf86dri_info = &_xf86dri_info_data; +static char xf86dri_extension_name[] = XF86DRINAME; + +#define XF86DRICheckExtension(dpy,i,val) \ + XextCheckExtension (dpy, i, xf86dri_extension_name, val) + +/***************************************************************************** + * * + * private utility routines * + * * + *****************************************************************************/ + +static int close_display(Display *dpy, XExtCodes *extCodes); +static /* const */ XExtensionHooks xf86dri_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + close_display, /* close_display */ + NULL, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + NULL, /* error_string */ +}; + +static XEXT_GENERATE_FIND_DISPLAY (find_display, xf86dri_info, + xf86dri_extension_name, + &xf86dri_extension_hooks, + 0, NULL) + +static XEXT_GENERATE_CLOSE_DISPLAY (close_display, xf86dri_info) + + +/***************************************************************************** + * * + * public XFree86-DRI Extension routines * + * * + *****************************************************************************/ + +#if 0 +#include <stdio.h> +#define TRACE(msg) fprintf(stderr,"XF86DRI%s\n", msg); +#else +#define TRACE(msg) +#endif + +#define PUBLIC + +PUBLIC Bool XF86DRIQueryExtension (dpy, event_basep, error_basep) + Display *dpy; + int *event_basep, *error_basep; +{ + XExtDisplayInfo *info = find_display (dpy); + + TRACE("QueryExtension..."); + if (XextHasExtension(info)) { + *event_basep = info->codes->first_event; + *error_basep = info->codes->first_error; + TRACE("QueryExtension... return True"); + return True; + } else { + TRACE("QueryExtension... return False"); + return False; + } +} + +PUBLIC Bool XF86DRIQueryVersion(dpy, majorVersion, minorVersion, patchVersion) + Display* dpy; + int* majorVersion; + int* minorVersion; + int* patchVersion; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIQueryVersionReply rep; + xXF86DRIQueryVersionReq *req; + + TRACE("QueryVersion..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryVersion, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryVersion; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return False"); + return False; + } + *majorVersion = rep.majorVersion; + *minorVersion = rep.minorVersion; + *patchVersion = rep.patchVersion; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return True"); + return True; +} + +PUBLIC Bool XF86DRIQueryDirectRenderingCapable(dpy, screen, isCapable) + Display* dpy; + int screen; + Bool* isCapable; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIQueryDirectRenderingCapableReply rep; + xXF86DRIQueryDirectRenderingCapableReq *req; + + TRACE("QueryDirectRenderingCapable..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryDirectRenderingCapable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryDirectRenderingCapable; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return False"); + return False; + } + *isCapable = rep.isCapable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return True"); + return True; +} + +PUBLIC Bool XF86DRIOpenConnection(dpy, screen, hSAREA, busIdString) + Display* dpy; + int screen; + drm_handle_t * hSAREA; + char **busIdString; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIOpenConnectionReply rep; + xXF86DRIOpenConnectionReq *req; + + TRACE("OpenConnection..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIOpenConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIOpenConnection; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + + *hSAREA = rep.hSAREALow; + if (sizeof(drm_handle_t) == 8) { + int shift = 32; /* var to prevent warning on next line */ + *hSAREA |= ((drm_handle_t) rep.hSAREAHigh) << shift; + } + + if (rep.length) { + if (!(*busIdString = (char *)Xcalloc(rep.busIdStringLength + 1, 1))) { + _XEatData(dpy, ((rep.busIdStringLength+3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + _XReadPad(dpy, *busIdString, rep.busIdStringLength); + } else { + *busIdString = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return True"); + return True; +} + +PUBLIC Bool XF86DRIAuthConnection(dpy, screen, magic) + Display* dpy; + int screen; + drm_magic_t magic; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIAuthConnectionReq *req; + xXF86DRIAuthConnectionReply rep; + + TRACE("AuthConnection..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIAuthConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIAuthConnection; + req->screen = screen; + req->magic = magic; + rep.authenticated = 0; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.authenticated) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return False"); + return False; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return True"); + return True; +} + +PUBLIC Bool XF86DRICloseConnection(dpy, screen) + Display* dpy; + int screen; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRICloseConnectionReq *req; + + TRACE("CloseConnection..."); + + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICloseConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICloseConnection; + req->screen = screen; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CloseConnection... return True"); + return True; +} + +PUBLIC Bool XF86DRIGetClientDriverName(dpy, screen, ddxDriverMajorVersion, + ddxDriverMinorVersion, ddxDriverPatchVersion, clientDriverName) + Display* dpy; + int screen; + int* ddxDriverMajorVersion; + int* ddxDriverMinorVersion; + int* ddxDriverPatchVersion; + char** clientDriverName; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIGetClientDriverNameReply rep; + xXF86DRIGetClientDriverNameReq *req; + + TRACE("GetClientDriverName..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetClientDriverName, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetClientDriverName; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + + *ddxDriverMajorVersion = rep.ddxDriverMajorVersion; + *ddxDriverMinorVersion = rep.ddxDriverMinorVersion; + *ddxDriverPatchVersion = rep.ddxDriverPatchVersion; + + if (rep.length) { + if (!(*clientDriverName = (char *)Xcalloc(rep.clientDriverNameLength + 1, 1))) { + _XEatData(dpy, ((rep.clientDriverNameLength+3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + _XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength); + } else { + *clientDriverName = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return True"); + return True; +} + +PUBLIC Bool XF86DRICreateContextWithConfig(dpy, screen, configID, context, + hHWContext) + Display* dpy; + int screen; + int configID; + XID* context; + drm_context_t * hHWContext; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRICreateContextReply rep; + xXF86DRICreateContextReq *req; + + TRACE("CreateContext..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateContext; + req->visual = configID; + req->screen = screen; + *context = XAllocID(dpy); + req->context = *context; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return False"); + return False; + } + *hHWContext = rep.hHWContext; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return True"); + return True; +} + +PUBLIC Bool XF86DRICreateContext(dpy, screen, visual, context, hHWContext) + Display* dpy; + int screen; + Visual* visual; + XID* context; + drm_context_t * hHWContext; +{ + return XF86DRICreateContextWithConfig( dpy, screen, visual->visualid, + context, hHWContext ); +} + +PUBLIC Bool XF86DRIDestroyContext( Display * ndpy, int screen, + XID context ) +{ + Display * const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIDestroyContextReq *req; + + TRACE("DestroyContext..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyContext; + req->screen = screen; + req->context = context; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyContext... return True"); + return True; +} + +PUBLIC Bool XF86DRICreateDrawable( Display * ndpy, int screen, + Drawable drawable, drm_drawable_t * hHWDrawable ) +{ + Display * const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display (dpy); + xXF86DRICreateDrawableReply rep; + xXF86DRICreateDrawableReq *req; + + TRACE("CreateDrawable..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateDrawable; + req->screen = screen; + req->drawable = drawable; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return False"); + return False; + } + *hHWDrawable = rep.hHWDrawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return True"); + return True; +} + +PUBLIC Bool XF86DRIDestroyDrawable( Display * ndpy, int screen, + Drawable drawable ) +{ + Display * const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIDestroyDrawableReq *req; + + TRACE("DestroyDrawable..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyDrawable; + req->screen = screen; + req->drawable = drawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyDrawable... return True"); + return True; +} + +PUBLIC Bool XF86DRIGetDrawableInfo(Display* dpy, int screen, Drawable drawable, + unsigned int* index, unsigned int* stamp, + int* X, int* Y, int* W, int* H, + int* numClipRects, drm_clip_rect_t ** pClipRects, + int* backX, int* backY, + int* numBackClipRects, drm_clip_rect_t ** pBackClipRects ) +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIGetDrawableInfoReply rep; + xXF86DRIGetDrawableInfoReq *req; + int total_rects; + + TRACE("GetDrawableInfo..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDrawableInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDrawableInfo; + req->screen = screen; + req->drawable = drawable; + + if (!_XReply(dpy, (xReply *)&rep, 1, xFalse)) + { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } + *index = rep.drawableTableIndex; + *stamp = rep.drawableTableStamp; + *X = (int)rep.drawableX; + *Y = (int)rep.drawableY; + *W = (int)rep.drawableWidth; + *H = (int)rep.drawableHeight; + *numClipRects = rep.numClipRects; + total_rects = *numClipRects; + + *backX = rep.backX; + *backY = rep.backY; + *numBackClipRects = rep.numBackClipRects; + total_rects += *numBackClipRects; + +#if 0 + /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks + * backwards compatibility (Because of the >> 2 shift) but the fix + * enables multi-threaded apps to work. + */ + if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply) + + total_rects * sizeof(drm_clip_rect_t)) + 3) & ~3) >> 2)) { + _XEatData(dpy, rep.length); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } +#endif + + if (*numClipRects) { + int len = sizeof(drm_clip_rect_t) * (*numClipRects); + + *pClipRects = (drm_clip_rect_t *)Xcalloc(len, 1); + if (*pClipRects) + _XRead(dpy, (char*)*pClipRects, len); + } else { + *pClipRects = NULL; + } + + if (*numBackClipRects) { + int len = sizeof(drm_clip_rect_t) * (*numBackClipRects); + + *pBackClipRects = (drm_clip_rect_t *)Xcalloc(len, 1); + if (*pBackClipRects) + _XRead(dpy, (char*)*pBackClipRects, len); + } else { + *pBackClipRects = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return True"); + return True; +} + +PUBLIC Bool XF86DRIGetDeviceInfo(dpy, screen, hFrameBuffer, + fbOrigin, fbSize, fbStride, devPrivateSize, pDevPrivate) + Display* dpy; + int screen; + drm_handle_t * hFrameBuffer; + int* fbOrigin; + int* fbSize; + int* fbStride; + int* devPrivateSize; + void** pDevPrivate; +{ + XExtDisplayInfo *info = find_display (dpy); + xXF86DRIGetDeviceInfoReply rep; + xXF86DRIGetDeviceInfoReq *req; + + TRACE("GetDeviceInfo..."); + XF86DRICheckExtension (dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDeviceInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDeviceInfo; + req->screen = screen; + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + + *hFrameBuffer = rep.hFrameBufferLow; + if (sizeof(drm_handle_t) == 8) { + int shift = 32; /* var to prevent warning on next line */ + *hFrameBuffer |= ((drm_handle_t) rep.hFrameBufferHigh) << shift; + } + + *fbOrigin = rep.framebufferOrigin; + *fbSize = rep.framebufferSize; + *fbStride = rep.framebufferStride; + *devPrivateSize = rep.devPrivateSize; + + if (rep.length) { + if (!(*pDevPrivate = (void *)Xcalloc(rep.devPrivateSize, 1))) { + _XEatData(dpy, ((rep.devPrivateSize+3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + _XRead(dpy, (char*)*pDevPrivate, rep.devPrivateSize); + } else { + *pDevPrivate = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return True"); + return True; +} + +PUBLIC Bool XF86DRIOpenFullScreen(dpy, screen, drawable) + Display* dpy; + int screen; + Drawable drawable; +{ + /* This function and the underlying X protocol are deprecated. + */ + (void) dpy; + (void) screen; + (void) drawable; + return False; +} + +PUBLIC Bool XF86DRICloseFullScreen(dpy, screen, drawable) + Display* dpy; + int screen; + Drawable drawable; +{ + /* This function and the underlying X protocol are deprecated. + */ + (void) dpy; + (void) screen; + (void) drawable; + return True; +} + diff --git a/src/gallium/winsys/g3dvl/dri/dri2.c b/src/gallium/winsys/g3dvl/dri/dri2.c new file mode 100644 index 00000000000..12ed6d0ab74 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/dri2.c @@ -0,0 +1,666 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Soft- + * ware"), to deal in the Software without restriction, including without + * limitation the rights to use, copy, modify, merge, publish, distribute, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, provided that the above copyright + * notice(s) and this permission notice appear in all copies of the Soft- + * ware and that both the above copyright notice(s) and this permission + * notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- + * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY + * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN + * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- + * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- + * MANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization of + * the copyright holder. + * + * Authors: + * Kristian Høgsberg ([email protected]) + */ + + +#define NEED_REPLIES +#include <stdio.h> +#include <X11/Xlibint.h> +#include <X11/extensions/Xext.h> +#include <X11/extensions/extutil.h> +#include <X11/extensions/dri2proto.h> +#include "xf86drm.h" +#include "dri2.h" +#if 0 +#include "glxclient.h" +#include "GL/glxext.h" +#endif + +/* Allow the build to work with an older versions of dri2proto.h and + * dri2tokens.h. + */ +#if DRI2_MINOR < 1 +#undef DRI2_MINOR +#define DRI2_MINOR 1 +#define X_DRI2GetBuffersWithFormat 7 +#endif + + +static char dri2ExtensionName[] = DRI2_NAME; +static XExtensionInfo *dri2Info; +static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info) + +static Bool +DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire); +static Status +DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire); + +static /* const */ XExtensionHooks dri2ExtensionHooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + DRI2CloseDisplay, /* close_display */ + DRI2WireToEvent, /* wire_to_event */ + DRI2EventToWire, /* event_to_wire */ + NULL, /* error */ + NULL, /* error_string */ +}; + +static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay, + dri2Info, + dri2ExtensionName, + &dri2ExtensionHooks, + 0, NULL) + +static Bool +DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire) +{ +#if 0 + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + XExtDisplayInfo *glx_info = __glXFindDisplay(dpy); + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + switch ((wire->u.u.type & 0x7f) - info->codes->first_event) { + +#ifdef X_DRI2SwapBuffers + case DRI2_BufferSwapComplete: + { + GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event; + xDRI2BufferSwapComplete *awire = (xDRI2BufferSwapComplete *)wire; + aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); + aevent->type = + (glx_info->codes->first_event + GLX_BufferSwapComplete) & 0x75; + aevent->send_event = (awire->type & 0x80) != 0; + aevent->display = dpy; + aevent->drawable = awire->drawable; + switch (awire->event_type) { + case DRI2_EXCHANGE_COMPLETE: + aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL; + break; + case DRI2_BLIT_COMPLETE: + aevent->event_type = GLX_BLIT_COMPLETE_INTEL; + break; + case DRI2_FLIP_COMPLETE: + aevent->event_type = GLX_FLIP_COMPLETE_INTEL; + break; + default: + /* unknown swap completion type */ + return False; + } + aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; + aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; + aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo; + return True; + } +#endif +#ifdef DRI2_InvalidateBuffers + case DRI2_InvalidateBuffers: + { + xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire; + + dri2InvalidateBuffers(dpy, awire->drawable); + return False; + } +#endif + default: + /* client doesn't support server event */ + break; + } +#endif + return False; +} + +/* We don't actually support this. It doesn't make sense for clients to + * send each other DRI2 events. + */ +static Status +DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + switch (event->type) { + default: + /* client doesn't support server event */ + break; + } + + return Success; +} + +Bool +DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + + if (XextHasExtension(info)) { + *eventBase = info->codes->first_event; + *errorBase = info->codes->first_error; + return True; + } + + return False; +} + +Bool +DRI2QueryVersion(Display * dpy, int *major, int *minor) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2QueryVersionReply rep; + xDRI2QueryVersionReq *req; + int i, nevents; + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReq(DRI2QueryVersion, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2QueryVersion; + req->majorVersion = DRI2_MAJOR; + req->minorVersion = DRI2_MINOR; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + *major = rep.majorVersion; + *minor = rep.minorVersion; + UnlockDisplay(dpy); + SyncHandle(); + + switch (rep.minorVersion) { + case 1: + nevents = 0; + break; + case 2: + nevents = 1; + break; + case 3: + default: + nevents = 2; + break; + } + + for (i = 0; i < nevents; i++) { + XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent); + XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire); + } + + return True; +} + +Bool +DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2ConnectReply rep; + xDRI2ConnectReq *req; + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReq(DRI2Connect, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2Connect; + req->window = window; + req->driverType = DRI2DriverDRI; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + *driverName = Xmalloc(rep.driverNameLength + 1); + if (*driverName == NULL) { + _XEatData(dpy, + ((rep.driverNameLength + 3) & ~3) + + ((rep.deviceNameLength + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + _XReadPad(dpy, *driverName, rep.driverNameLength); + (*driverName)[rep.driverNameLength] = '\0'; + + *deviceName = Xmalloc(rep.deviceNameLength + 1); + if (*deviceName == NULL) { + Xfree(*driverName); + _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + _XReadPad(dpy, *deviceName, rep.deviceNameLength); + (*deviceName)[rep.deviceNameLength] = '\0'; + + UnlockDisplay(dpy); + SyncHandle(); + + return True; +} + +Bool +DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2AuthenticateReq *req; + xDRI2AuthenticateReply rep; + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReq(DRI2Authenticate, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2Authenticate; + req->window = window; + req->magic = magic; + + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + UnlockDisplay(dpy); + SyncHandle(); + + return rep.authenticated; +} + +void +DRI2CreateDrawable(Display * dpy, XID drawable) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2CreateDrawableReq *req; + + XextSimpleCheckExtension(dpy, info, dri2ExtensionName); + + LockDisplay(dpy); + GetReq(DRI2CreateDrawable, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2CreateDrawable; + req->drawable = drawable; + UnlockDisplay(dpy); + SyncHandle(); +} + +void +DRI2DestroyDrawable(Display * dpy, XID drawable) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2DestroyDrawableReq *req; + + XextSimpleCheckExtension(dpy, info, dri2ExtensionName); + + XSync(dpy, False); + + LockDisplay(dpy); + GetReq(DRI2DestroyDrawable, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2DestroyDrawable; + req->drawable = drawable; + UnlockDisplay(dpy); + SyncHandle(); +} + +DRI2Buffer * +DRI2GetBuffers(Display * dpy, XID drawable, + int *width, int *height, + unsigned int *attachments, int count, int *outCount) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2GetBuffersReply rep; + xDRI2GetBuffersReq *req; + DRI2Buffer *buffers; + xDRI2Buffer repBuffer; + CARD32 *p; + int i; + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReqExtra(DRI2GetBuffers, count * 4, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2GetBuffers; + req->drawable = drawable; + req->count = count; + p = (CARD32 *) & req[1]; + for (i = 0; i < count; i++) + p[i] = attachments[i]; + + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + *width = rep.width; + *height = rep.height; + *outCount = rep.count; + + buffers = Xmalloc(rep.count * sizeof buffers[0]); + if (buffers == NULL) { + _XEatData(dpy, rep.count * sizeof repBuffer); + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + for (i = 0; i < rep.count; i++) { + _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); + buffers[i].attachment = repBuffer.attachment; + buffers[i].name = repBuffer.name; + buffers[i].pitch = repBuffer.pitch; + buffers[i].cpp = repBuffer.cpp; + buffers[i].flags = repBuffer.flags; + } + + UnlockDisplay(dpy); + SyncHandle(); + + return buffers; +} + + +DRI2Buffer * +DRI2GetBuffersWithFormat(Display * dpy, XID drawable, + int *width, int *height, + unsigned int *attachments, int count, int *outCount) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2GetBuffersReply rep; + xDRI2GetBuffersReq *req; + DRI2Buffer *buffers; + xDRI2Buffer repBuffer; + CARD32 *p; + int i; + + XextCheckExtension(dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReqExtra(DRI2GetBuffers, count * (4 * 2), req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2GetBuffersWithFormat; + req->drawable = drawable; + req->count = count; + p = (CARD32 *) & req[1]; + for (i = 0; i < (count * 2); i++) + p[i] = attachments[i]; + + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + *width = rep.width; + *height = rep.height; + *outCount = rep.count; + + buffers = Xmalloc(rep.count * sizeof buffers[0]); + if (buffers == NULL) { + _XEatData(dpy, rep.count * sizeof repBuffer); + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + for (i = 0; i < rep.count; i++) { + _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); + buffers[i].attachment = repBuffer.attachment; + buffers[i].name = repBuffer.name; + buffers[i].pitch = repBuffer.pitch; + buffers[i].cpp = repBuffer.cpp; + buffers[i].flags = repBuffer.flags; + } + + UnlockDisplay(dpy); + SyncHandle(); + + return buffers; +} + + +void +DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region, + CARD32 dest, CARD32 src) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2CopyRegionReq *req; + + XextSimpleCheckExtension(dpy, info, dri2ExtensionName); + + LockDisplay(dpy); + GetReq(DRI2CopyRegion, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2CopyRegion; + req->drawable = drawable; + req->region = region; + req->dest = dest; + req->src = src; + + UnlockDisplay(dpy); + SyncHandle(); +} + +#ifdef X_DRI2SwapBuffers +static void +load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor, + CARD64 remainder) +{ + req->target_msc_hi = target >> 32; + req->target_msc_lo = target & 0xffffffff; + req->divisor_hi = divisor >> 32; + req->divisor_lo = divisor & 0xffffffff; + req->remainder_hi = remainder >> 32; + req->remainder_lo = remainder & 0xffffffff; +} + +static CARD64 +vals_to_card64(CARD32 lo, CARD32 hi) +{ + return (CARD64)hi << 32 | lo; +} + +void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc, + CARD64 divisor, CARD64 remainder, CARD64 *count) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2SwapBuffersReq *req; + xDRI2SwapBuffersReply rep; + + XextSimpleCheckExtension (dpy, info, dri2ExtensionName); + + LockDisplay(dpy); + GetReq(DRI2SwapBuffers, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2SwapBuffers; + req->drawable = drawable; + load_swap_req(req, target_msc, divisor, remainder); + + _XReply(dpy, (xReply *)&rep, 0, xFalse); + + *count = vals_to_card64(rep.swap_lo, rep.swap_hi); + + UnlockDisplay(dpy); + SyncHandle(); +} +#endif + +#ifdef X_DRI2GetMSC +Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc, + CARD64 *sbc) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2GetMSCReq *req; + xDRI2MSCReply rep; + + XextCheckExtension (dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReq(DRI2GetMSC, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2GetMSC; + req->drawable = drawable; + + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + *ust = vals_to_card64(rep.ust_lo, rep.ust_hi); + *msc = vals_to_card64(rep.msc_lo, rep.msc_hi); + *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi); + + UnlockDisplay(dpy); + SyncHandle(); + + return True; +} +#endif + +#ifdef X_DRI2WaitMSC +static void +load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor, + CARD64 remainder) +{ + req->target_msc_hi = target >> 32; + req->target_msc_lo = target & 0xffffffff; + req->divisor_hi = divisor >> 32; + req->divisor_lo = divisor & 0xffffffff; + req->remainder_hi = remainder >> 32; + req->remainder_lo = remainder & 0xffffffff; +} + +Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor, + CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2WaitMSCReq *req; + xDRI2MSCReply rep; + + XextCheckExtension (dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReq(DRI2WaitMSC, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2WaitMSC; + req->drawable = drawable; + load_msc_req(req, target_msc, divisor, remainder); + + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo; + *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo; + *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo; + + UnlockDisplay(dpy); + SyncHandle(); + + return True; +} +#endif + +#ifdef X_DRI2WaitSBC +static void +load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target) +{ + req->target_sbc_hi = target >> 32; + req->target_sbc_lo = target & 0xffffffff; +} + +Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust, + CARD64 *msc, CARD64 *sbc) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2WaitSBCReq *req; + xDRI2MSCReply rep; + + XextCheckExtension (dpy, info, dri2ExtensionName, False); + + LockDisplay(dpy); + GetReq(DRI2WaitSBC, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2WaitSBC; + req->drawable = drawable; + load_sbc_req(req, target_sbc); + + if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + return False; + } + + *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo; + *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo; + *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo; + + UnlockDisplay(dpy); + SyncHandle(); + + return True; +} +#endif + +#ifdef X_DRI2SwapInterval +void DRI2SwapInterval(Display *dpy, XID drawable, int interval) +{ + XExtDisplayInfo *info = DRI2FindDisplay(dpy); + xDRI2SwapIntervalReq *req; + + XextSimpleCheckExtension (dpy, info, dri2ExtensionName); + + LockDisplay(dpy); + GetReq(DRI2SwapInterval, req); + req->reqType = info->codes->major_opcode; + req->dri2ReqType = X_DRI2SwapInterval; + req->drawable = drawable; + req->interval = interval; + UnlockDisplay(dpy); + SyncHandle(); +} +#endif diff --git a/src/gallium/winsys/g3dvl/dri/dri2.h b/src/gallium/winsys/g3dvl/dri/dri2.h new file mode 100644 index 00000000000..114e9f8f965 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/dri2.h @@ -0,0 +1,106 @@ +/* + * Copyright © 2007,2008 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Soft- + * ware"), to deal in the Software without restriction, including without + * limitation the rights to use, copy, modify, merge, publish, distribute, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, provided that the above copyright + * notice(s) and this permission notice appear in all copies of the Soft- + * ware and that both the above copyright notice(s) and this permission + * notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- + * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY + * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN + * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- + * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- + * MANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization of + * the copyright holder. + * + * Authors: + * Kristian Høgsberg ([email protected]) + */ + +#ifndef _DRI2_H_ +#define _DRI2_H_ + +#include <X11/extensions/Xfixes.h> +#include <X11/extensions/dri2tokens.h> + +typedef struct +{ + unsigned int attachment; + unsigned int name; + unsigned int pitch; + unsigned int cpp; + unsigned int flags; +} DRI2Buffer; + +extern Bool +DRI2QueryExtension(Display * display, int *eventBase, int *errorBase); + +extern Bool +DRI2QueryVersion(Display * display, int *major, int *minor); + +extern Bool +DRI2Connect(Display * display, XID window, + char **driverName, char **deviceName); + +extern Bool +DRI2Authenticate(Display * display, XID window, drm_magic_t magic); + +extern void +DRI2CreateDrawable(Display * display, XID drawable); + +extern void +DRI2DestroyDrawable(Display * display, XID handle); + +extern DRI2Buffer* +DRI2GetBuffers(Display * dpy, XID drawable, + int *width, int *height, + unsigned int *attachments, int count, + int *outCount); + +/** + * \note + * This function is only supported with DRI2 version 1.1 or later. + */ +extern DRI2Buffer* +DRI2GetBuffersWithFormat(Display * dpy, XID drawable, + int *width, int *height, + unsigned int *attachments, + int count, int *outCount); + +extern void +DRI2CopyRegion(Display * dpy, XID drawable, + XserverRegion region, + CARD32 dest, CARD32 src); + +extern void +DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor, + CARD64 remainder, CARD64 *count); + +extern Bool +DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc, CARD64 *sbc); + +extern Bool +DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor, + CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc); + +extern Bool +DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust, + CARD64 *msc, CARD64 *sbc); + +extern void +DRI2SwapInterval(Display *dpy, XID drawable, int interval); + +#endif diff --git a/src/gallium/winsys/g3dvl/dri/dri_winsys.c b/src/gallium/winsys/g3dvl/dri/dri_winsys.c new file mode 100644 index 00000000000..276731ca588 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/dri_winsys.c @@ -0,0 +1,258 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <vl_winsys.h> +#include <driclient.h> +#include <pipe/p_screen.h> +#include <pipe/p_context.h> +#include <pipe/p_state.h> +#include <util/u_memory.h> +#include <util/u_hash.h> +#include <util/u_hash_table.h> +#include <util/u_inlines.h> +#include <state_tracker/drm_driver.h> +#include <X11/Xlibint.h> + +struct vl_dri_screen +{ + struct vl_screen base; + dri_screen_t *dri_screen; + struct util_hash_table *drawable_table; + Drawable last_seen_drawable; +}; + +struct vl_dri_context +{ + struct vl_context base; + int fd; +}; + +static struct pipe_surface* +vl_dri2_get_front(struct vl_context *vctx, Drawable drawable) +{ + int w, h; + unsigned int attachments[1] = {DRI_BUFFER_FRONT_LEFT}; + int count; + DRI2Buffer *dri2_front; + struct pipe_resource *front_tex; + struct pipe_surface *front_surf = NULL; + + assert(vctx); + + struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vctx->vscreen; + assert(vl_dri_scrn); + + dri2_front = DRI2GetBuffers(vl_dri_scrn->dri_screen->display, + drawable, &w, &h, attachments, 1, &count); + + assert(count == 1); + + if (dri2_front) { + struct winsys_handle dri2_front_handle = + { + .type = DRM_API_HANDLE_TYPE_SHARED, + .handle = dri2_front->name, + .stride = dri2_front->pitch + }; + struct pipe_resource template; + struct pipe_surface surf_template; + + memset(&template, 0, sizeof(struct pipe_resource)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_B8G8R8X8_UNORM; + template.last_level = 0; + template.width0 = w; + template.height0 = h; + template.depth0 = 1; + template.usage = PIPE_USAGE_STATIC; + template.bind = PIPE_BIND_RENDER_TARGET; + template.flags = 0; + + front_tex = vl_dri_scrn->base.pscreen->resource_from_handle(vl_dri_scrn->base.pscreen, &template, &dri2_front_handle); + if (front_tex) { + memset(&surf_template, 0, sizeof(surf_template)); + surf_template.format = front_tex->format; + surf_template.usage = PIPE_BIND_RENDER_TARGET; + front_surf = vctx->pipe->create_surface(vctx->pipe, front_tex, &surf_template); + } + pipe_resource_reference(&front_tex, NULL); + Xfree(dri2_front); + } + + return front_surf; +} + +static void +vl_dri2_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_resource *resource, + unsigned level, unsigned layer, + void *context_private) +{ + struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private; + struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen; + + assert(screen); + assert(resource); + assert(context_private); + + dri2CopyDrawable(vl_dri_scrn->dri_screen, vl_dri_scrn->last_seen_drawable, + DRI_BUFFER_FRONT_LEFT, DRI_BUFFER_FAKE_FRONT_LEFT); +} + +struct pipe_surface* +vl_drawable_surface_get(struct vl_context *vctx, Drawable drawable) +{ + assert(vctx); + + struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vctx->vscreen; + assert(vl_dri_scrn); + + if (vl_dri_scrn->last_seen_drawable != drawable) { + /* Hash table business depends on this equality */ + assert(None == NULL); + Drawable lookup_drawable = (Drawable)util_hash_table_get(vl_dri_scrn->drawable_table, (void*)drawable); + if (lookup_drawable == None) { + dri2CreateDrawable(vl_dri_scrn->dri_screen, drawable); + util_hash_table_set(vl_dri_scrn->drawable_table, (void*)drawable, (void*)drawable); + } + vl_dri_scrn->last_seen_drawable = drawable; + } + + return vl_dri2_get_front(vctx, drawable); +} + +void* +vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *displaytarget) +{ + return vctx; +} + +static unsigned drawable_hash(void *key) +{ + Drawable drawable = (Drawable)key; + assert(drawable != None); + return util_hash_crc32(&drawable, sizeof(Drawable)); +} + +static int drawable_cmp(void *key1, void *key2) +{ + Drawable d1 = (Drawable)key1; + Drawable d2 = (Drawable)key2; + assert(d1 != None); + assert(d2 != None); + return d1 != d2; +} + +struct vl_screen* +vl_screen_create(Display *display, int screen) +{ + struct vl_dri_screen *vl_dri_scrn; + + assert(display); + + vl_dri_scrn = CALLOC_STRUCT(vl_dri_screen); + if (!vl_dri_scrn) + goto no_struct; + + if (dri2CreateScreen(display, screen, &vl_dri_scrn->dri_screen)) + goto no_dri2screen; + + vl_dri_scrn->base.pscreen = driver_descriptor.create_screen(vl_dri_scrn->dri_screen->fd); + + if (!vl_dri_scrn->base.pscreen) + goto no_pscreen; + + vl_dri_scrn->drawable_table = util_hash_table_create(&drawable_hash, &drawable_cmp); + if (!vl_dri_scrn->drawable_table) + goto no_hash; + + vl_dri_scrn->last_seen_drawable = None; + vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer; + + return &vl_dri_scrn->base; + +no_hash: + vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen); +no_pscreen: + dri2DestroyScreen(vl_dri_scrn->dri_screen); +no_dri2screen: + FREE(vl_dri_scrn); +no_struct: + return NULL; +} + +void vl_screen_destroy(struct vl_screen *vscreen) +{ + struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen; + + assert(vscreen); + + util_hash_table_destroy(vl_dri_scrn->drawable_table); + vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen); + dri2DestroyScreen(vl_dri_scrn->dri_screen); + FREE(vl_dri_scrn); +} + +struct vl_context* +vl_video_create(struct vl_screen *vscreen) +{ + struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen; + struct vl_dri_context *vl_dri_ctx; + + vl_dri_ctx = CALLOC_STRUCT(vl_dri_context); + if (!vl_dri_ctx) + goto no_struct; + + vl_dri_ctx->base.pipe = vscreen->pscreen->context_create(vscreen->pscreen, vl_dri_ctx); + if (!vl_dri_ctx->base.pipe) { + debug_printf("[G3DVL] No video support found on %s/%s.\n", + vscreen->pscreen->get_vendor(vscreen->pscreen), + vscreen->pscreen->get_name(vscreen->pscreen)); + goto no_pipe; + } + + vl_dri_ctx->base.vscreen = vscreen; + vl_dri_ctx->fd = vl_dri_scrn->dri_screen->fd; + + return &vl_dri_ctx->base; + +no_pipe: + FREE(vl_dri_ctx); + +no_struct: + return NULL; +} + +void vl_video_destroy(struct vl_context *vctx) +{ + struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx; + + assert(vctx); + + vl_dri_ctx->base.pipe->destroy(vl_dri_ctx->base.pipe); + FREE(vl_dri_ctx); +} diff --git a/src/gallium/winsys/g3dvl/dri/driclient.c b/src/gallium/winsys/g3dvl/dri/driclient.c new file mode 100644 index 00000000000..90e48a7cb28 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/driclient.c @@ -0,0 +1,388 @@ +#include "driclient.h" +#include <assert.h> +#include <stdlib.h> +#include <fcntl.h> +#include <X11/Xlibint.h> + +int driCreateScreen(Display *display, int screen, dri_screen_t **dri_screen, dri_framebuffer_t *dri_framebuf) +{ + int evbase, errbase; + char *driver_name; + int newly_opened; + drm_magic_t magic; + drmVersionPtr drm_version; + drm_handle_t sarea_handle; + char *bus_id; + dri_screen_t *dri_scrn; + + assert(display); + assert(dri_screen); + + if (!XF86DRIQueryExtension(display, &evbase, &errbase)) + return 1; + + dri_scrn = calloc(1, sizeof(dri_screen_t)); + + if (!dri_scrn) + return 1; + + if (!XF86DRIQueryVersion(display, &dri_scrn->dri.major, &dri_scrn->dri.minor, &dri_scrn->dri.patch)) + goto free_screen; + + dri_scrn->display = display; + dri_scrn->num = screen; + dri_scrn->draw_lock_id = 1; + + if (!XF86DRIOpenConnection(display, screen, &sarea_handle, &bus_id)) + goto free_screen; + + dri_scrn->fd = -1; + dri_scrn->fd = drmOpenOnce(NULL, bus_id, &newly_opened); + XFree(bus_id); + + if (dri_scrn->fd < 0) + goto close_connection; + + if (drmGetMagic(dri_scrn->fd, &magic)) + goto close_drm; + + drm_version = drmGetVersion(dri_scrn->fd); + + if (!drm_version) + goto close_drm; + + dri_scrn->drm.major = drm_version->version_major; + dri_scrn->drm.minor = drm_version->version_minor; + dri_scrn->drm.patch = drm_version->version_patchlevel; + drmFreeVersion(drm_version); + + if (!XF86DRIAuthConnection(display, screen, magic)) + goto close_drm; + + if (!XF86DRIGetClientDriverName + ( + display, + screen, + &dri_scrn->ddx.major, + &dri_scrn->ddx.minor, + &dri_scrn->ddx.patch, + &driver_name + )) + goto close_drm; + + if (drmMap(dri_scrn->fd, sarea_handle, SAREA_MAX, (drmAddress)&dri_scrn->sarea)) + goto close_drm; + + dri_scrn->drawable_hash = drmHashCreate(); + + if (!dri_scrn->drawable_hash) + goto unmap_sarea; + + if (dri_framebuf) + { + if (!XF86DRIGetDeviceInfo + ( + display, + screen, &dri_framebuf->drm_handle, + &dri_framebuf->base, + &dri_framebuf->size, + &dri_framebuf->stride, + &dri_framebuf->private_size, + &dri_framebuf->private + )) + goto destroy_hash; + } + + *dri_screen = dri_scrn; + + return 0; + +destroy_hash: + drmHashDestroy(dri_scrn->drawable_hash); +unmap_sarea: + drmUnmap(dri_scrn->sarea, SAREA_MAX); +close_drm: + drmCloseOnce(dri_scrn->fd); +close_connection: + XF86DRICloseConnection(display, screen); +free_screen: + free(dri_scrn); + + return 1; +} + +int driDestroyScreen(dri_screen_t *dri_screen) +{ + Drawable draw; + dri_drawable_t *dri_draw; + + assert(dri_screen); + + if (drmHashFirst(dri_screen->drawable_hash, &draw, (void**)&dri_draw)) + { + dri_draw->refcount = 1; + driDestroyDrawable(dri_draw); + + while (drmHashNext(dri_screen->drawable_hash, &draw, (void**)&dri_draw)) + { + dri_draw->refcount = 1; + driDestroyDrawable(dri_draw); + } + } + + drmHashDestroy(dri_screen->drawable_hash); + drmUnmap(dri_screen->sarea, SAREA_MAX); + drmCloseOnce(dri_screen->fd); + XF86DRICloseConnection(dri_screen->display, dri_screen->num); + free(dri_screen); + + return 0; +} + +int driCreateDrawable(dri_screen_t *dri_screen, Drawable drawable, dri_drawable_t **dri_drawable) +{ + int evbase, errbase; + dri_drawable_t *dri_draw; + + assert(dri_screen); + assert(dri_drawable); + + if (!XF86DRIQueryExtension(dri_screen->display, &evbase, &errbase)) + return 1; + + if (!drmHashLookup(dri_screen->drawable_hash, drawable, (void**)dri_drawable)) + { + /* Found */ + (*dri_drawable)->refcount++; + return 0; + } + + dri_draw = calloc(1, sizeof(dri_drawable_t)); + + if (!dri_draw) + return 1; + + if (!XF86DRICreateDrawable(dri_screen->display, 0, drawable, &dri_draw->drm_drawable)) + { + free(dri_draw); + return 1; + } + + dri_draw->x_drawable = drawable; + dri_draw->sarea_index = 0; + dri_draw->sarea_stamp = NULL; + dri_draw->last_sarea_stamp = 0; + dri_draw->dri_screen = dri_screen; + dri_draw->refcount = 1; + + if (drmHashInsert(dri_screen->drawable_hash, drawable, dri_draw)) + { + XF86DRIDestroyDrawable(dri_screen->display, dri_screen->num, drawable); + free(dri_draw); + return 1; + } + + if (!dri_draw->sarea_stamp || *dri_draw->sarea_stamp != dri_draw->last_sarea_stamp) + { + DRM_SPINLOCK(&dri_screen->sarea->drawable_lock, dri_screen->draw_lock_id); + + if (driUpdateDrawableInfo(dri_draw)) + { + XF86DRIDestroyDrawable(dri_screen->display, dri_screen->num, drawable); + free(dri_draw); + DRM_SPINUNLOCK(&dri_screen->sarea->drawable_lock, dri_screen->draw_lock_id); + return 1; + } + + DRM_SPINUNLOCK(&dri_screen->sarea->drawable_lock, dri_screen->draw_lock_id); + } + + *dri_drawable = dri_draw; + + return 0; +} + +int driUpdateDrawableInfo(dri_drawable_t *dri_drawable) +{ + assert(dri_drawable); + + if (dri_drawable->cliprects) + { + XFree(dri_drawable->cliprects); + dri_drawable->cliprects = NULL; + } + if (dri_drawable->back_cliprects) + { + XFree(dri_drawable->back_cliprects); + dri_drawable->back_cliprects = NULL; + } + + DRM_SPINUNLOCK(&dri_drawable->dri_screen->sarea->drawable_lock, dri_drawable->dri_screen->draw_lock_id); + + if (!XF86DRIGetDrawableInfo + ( + dri_drawable->dri_screen->display, + dri_drawable->dri_screen->num, + dri_drawable->x_drawable, + &dri_drawable->sarea_index, + &dri_drawable->last_sarea_stamp, + &dri_drawable->x, + &dri_drawable->y, + &dri_drawable->w, + &dri_drawable->h, + &dri_drawable->num_cliprects, + &dri_drawable->cliprects, + &dri_drawable->back_x, + &dri_drawable->back_y, + &dri_drawable->num_back_cliprects, + &dri_drawable->back_cliprects + )) + { + dri_drawable->sarea_stamp = &dri_drawable->last_sarea_stamp; + dri_drawable->num_cliprects = 0; + dri_drawable->cliprects = NULL; + dri_drawable->num_back_cliprects = 0; + dri_drawable->back_cliprects = 0; + + return 1; + } + else + dri_drawable->sarea_stamp = &dri_drawable->dri_screen->sarea->drawableTable[dri_drawable->sarea_index].stamp; + + DRM_SPINLOCK(&dri_drawable->dri_screen->sarea->drawable_lock, dri_drawable->dri_screen->draw_lock_id); + + return 0; +} + +int driDestroyDrawable(dri_drawable_t *dri_drawable) +{ + assert(dri_drawable); + + if (--dri_drawable->refcount == 0) + { + if (dri_drawable->cliprects) + XFree(dri_drawable->cliprects); + if (dri_drawable->back_cliprects) + XFree(dri_drawable->back_cliprects); + drmHashDelete(dri_drawable->dri_screen->drawable_hash, dri_drawable->x_drawable); + XF86DRIDestroyDrawable(dri_drawable->dri_screen->display, dri_drawable->dri_screen->num, dri_drawable->x_drawable); + free(dri_drawable); + } + + return 0; +} + +int driCreateContext(dri_screen_t *dri_screen, Visual *visual, dri_context_t **dri_context) +{ + int evbase, errbase; + dri_context_t *dri_ctx; + + assert(dri_screen); + assert(visual); + assert(dri_context); + + if (!XF86DRIQueryExtension(dri_screen->display, &evbase, &errbase)) + return 1; + + dri_ctx = calloc(1, sizeof(dri_context_t)); + + if (!dri_ctx) + return 1; + + if (!XF86DRICreateContext(dri_screen->display, dri_screen->num, visual, &dri_ctx->id, &dri_ctx->drm_context)) + { + free(dri_ctx); + return 1; + } + + dri_ctx->dri_screen = dri_screen; + *dri_context = dri_ctx; + + return 0; +} + +int driDestroyContext(dri_context_t *dri_context) +{ + assert(dri_context); + + XF86DRIDestroyContext(dri_context->dri_screen->display, dri_context->dri_screen->num, dri_context->id); + free(dri_context); + + return 0; +} + +int dri2CreateScreen(Display *display, int screen, dri_screen_t **dri_screen) +{ + dri_screen_t *dri_scrn; + drm_magic_t magic; + char *drvName; + char *devName; + + dri_scrn = calloc(1, sizeof(dri_screen_t)); + + if (!dri_scrn) + return 1; + + if (!DRI2Connect(display, XRootWindow(display, screen), &drvName, &devName)) + goto free_screen; + + dri_scrn->fd = open(devName, O_RDWR); + Xfree(drvName); + Xfree(devName); + if (dri_scrn->fd < 0) + goto free_screen; + + if (drmGetMagic(dri_scrn->fd, &magic)) + goto free_screen; + + if (!DRI2Authenticate(display, RootWindow(display, screen), magic)) + goto free_screen; + + dri_scrn->display = display; + dri_scrn->num = screen; + *dri_screen = dri_scrn; + + return 0; + +free_screen: + free(dri_scrn); + + return 1; +} + +int dri2DestroyScreen(dri_screen_t *dri_screen) +{ + /* Not much to do here apparently... */ + assert(dri_screen); + free(dri_screen); + return 0; +} + +int dri2CreateDrawable(dri_screen_t *dri_screen, XID drawable) +{ + assert(dri_screen); + DRI2CreateDrawable(dri_screen->display, drawable); + return 0; +} + +int dri2DestroyDrawable(dri_screen_t *dri_screen, XID drawable) +{ + assert(dri_screen); + DRI2DestroyDrawable(dri_screen->display, drawable); + return 0; +} + +int dri2CopyDrawable(dri_screen_t *dri_screen, XID drawable, int dest, int src) +{ + XserverRegion region; + + assert(dri_screen); + assert(dest >= DRI_BUFFER_FRONT_LEFT && dest <= DRI_BUFFER_DEPTH_STENCIL); + assert(src >= DRI_BUFFER_FRONT_LEFT && src <= DRI_BUFFER_DEPTH_STENCIL); + + region = XFixesCreateRegionFromWindow(dri_screen->display, drawable, WindowRegionBounding); + DRI2CopyRegion(dri_screen->display, drawable, region, dest, src); + XFixesDestroyRegion(dri_screen->display, region); + + return 0; +} diff --git a/src/gallium/winsys/g3dvl/dri/driclient.h b/src/gallium/winsys/g3dvl/dri/driclient.h new file mode 100644 index 00000000000..4e4fd362395 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/driclient.h @@ -0,0 +1,117 @@ +#ifndef driclient_h +#define driclient_h + +#include <stdint.h> +#include <X11/Xmd.h> +#include <X11/Xlib.h> +#include <drm_sarea.h> +//#include <X11/extensions/dri2proto.h> +#include "xf86dri.h" +#include "dri2.h" + +/* TODO: Bring in DRI XML options */ + +typedef struct dri_version +{ + int major; + int minor; + int patch; +} dri_version_t; + +typedef struct dri_screen +{ + Display *display; + unsigned int num; + dri_version_t ddx, dri, drm; + int draw_lock_id; + int fd; + drm_sarea_t *sarea; + void *drawable_hash; + void *private; +} dri_screen_t; + +struct dri_context; + +typedef struct dri_drawable +{ + drm_drawable_t drm_drawable; + Drawable x_drawable; + unsigned int sarea_index; + unsigned int *sarea_stamp; + unsigned int last_sarea_stamp; + int x, y, w, h; + int back_x, back_y; + int num_cliprects, num_back_cliprects; + drm_clip_rect_t *cliprects, *back_cliprects; + dri_screen_t *dri_screen; + unsigned int refcount; + void *private; +} dri_drawable_t; + +typedef struct dri_context +{ + XID id; + drm_context_t drm_context; + dri_screen_t *dri_screen; + void *private; +} dri_context_t; + +typedef struct dri_framebuffer +{ + drm_handle_t drm_handle; + int base, size, stride; + int private_size; + void *private; +} dri_framebuffer_t; + +int driCreateScreen(Display *display, int screen, dri_screen_t **dri_screen, dri_framebuffer_t *dri_framebuf); +int driDestroyScreen(dri_screen_t *dri_screen); +int driCreateDrawable(dri_screen_t *dri_screen, Drawable drawable, dri_drawable_t **dri_drawable); +int driUpdateDrawableInfo(dri_drawable_t *dri_drawable); +int driDestroyDrawable(dri_drawable_t *dri_drawable); +int driCreateContext(dri_screen_t *dri_screen, Visual *visual, dri_context_t **dri_context); +int driDestroyContext(dri_context_t *dri_context); + +#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(dri_drawable) \ +do \ +{ \ + if (*(dri_drawable->sarea_stamp) != dri_drawable->last_sarea_stamp) \ + driUpdateDrawableInfo(dri_drawable); \ +} while (0) + +#define DRI_VALIDATE_DRAWABLE_INFO(dri_screen, dri_drawable) \ +do \ +{ \ + while (*(dri_drawable->sarea_stamp) != dri_drawable->last_sarea_stamp) \ + { \ + register unsigned int hwContext = dri_screen->sarea->lock.lock & \ + ~(DRM_LOCK_HELD | DRM_LOCK_CONT); \ + DRM_UNLOCK(dri_screen->fd, &dri_screen->sarea->lock, hwContext); \ + \ + DRM_SPINLOCK(&dri_screen->sarea->drawable_lock, dri_screen->draw_lock_id); \ + DRI_VALIDATE_DRAWABLE_INFO_ONCE(dri_drawable); \ + DRM_SPINUNLOCK(&dri_screen->sarea->drawable_lock, dri_screen->draw_lock_id); \ + \ + DRM_LIGHT_LOCK(dri_screen->fd, &dri_screen->sarea->lock, hwContext); \ + } \ +} while (0) + +int dri2CreateScreen(Display *display, int screen, dri_screen_t **dri_screen); +int dri2DestroyScreen(dri_screen_t *dri_screen); +int dri2CreateDrawable(dri_screen_t *dri_screen, XID drawable); +int dri2DestroyDrawable(dri_screen_t *dri_screen, XID drawable); +int dri2CopyDrawable(dri_screen_t *dri_screen, XID drawable, int dest, int src); + +#define DRI_BUFFER_FRONT_LEFT 0 +#define DRI_BUFFER_BACK_LEFT 1 +#define DRI_BUFFER_FRONT_RIGHT 2 +#define DRI_BUFFER_BACK_RIGHT 3 +#define DRI_BUFFER_DEPTH 4 +#define DRI_BUFFER_STENCIL 5 +#define DRI_BUFFER_ACCUM 6 +#define DRI_BUFFER_FAKE_FRONT_LEFT 7 +#define DRI_BUFFER_FAKE_FRONT_RIGHT 8 +#define DRI_BUFFER_DEPTH_STENCIL 9 /**< Only available with DRI2 1.1 */ + +#endif + diff --git a/src/gallium/winsys/g3dvl/dri/xf86dri.h b/src/gallium/winsys/g3dvl/dri/xf86dri.h new file mode 100644 index 00000000000..baf80a7a9dd --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/xf86dri.h @@ -0,0 +1,119 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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 PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/** + * \file xf86dri.h + * Protocol numbers and function prototypes for DRI X protocol. + * + * \author Kevin E. Martin <[email protected]> + * \author Jens Owen <[email protected]> + * \author Rickard E. (Rik) Faith <[email protected]> + */ + +#ifndef _XF86DRI_H_ +#define _XF86DRI_H_ + +#include <X11/Xfuncproto.h> +#include <xf86drm.h> + +#define X_XF86DRIQueryVersion 0 +#define X_XF86DRIQueryDirectRenderingCapable 1 +#define X_XF86DRIOpenConnection 2 +#define X_XF86DRICloseConnection 3 +#define X_XF86DRIGetClientDriverName 4 +#define X_XF86DRICreateContext 5 +#define X_XF86DRIDestroyContext 6 +#define X_XF86DRICreateDrawable 7 +#define X_XF86DRIDestroyDrawable 8 +#define X_XF86DRIGetDrawableInfo 9 +#define X_XF86DRIGetDeviceInfo 10 +#define X_XF86DRIAuthConnection 11 +#define X_XF86DRIOpenFullScreen 12 /* Deprecated */ +#define X_XF86DRICloseFullScreen 13 /* Deprecated */ + +#define XF86DRINumberEvents 0 + +#define XF86DRIClientNotLocal 0 +#define XF86DRIOperationNotSupported 1 +#define XF86DRINumberErrors (XF86DRIOperationNotSupported + 1) + +#ifndef _XF86DRI_SERVER_ + +_XFUNCPROTOBEGIN + +Bool XF86DRIQueryExtension( Display *dpy, int *event_base, int *error_base ); + +Bool XF86DRIQueryVersion( Display *dpy, int *majorVersion, int *minorVersion, + int *patchVersion ); + +Bool XF86DRIQueryDirectRenderingCapable( Display *dpy, int screen, + Bool *isCapable ); + +Bool XF86DRIOpenConnection( Display *dpy, int screen, drm_handle_t *hSAREA, + char **busIDString ); + +Bool XF86DRIAuthConnection( Display *dpy, int screen, drm_magic_t magic ); + +Bool XF86DRICloseConnection( Display *dpy, int screen ); + +Bool XF86DRIGetClientDriverName( Display *dpy, int screen, + int *ddxDriverMajorVersion, int *ddxDriverMinorVersion, + int *ddxDriverPatchVersion, char **clientDriverName ); + +Bool XF86DRICreateContext( Display *dpy, int screen, Visual *visual, + XID *ptr_to_returned_context_id, drm_context_t *hHWContext ); + +Bool XF86DRICreateContextWithConfig( Display *dpy, int screen, int configID, + XID *ptr_to_returned_context_id, drm_context_t *hHWContext ); + +Bool XF86DRIDestroyContext( Display *dpy, int screen, + XID context_id ); + +Bool XF86DRICreateDrawable( Display *dpy, int screen, + Drawable drawable, drm_drawable_t *hHWDrawable ); + +Bool XF86DRIDestroyDrawable( Display *dpy, int screen, + Drawable drawable); + +Bool XF86DRIGetDrawableInfo( Display *dpy, int screen, Drawable drawable, + unsigned int *index, unsigned int *stamp, + int *X, int *Y, int *W, int *H, + int *numClipRects, drm_clip_rect_t ** pClipRects, + int *backX, int *backY, + int *numBackClipRects, drm_clip_rect_t **pBackClipRects ); + +Bool XF86DRIGetDeviceInfo( Display *dpy, int screen, + drm_handle_t *hFrameBuffer, int *fbOrigin, int *fbSize, + int *fbStride, int *devPrivateSize, void **pDevPrivate ); + +_XFUNCPROTOEND + +#endif /* _XF86DRI_SERVER_ */ + +#endif /* _XF86DRI_H_ */ + diff --git a/src/gallium/winsys/g3dvl/dri/xf86dristr.h b/src/gallium/winsys/g3dvl/dri/xf86dristr.h new file mode 100644 index 00000000000..b834bd1a1a0 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/xf86dristr.h @@ -0,0 +1,342 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, 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 PRECISION INSIGHT AND/OR ITS SUPPLIERS 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: + * Kevin E. Martin <[email protected]> + * Jens Owen <[email protected]> + * Rickard E. (Rik) Fiath <[email protected]> + * + */ + +#ifndef _XF86DRISTR_H_ +#define _XF86DRISTR_H_ + +#include "xf86dri.h" + +#define XF86DRINAME "XFree86-DRI" + +/* The DRI version number. This was originally set to be the same of the + * XFree86 version number. However, this version is really indepedent of + * the XFree86 version. + * + * Version History: + * 4.0.0: Original + * 4.0.1: Patch to bump clipstamp when windows are destroyed, 28 May 02 + * 4.1.0: Add transition from single to multi in DRMInfo rec, 24 Jun 02 + */ +#define XF86DRI_MAJOR_VERSION 4 +#define XF86DRI_MINOR_VERSION 1 +#define XF86DRI_PATCH_VERSION 0 + +typedef struct _XF86DRIQueryVersion { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIQueryVersion */ + CARD16 length B16; +} xXF86DRIQueryVersionReq; +#define sz_xXF86DRIQueryVersionReq 4 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD16 majorVersion B16; /* major version of DRI protocol */ + CARD16 minorVersion B16; /* minor version of DRI protocol */ + CARD32 patchVersion B32; /* patch version of DRI protocol */ + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIQueryVersionReply; +#define sz_xXF86DRIQueryVersionReply 32 + +typedef struct _XF86DRIQueryDirectRenderingCapable { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* X_DRIQueryDirectRenderingCapable */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIQueryDirectRenderingCapableReq; +#define sz_xXF86DRIQueryDirectRenderingCapableReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + BOOL isCapable; + BOOL pad2; + BOOL pad3; + BOOL pad4; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; + CARD32 pad9 B32; +} xXF86DRIQueryDirectRenderingCapableReply; +#define sz_xXF86DRIQueryDirectRenderingCapableReply 32 + +typedef struct _XF86DRIOpenConnection { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIOpenConnectionReq; +#define sz_xXF86DRIOpenConnectionReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hSAREALow B32; + CARD32 hSAREAHigh B32; + CARD32 busIdStringLength B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xXF86DRIOpenConnectionReply; +#define sz_xXF86DRIOpenConnectionReply 32 + +typedef struct _XF86DRIAuthConnection { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; + CARD32 magic B32; +} xXF86DRIAuthConnectionReq; +#define sz_xXF86DRIAuthConnectionReq 12 + +typedef struct { + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 authenticated B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIAuthConnectionReply; +#define zx_xXF86DRIAuthConnectionReply 32 + +typedef struct _XF86DRICloseConnection { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRICloseConnectionReq; +#define sz_xXF86DRICloseConnectionReq 8 + +typedef struct _XF86DRIGetClientDriverName { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetClientDriverName */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetClientDriverNameReq; +#define sz_xXF86DRIGetClientDriverNameReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 ddxDriverMajorVersion B32; + CARD32 ddxDriverMinorVersion B32; + CARD32 ddxDriverPatchVersion B32; + CARD32 clientDriverNameLength B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIGetClientDriverNameReply; +#define sz_xXF86DRIGetClientDriverNameReply 32 + +typedef struct _XF86DRICreateContext { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 visual B32; + CARD32 context B32; +} xXF86DRICreateContextReq; +#define sz_xXF86DRICreateContextReq 16 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWContext B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateContextReply; +#define sz_xXF86DRICreateContextReply 32 + +typedef struct _XF86DRIDestroyContext { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 context B32; +} xXF86DRIDestroyContextReq; +#define sz_xXF86DRIDestroyContextReq 12 + +typedef struct _XF86DRICreateDrawable { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICreateDrawableReq; +#define sz_xXF86DRICreateDrawableReq 12 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWDrawable B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateDrawableReply; +#define sz_xXF86DRICreateDrawableReply 32 + +typedef struct _XF86DRIDestroyDrawable { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIDestroyDrawableReq; +#define sz_xXF86DRIDestroyDrawableReq 12 + +typedef struct _XF86DRIGetDrawableInfo { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDrawableInfo */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIGetDrawableInfoReq; +#define sz_xXF86DRIGetDrawableInfoReq 12 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 drawableTableIndex B32; + CARD32 drawableTableStamp B32; + INT16 drawableX B16; + INT16 drawableY B16; + INT16 drawableWidth B16; + INT16 drawableHeight B16; + CARD32 numClipRects B32; + INT16 backX B16; + INT16 backY B16; + CARD32 numBackClipRects B32; +} xXF86DRIGetDrawableInfoReply; + +#define sz_xXF86DRIGetDrawableInfoReply 36 + + +typedef struct _XF86DRIGetDeviceInfo { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDeviceInfo */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetDeviceInfoReq; +#define sz_xXF86DRIGetDeviceInfoReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hFrameBufferLow B32; + CARD32 hFrameBufferHigh B32; + CARD32 framebufferOrigin B32; + CARD32 framebufferSize B32; + CARD32 framebufferStride B32; + CARD32 devPrivateSize B32; +} xXF86DRIGetDeviceInfoReply; +#define sz_xXF86DRIGetDeviceInfoReply 32 + +typedef struct _XF86DRIOpenFullScreen { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIOpenFullScreenReq; +#define sz_xXF86DRIOpenFullScreenReq 12 + +typedef struct { + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 isFullScreen B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIOpenFullScreenReply; +#define sz_xXF86DRIOpenFullScreenReply 32 + +typedef struct _XF86DRICloseFullScreen { + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICloseFullScreenReq; +#define sz_xXF86DRICloseFullScreenReq 12 + +typedef struct { + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xXF86DRICloseFullScreenReply; +#define sz_xXF86DRICloseFullScreenReply 32 + + +#endif /* _XF86DRISTR_H_ */ diff --git a/src/gallium/winsys/g3dvl/vl_winsys.h b/src/gallium/winsys/g3dvl/vl_winsys.h new file mode 100644 index 00000000000..384a8ba5f17 --- /dev/null +++ b/src/gallium/winsys/g3dvl/vl_winsys.h @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#ifndef vl_winsys_h +#define vl_winsys_h + +#include <X11/Xlib.h> +#include <pipe/p_defines.h> +#include <pipe/p_format.h> + +struct pipe_screen; +struct pipe_surface; + +struct vl_screen +{ + struct pipe_screen *pscreen; +}; + +struct vl_context +{ + struct vl_screen *vscreen; + struct pipe_context *pipe; +}; + +struct vl_screen* +vl_screen_create(Display *display, int screen); + +void vl_screen_destroy(struct vl_screen *vscreen); + +struct vl_context* +vl_video_create(struct vl_screen *vscreen); + +void vl_video_destroy(struct vl_context *vctx); + +struct pipe_surface* +vl_drawable_surface_get(struct vl_context *vctx, Drawable drawable); + +void* +vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *drawable_surface); + +#endif diff --git a/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c b/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c new file mode 100644 index 00000000000..92f0bd6da90 --- /dev/null +++ b/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c @@ -0,0 +1,201 @@ +/************************************************************************** + * + * Copyright 2009 Younes Manton. + * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + +#include <X11/Xlibint.h> + +#include <pipe/p_state.h> + +#include <util/u_memory.h> +#include <util/u_format.h> +#include <util/u_inlines.h> + +#include <state_tracker/xlib_sw_winsys.h> +#include <softpipe/sp_public.h> + +#include <vl_winsys.h> + +struct vl_xsp_screen +{ + struct vl_screen base; + Display *display; + int screen; + Visual visual; + struct xlib_drawable xdraw; + struct pipe_surface *drawable_surface; +}; + +struct pipe_surface* +vl_drawable_surface_get(struct vl_context *vctx, Drawable drawable) +{ + struct vl_screen *vscreen = vctx->vscreen; + struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen; + Window root; + int x, y; + unsigned int width, height; + unsigned int border_width; + unsigned int depth; + struct pipe_resource templat, *drawable_tex; + struct pipe_surface surf_template, *drawable_surface = NULL; + + assert(vscreen); + assert(drawable != None); + + if (XGetGeometry(xsp_screen->display, drawable, &root, &x, &y, &width, &height, &border_width, &depth) == BadDrawable) + return NULL; + + xsp_screen->xdraw.drawable = drawable; + + if (xsp_screen->drawable_surface) { + if (xsp_screen->drawable_surface->width == width && + xsp_screen->drawable_surface->height == height) { + pipe_surface_reference(&drawable_surface, xsp_screen->drawable_surface); + return drawable_surface; + } + else + pipe_surface_reference(&xsp_screen->drawable_surface, NULL); + } + + memset(&templat, 0, sizeof(struct pipe_resource)); + templat.target = PIPE_TEXTURE_2D; + /* XXX: Need to figure out drawable's format */ + templat.format = PIPE_FORMAT_B8G8R8X8_UNORM; + templat.last_level = 0; + templat.width0 = width; + templat.height0 = height; + templat.depth0 = 1; + templat.usage = PIPE_USAGE_DEFAULT; + templat.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET; + templat.flags = 0; + + drawable_tex = vscreen->pscreen->resource_create(vscreen->pscreen, &templat); + if (!drawable_tex) + return NULL; + + memset(&surf_template, 0, sizeof(surf_template)); + surf_template.format = templat.format; + surf_template.usage = PIPE_BIND_RENDER_TARGET; + xsp_screen->drawable_surface = vctx->pipe->create_surface(vctx->pipe, drawable_tex, + &surf_template); + pipe_resource_reference(&drawable_tex, NULL); + + if (!xsp_screen->drawable_surface) + return NULL; + + pipe_surface_reference(&drawable_surface, xsp_screen->drawable_surface); + + xsp_screen->xdraw.depth = 24/*util_format_get_blocksizebits(templat.format) / + util_format_get_blockwidth(templat.format)*/; + + return drawable_surface; +} + +void* +vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *drawable_surface) +{ + struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vctx->vscreen; + + assert(vctx); + assert(drawable_surface); + assert(xsp_screen->drawable_surface == drawable_surface); + + return &xsp_screen->xdraw; +} + +struct vl_screen* +vl_screen_create(Display *display, int screen) +{ + struct vl_xsp_screen *xsp_screen; + struct sw_winsys *winsys; + + assert(display); + + xsp_screen = CALLOC_STRUCT(vl_xsp_screen); + if (!xsp_screen) + return NULL; + + winsys = xlib_create_sw_winsys(display); + if (!winsys) { + FREE(xsp_screen); + return NULL; + } + + xsp_screen->base.pscreen = softpipe_create_screen(winsys); + if (!xsp_screen->base.pscreen) { + winsys->destroy(winsys); + FREE(xsp_screen); + return NULL; + } + + xsp_screen->display = display; + xsp_screen->screen = screen; + xsp_screen->xdraw.visual = XDefaultVisual(display, screen); + + return &xsp_screen->base; +} + +void vl_screen_destroy(struct vl_screen *vscreen) +{ + struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen; + + assert(vscreen); + + pipe_surface_reference(&xsp_screen->drawable_surface, NULL); + vscreen->pscreen->destroy(vscreen->pscreen); + FREE(vscreen); +} + +struct vl_context* +vl_video_create(struct vl_screen *vscreen) +{ + struct pipe_context *pipe; + struct vl_context *vctx; + + assert(vscreen); + + pipe = vscreen->pscreen->context_create(vscreen->pscreen, NULL); + if (!pipe) + return NULL; + + vctx = CALLOC_STRUCT(vl_context); + if (!vctx) { + pipe->destroy(pipe); + return NULL; + } + + vctx->pipe = pipe; + vctx->vscreen = vscreen; + + return vctx; +} + +void vl_video_destroy(struct vl_context *vctx) +{ + assert(vctx); + + vctx->pipe->destroy(vctx->pipe); + FREE(vctx); +} diff --git a/src/gallium/winsys/i915/drm/SConscript b/src/gallium/winsys/i915/drm/SConscript index d8f5885b62c..15c97998fd8 100644 --- a/src/gallium/winsys/i915/drm/SConscript +++ b/src/gallium/winsys/i915/drm/SConscript @@ -2,7 +2,7 @@ Import('*') env = env.Clone() -env.ParseConfig('pkg-config --cflags libdrm') +env.PkgUseModules('DRM') i915drm_sources = [ 'i915_drm_batchbuffer.c', diff --git a/src/gallium/winsys/i915/drm/i915_drm_buffer.c b/src/gallium/winsys/i915/drm/i915_drm_buffer.c index 01dd4bf062f..ac66af333df 100644 --- a/src/gallium/winsys/i915/drm/i915_drm_buffer.c +++ b/src/gallium/winsys/i915/drm/i915_drm_buffer.c @@ -213,6 +213,17 @@ i915_drm_buffer_destroy(struct i915_winsys *iws, FREE(buffer); } +static boolean +i915_drm_buffer_is_busy(struct i915_winsys *iws, + struct i915_winsys_buffer *buffer) +{ + struct i915_drm_buffer* i915_buffer = i915_drm_buffer(buffer); + if (!i915_buffer) + return FALSE; + return drm_intel_bo_busy(i915_buffer->bo); +} + + void i915_drm_winsys_init_buffer_functions(struct i915_drm_winsys *idws) { @@ -224,4 +235,5 @@ i915_drm_winsys_init_buffer_functions(struct i915_drm_winsys *idws) idws->base.buffer_unmap = i915_drm_buffer_unmap; idws->base.buffer_write = i915_drm_buffer_write; idws->base.buffer_destroy = i915_drm_buffer_destroy; + idws->base.buffer_is_busy = i915_drm_buffer_is_busy; } diff --git a/src/gallium/winsys/i965/drm/SConscript b/src/gallium/winsys/i965/drm/SConscript index 785be449f70..a0f32ded402 100644 --- a/src/gallium/winsys/i965/drm/SConscript +++ b/src/gallium/winsys/i965/drm/SConscript @@ -2,7 +2,7 @@ Import('*') env = env.Clone() -env.ParseConfig('pkg-config --cflags libdrm') +env.PkgUseModules('DRM') i965drm_sources = [ 'i965_drm_buffer.c', diff --git a/src/gallium/winsys/r600/drm/Makefile b/src/gallium/winsys/r600/drm/Makefile index fb7b09b3a0d..1d0de31c65a 100644 --- a/src/gallium/winsys/r600/drm/Makefile +++ b/src/gallium/winsys/r600/drm/Makefile @@ -5,7 +5,6 @@ include $(TOP)/configs/current LIBNAME = r600winsys C_SOURCES = \ - bof.c \ evergreen_hw_context.c \ radeon_bo.c \ radeon_pciid.c \ diff --git a/src/gallium/winsys/r600/drm/SConscript b/src/gallium/winsys/r600/drm/SConscript index cc9a06a2393..efcedc6bff9 100644 --- a/src/gallium/winsys/r600/drm/SConscript +++ b/src/gallium/winsys/r600/drm/SConscript @@ -3,7 +3,6 @@ Import('*') env = env.Clone() r600_sources = [ - 'bof.c', 'evergreen_hw_context.c', 'radeon_bo.c', 'radeon_pciid.c', @@ -13,11 +12,7 @@ r600_sources = [ 'r600_bomgr.c', ] -try: - env.ParseConfig('pkg-config --cflags libdrm_radeon') -except OSError: - print 'warning: not building r600g' - Return() +env.PkgUseModules('DRM_RADEON') env.Append(CPPPATH = '#/src/gallium/drivers/r600') diff --git a/src/gallium/winsys/r600/drm/bof.c b/src/gallium/winsys/r600/drm/bof.c deleted file mode 100644 index 5c923ad38d6..00000000000 --- a/src/gallium/winsys/r600/drm/bof.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright 2010 Jerome Glisse <[email protected]> - * - * 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 - * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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: - * Jerome Glisse - */ -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include "bof.h" - -/* - * helpers - */ -static int bof_entry_grow(bof_t *bof) -{ - bof_t **array; - - if (bof->array_size < bof->nentry) - return 0; - array = realloc(bof->array, (bof->nentry + 16) * sizeof(void*)); - if (array == NULL) - return -ENOMEM; - bof->array = array; - bof->nentry += 16; - return 0; -} - -/* - * object - */ -bof_t *bof_object(void) -{ - bof_t *object; - - object = calloc(1, sizeof(bof_t)); - if (object == NULL) - return NULL; - object->refcount = 1; - object->type = BOF_TYPE_OBJECT; - object->size = 12; - return object; -} - -bof_t *bof_object_get(bof_t *object, const char *keyname) -{ - unsigned i; - - for (i = 0; i < object->array_size; i += 2) { - if (!strcmp(object->array[i]->value, keyname)) { - return object->array[i + 1]; - } - } - return NULL; -} - -int bof_object_set(bof_t *object, const char *keyname, bof_t *value) -{ - bof_t *key; - int r; - - if (object->type != BOF_TYPE_OBJECT) - return -EINVAL; - r = bof_entry_grow(object); - if (r) - return r; - key = bof_string(keyname); - if (key == NULL) - return -ENOMEM; - object->array[object->array_size++] = key; - object->array[object->array_size++] = value; - object->size += value->size; - object->size += key->size; - bof_incref(value); - return 0; -} - -/* - * array - */ -bof_t *bof_array(void) -{ - bof_t *array = bof_object(); - - if (array == NULL) - return NULL; - array->type = BOF_TYPE_ARRAY; - array->size = 12; - return array; -} - -int bof_array_append(bof_t *array, bof_t *value) -{ - int r; - if (array->type != BOF_TYPE_ARRAY) - return -EINVAL; - r = bof_entry_grow(array); - if (r) - return r; - array->array[array->array_size++] = value; - array->size += value->size; - bof_incref(value); - return 0; -} - -bof_t *bof_array_get(bof_t *bof, unsigned i) -{ - if (!bof_is_array(bof) || i >= bof->array_size) - return NULL; - return bof->array[i]; -} - -unsigned bof_array_size(bof_t *bof) -{ - if (!bof_is_array(bof)) - return 0; - return bof->array_size; -} - -/* - * blob - */ -bof_t *bof_blob(unsigned size, void *value) -{ - bof_t *blob = bof_object(); - - if (blob == NULL) - return NULL; - blob->type = BOF_TYPE_BLOB; - blob->value = calloc(1, size); - if (blob->value == NULL) { - bof_decref(blob); - return NULL; - } - blob->size = size; - memcpy(blob->value, value, size); - blob->size += 12; - return blob; -} - -unsigned bof_blob_size(bof_t *bof) -{ - if (!bof_is_blob(bof)) - return 0; - return bof->size - 12; -} - -void *bof_blob_value(bof_t *bof) -{ - if (!bof_is_blob(bof)) - return NULL; - return bof->value; -} - -/* - * string - */ -bof_t *bof_string(const char *value) -{ - bof_t *string = bof_object(); - - if (string == NULL) - return NULL; - string->type = BOF_TYPE_STRING; - string->size = strlen(value) + 1; - string->value = calloc(1, string->size); - if (string->value == NULL) { - bof_decref(string); - return NULL; - } - strcpy(string->value, value); - string->size += 12; - return string; -} - -/* - * int32 - */ -bof_t *bof_int32(int32_t value) -{ - bof_t *int32 = bof_object(); - - if (int32 == NULL) - return NULL; - int32->type = BOF_TYPE_INT32; - int32->size = 4; - int32->value = calloc(1, int32->size); - if (int32->value == NULL) { - bof_decref(int32); - return NULL; - } - memcpy(int32->value, &value, 4); - int32->size += 12; - return int32; -} - -int32_t bof_int32_value(bof_t *bof) -{ - return *((uint32_t*)bof->value); -} - -/* - * common - */ -static void bof_indent(int level) -{ - int i; - - for (i = 0; i < level; i++) - fprintf(stderr, " "); -} - -static void bof_print_bof(bof_t *bof, int level, int entry) -{ - bof_indent(level); - if (bof == NULL) { - fprintf(stderr, "--NULL-- for entry %d\n", entry); - return; - } - switch (bof->type) { - case BOF_TYPE_STRING: - fprintf(stderr, "%p string [%s %d]\n", bof, (char*)bof->value, bof->size); - break; - case BOF_TYPE_INT32: - fprintf(stderr, "%p int32 [%d %d]\n", bof, *(int*)bof->value, bof->size); - break; - case BOF_TYPE_BLOB: - fprintf(stderr, "%p blob [%d]\n", bof, bof->size); - break; - case BOF_TYPE_NULL: - fprintf(stderr, "%p null [%d]\n", bof, bof->size); - break; - case BOF_TYPE_OBJECT: - fprintf(stderr, "%p object [%d %d]\n", bof, bof->array_size / 2, bof->size); - break; - case BOF_TYPE_ARRAY: - fprintf(stderr, "%p array [%d %d]\n", bof, bof->array_size, bof->size); - break; - default: - fprintf(stderr, "%p unknown [%d]\n", bof, bof->type); - return; - } -} - -static void bof_print_rec(bof_t *bof, int level, int entry) -{ - unsigned i; - - bof_print_bof(bof, level, entry); - for (i = 0; i < bof->array_size; i++) { - bof_print_rec(bof->array[i], level + 2, i); - } -} - -void bof_print(bof_t *bof) -{ - bof_print_rec(bof, 0, 0); -} - -static int bof_read(bof_t *root, FILE *file, long end, int level) -{ - bof_t *bof = NULL; - int r; - - if (ftell(file) >= end) { - return 0; - } - r = bof_entry_grow(root); - if (r) - return r; - bof = bof_object(); - if (bof == NULL) - return -ENOMEM; - bof->offset = ftell(file); - r = fread(&bof->type, 4, 1, file); - if (r != 1) - goto out_err; - r = fread(&bof->size, 4, 1, file); - if (r != 1) - goto out_err; - r = fread(&bof->array_size, 4, 1, file); - if (r != 1) - goto out_err; - switch (bof->type) { - case BOF_TYPE_STRING: - case BOF_TYPE_INT32: - case BOF_TYPE_BLOB: - bof->value = calloc(1, bof->size - 12); - if (bof->value == NULL) { - goto out_err; - } - r = fread(bof->value, bof->size - 12, 1, file); - if (r != 1) { - fprintf(stderr, "error reading %d\n", bof->size - 12); - goto out_err; - } - break; - case BOF_TYPE_NULL: - return 0; - case BOF_TYPE_OBJECT: - case BOF_TYPE_ARRAY: - r = bof_read(bof, file, bof->offset + bof->size, level + 2); - if (r) - goto out_err; - break; - default: - fprintf(stderr, "invalid type %d\n", bof->type); - goto out_err; - } - root->array[root->centry++] = bof; - return bof_read(root, file, end, level); -out_err: - bof_decref(bof); - return -EINVAL; -} - -bof_t *bof_load_file(const char *filename) -{ - bof_t *root = bof_object(); - int r; - - if (root == NULL) { - fprintf(stderr, "%s failed to create root object\n", __func__); - return NULL; - } - root->file = fopen(filename, "r"); - if (root->file == NULL) - goto out_err; - r = fseek(root->file, 0L, SEEK_SET); - if (r) { - fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename); - goto out_err; - } - root->offset = ftell(root->file); - r = fread(&root->type, 4, 1, root->file); - if (r != 1) - goto out_err; - r = fread(&root->size, 4, 1, root->file); - if (r != 1) - goto out_err; - r = fread(&root->array_size, 4, 1, root->file); - if (r != 1) - goto out_err; - r = bof_read(root, root->file, root->offset + root->size, 2); - if (r) - goto out_err; - return root; -out_err: - bof_decref(root); - return NULL; -} - -void bof_incref(bof_t *bof) -{ - bof->refcount++; -} - -void bof_decref(bof_t *bof) -{ - unsigned i; - - if (bof == NULL) - return; - if (--bof->refcount > 0) - return; - for (i = 0; i < bof->array_size; i++) { - bof_decref(bof->array[i]); - bof->array[i] = NULL; - } - bof->array_size = 0; - if (bof->file) { - fclose(bof->file); - bof->file = NULL; - } - free(bof->array); - free(bof->value); - free(bof); -} - -static int bof_file_write(bof_t *bof, FILE *file) -{ - unsigned i; - int r; - - r = fwrite(&bof->type, 4, 1, file); - if (r != 1) - return -EINVAL; - r = fwrite(&bof->size, 4, 1, file); - if (r != 1) - return -EINVAL; - r = fwrite(&bof->array_size, 4, 1, file); - if (r != 1) - return -EINVAL; - switch (bof->type) { - case BOF_TYPE_NULL: - if (bof->size) - return -EINVAL; - break; - case BOF_TYPE_STRING: - case BOF_TYPE_INT32: - case BOF_TYPE_BLOB: - r = fwrite(bof->value, bof->size - 12, 1, file); - if (r != 1) - return -EINVAL; - break; - case BOF_TYPE_OBJECT: - case BOF_TYPE_ARRAY: - for (i = 0; i < bof->array_size; i++) { - r = bof_file_write(bof->array[i], file); - if (r) - return r; - } - break; - default: - return -EINVAL; - } - return 0; -} - -int bof_dump_file(bof_t *bof, const char *filename) -{ - unsigned i; - int r = 0; - - if (bof->file) { - fclose(bof->file); - bof->file = NULL; - } - bof->file = fopen(filename, "w"); - if (bof->file == NULL) { - fprintf(stderr, "%s failed to open file %s\n", __func__, filename); - r = -EINVAL; - goto out_err; - } - r = fseek(bof->file, 0L, SEEK_SET); - if (r) { - fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename); - goto out_err; - } - r = fwrite(&bof->type, 4, 1, bof->file); - if (r != 1) - goto out_err; - r = fwrite(&bof->size, 4, 1, bof->file); - if (r != 1) - goto out_err; - r = fwrite(&bof->array_size, 4, 1, bof->file); - if (r != 1) - goto out_err; - for (i = 0; i < bof->array_size; i++) { - r = bof_file_write(bof->array[i], bof->file); - if (r) - return r; - } -out_err: - fclose(bof->file); - bof->file = NULL; - return r; -} diff --git a/src/gallium/winsys/r600/drm/bof.h b/src/gallium/winsys/r600/drm/bof.h deleted file mode 100644 index 014affb74f1..00000000000 --- a/src/gallium/winsys/r600/drm/bof.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2010 Jerome Glisse <[email protected]> - * - * 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 - * on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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: - * Jerome Glisse - */ -#ifndef BOF_H -#define BOF_H - -#include <stdio.h> -#include <stdint.h> - -#define BOF_TYPE_STRING 0 -#define BOF_TYPE_NULL 1 -#define BOF_TYPE_BLOB 2 -#define BOF_TYPE_OBJECT 3 -#define BOF_TYPE_ARRAY 4 -#define BOF_TYPE_INT32 5 - -struct bof; - -typedef struct bof { - struct bof **array; - unsigned centry; - unsigned nentry; - unsigned refcount; - FILE *file; - uint32_t type; - uint32_t size; - uint32_t array_size; - void *value; - long offset; -} bof_t; - -extern int bof_file_flush(bof_t *root); -extern bof_t *bof_file_new(const char *filename); -extern int bof_object_dump(bof_t *object, const char *filename); - -/* object */ -extern bof_t *bof_object(void); -extern bof_t *bof_object_get(bof_t *object, const char *keyname); -extern int bof_object_set(bof_t *object, const char *keyname, bof_t *value); -/* array */ -extern bof_t *bof_array(void); -extern int bof_array_append(bof_t *array, bof_t *value); -extern bof_t *bof_array_get(bof_t *bof, unsigned i); -extern unsigned bof_array_size(bof_t *bof); -/* blob */ -extern bof_t *bof_blob(unsigned size, void *value); -extern unsigned bof_blob_size(bof_t *bof); -extern void *bof_blob_value(bof_t *bof); -/* string */ -extern bof_t *bof_string(const char *value); -/* int32 */ -extern bof_t *bof_int32(int32_t value); -extern int32_t bof_int32_value(bof_t *bof); -/* common functions */ -extern void bof_decref(bof_t *bof); -extern void bof_incref(bof_t *bof); -extern bof_t *bof_load_file(const char *filename); -extern int bof_dump_file(bof_t *bof, const char *filename); -extern void bof_print(bof_t *bof); - -static inline int bof_is_object(bof_t *bof){return (bof->type == BOF_TYPE_OBJECT);} -static inline int bof_is_blob(bof_t *bof){return (bof->type == BOF_TYPE_BLOB);} -static inline int bof_is_null(bof_t *bof){return (bof->type == BOF_TYPE_NULL);} -static inline int bof_is_int32(bof_t *bof){return (bof->type == BOF_TYPE_INT32);} -static inline int bof_is_array(bof_t *bof){return (bof->type == BOF_TYPE_ARRAY);} -static inline int bof_is_string(bof_t *bof){return (bof->type == BOF_TYPE_STRING);} - -#endif diff --git a/src/gallium/winsys/r600/drm/evergreen_hw_context.c b/src/gallium/winsys/r600/drm/evergreen_hw_context.c index 4d9dd505c41..7fe2050cd84 100644 --- a/src/gallium/winsys/r600/drm/evergreen_hw_context.c +++ b/src/gallium/winsys/r600/drm/evergreen_hw_context.c @@ -32,7 +32,6 @@ #include "r600.h" #include "evergreend.h" #include "radeon_drm.h" -#include "bof.h" #include "pipe/p_compiler.h" #include "util/u_inlines.h" #include "util/u_memory.h" @@ -55,6 +54,7 @@ static const struct r600_reg evergreen_config_reg_list[] = { {R_008C24_SQ_STACK_RESOURCE_MGMT_2, REG_FLAG_ENABLE_ALWAYS | REG_FLAG_FLUSH_CHANGE, 0, 0}, {R_008C28_SQ_STACK_RESOURCE_MGMT_3, REG_FLAG_ENABLE_ALWAYS | REG_FLAG_FLUSH_CHANGE, 0, 0}, {R_008D8C_SQ_DYN_GPR_CNTL_PS_FLUSH_REQ, REG_FLAG_ENABLE_ALWAYS | REG_FLAG_FLUSH_CHANGE, 0, 0}, + {R_008E2C_SQ_LDS_RESOURCE_MGMT, REG_FLAG_ENABLE_ALWAYS | REG_FLAG_FLUSH_CHANGE, 0, 0}, {R_009100_SPI_CONFIG_CNTL, REG_FLAG_ENABLE_ALWAYS | REG_FLAG_FLUSH_CHANGE, 0, 0}, {R_00913C_SPI_CONFIG_CNTL_1, REG_FLAG_ENABLE_ALWAYS | REG_FLAG_FLUSH_CHANGE, 0, 0}, }; @@ -1018,6 +1018,8 @@ int evergreen_context_init(struct r600_context *ctx, struct radeon *radeon) LIST_INITHEAD(&ctx->fenced_bo); + r600_get_backend_mask(ctx); + return 0; out_err: r600_context_fini(ctx); @@ -1202,7 +1204,7 @@ void evergreen_context_draw(struct r600_context *ctx, const struct r600_draw *dr pm4[3] = draw->vgt_num_instances; if (draw->indices) { pm4[4] = PKT3(PKT3_DRAW_INDEX, 3, ctx->predicate_drawing); - pm4[5] = draw->indices_bo_offset + r600_bo_offset(draw->indices); + pm4[5] = draw->indices_bo_offset; pm4[6] = 0; pm4[7] = draw->vgt_num_indices; pm4[8] = draw->vgt_draw_initiator; diff --git a/src/gallium/winsys/r600/drm/r600_bo.c b/src/gallium/winsys/r600/drm/r600_bo.c index 4098a6e1998..0f5b063cf5a 100644 --- a/src/gallium/winsys/r600/drm/r600_bo.c +++ b/src/gallium/winsys/r600/drm/r600_bo.c @@ -126,13 +126,13 @@ void *r600_bo_map(struct radeon *radeon, struct r600_bo *bo, unsigned usage, voi { struct pipe_context *pctx = ctx; - if (usage & PB_USAGE_UNSYNCHRONIZED) { + if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) { radeon_bo_map(radeon, bo->bo); return (uint8_t *) bo->bo->data + bo->offset; } if (p_atomic_read(&bo->bo->reference.count) > 1) { - if (usage & PB_USAGE_DONTBLOCK) { + if (usage & PIPE_TRANSFER_DONTBLOCK) { return NULL; } if (ctx) { @@ -140,7 +140,7 @@ void *r600_bo_map(struct radeon *radeon, struct r600_bo *bo, unsigned usage, voi } } - if (usage & PB_USAGE_DONTBLOCK) { + if (usage & PIPE_TRANSFER_DONTBLOCK) { uint32_t domain; if (radeon_bo_busy(radeon, bo->bo, &domain)) diff --git a/src/gallium/winsys/r600/drm/r600_drm.c b/src/gallium/winsys/r600/drm/r600_drm.c index 03fe385334c..8aa8c3df52a 100644 --- a/src/gallium/winsys/r600/drm/r600_drm.c +++ b/src/gallium/winsys/r600/drm/r600_drm.c @@ -50,6 +50,14 @@ #define RADEON_INFO_NUM_BACKENDS 0xa #endif +#ifndef RADEON_INFO_NUM_TILE_PIPES +#define RADEON_INFO_NUM_TILE_PIPES 0xb +#endif + +#ifndef RADEON_INFO_BACKEND_MAP +#define RADEON_INFO_BACKEND_MAP 0xd +#endif + enum radeon_family r600_get_family(struct radeon *r600) { return r600->family; @@ -75,6 +83,16 @@ unsigned r600_get_num_backends(struct radeon *radeon) return radeon->num_backends; } +unsigned r600_get_num_tile_pipes(struct radeon *radeon) +{ + return radeon->num_tile_pipes; +} + +unsigned r600_get_backend_map(struct radeon *radeon) +{ + return radeon->backend_map; +} + unsigned r600_get_minor_version(struct radeon *radeon) { return radeon->minor_version; @@ -156,7 +174,20 @@ static int eg_interpret_tiling(struct radeon *radeon, uint32_t tiling_config) return -EINVAL; } - radeon->tiling_info.num_banks = (tiling_config & 0xf0) >> 4; + switch ((tiling_config & 0xf0) >> 4) { + case 0: + radeon->tiling_info.num_banks = 4; + break; + case 1: + radeon->tiling_info.num_banks = 8; + break; + case 2: + radeon->tiling_info.num_banks = 16; + break; + default: + return -EINVAL; + + } switch ((tiling_config & 0xf00) >> 8) { case 0: @@ -173,7 +204,7 @@ static int eg_interpret_tiling(struct radeon *radeon, uint32_t tiling_config) static int radeon_drm_get_tiling(struct radeon *radeon) { - struct drm_radeon_info info; + struct drm_radeon_info info = {}; int r; uint32_t tiling_config = 0; @@ -195,8 +226,8 @@ static int radeon_drm_get_tiling(struct radeon *radeon) static int radeon_get_clock_crystal_freq(struct radeon *radeon) { - struct drm_radeon_info info; - uint32_t clock_crystal_freq; + struct drm_radeon_info info = {}; + uint32_t clock_crystal_freq = 0; int r; info.request = RADEON_INFO_CLOCK_CRYSTAL_FREQ; @@ -213,8 +244,8 @@ static int radeon_get_clock_crystal_freq(struct radeon *radeon) static int radeon_get_num_backends(struct radeon *radeon) { - struct drm_radeon_info info; - uint32_t num_backends; + struct drm_radeon_info info = {}; + uint32_t num_backends = 0; int r; info.request = RADEON_INFO_NUM_BACKENDS; @@ -228,6 +259,42 @@ static int radeon_get_num_backends(struct radeon *radeon) return 0; } +static int radeon_get_num_tile_pipes(struct radeon *radeon) +{ + struct drm_radeon_info info = {}; + uint32_t num_tile_pipes = 0; + int r; + + info.request = RADEON_INFO_NUM_TILE_PIPES; + info.value = (uintptr_t)&num_tile_pipes; + r = drmCommandWriteRead(radeon->fd, DRM_RADEON_INFO, &info, + sizeof(struct drm_radeon_info)); + if (r) + return r; + + radeon->num_tile_pipes = num_tile_pipes; + return 0; +} + +static int radeon_get_backend_map(struct radeon *radeon) +{ + struct drm_radeon_info info = {}; + uint32_t backend_map = 0; + int r; + + info.request = RADEON_INFO_BACKEND_MAP; + info.value = (uintptr_t)&backend_map; + r = drmCommandWriteRead(radeon->fd, DRM_RADEON_INFO, &info, + sizeof(struct drm_radeon_info)); + if (r) + return r; + + radeon->backend_map = backend_map; + radeon->backend_map_valid = TRUE; + + return 0; +} + static int radeon_init_fence(struct radeon *radeon) { @@ -236,7 +303,7 @@ static int radeon_init_fence(struct radeon *radeon) if (radeon->fence_bo == NULL) { return -ENOMEM; } - radeon->cfence = r600_bo_map(radeon, radeon->fence_bo, PB_USAGE_UNSYNCHRONIZED, NULL); + radeon->cfence = r600_bo_map(radeon, radeon->fence_bo, PIPE_TRANSFER_UNSYNCHRONIZED, NULL); *radeon->cfence = 0; return 0; } @@ -349,6 +416,11 @@ static struct radeon *radeon_new(int fd, unsigned device) if (radeon->minor_version >= 9) radeon_get_num_backends(radeon); + if (radeon->minor_version >= 11) { + radeon_get_num_tile_pipes(radeon); + radeon_get_backend_map(radeon); + } + radeon->bomgr = r600_bomgr_create(radeon, 1000000); if (radeon->bomgr == NULL) { return NULL; diff --git a/src/gallium/winsys/r600/drm/r600_hw_context.c b/src/gallium/winsys/r600/drm/r600_hw_context.c index f89f24c4d18..30af4e8066f 100644 --- a/src/gallium/winsys/r600/drm/r600_hw_context.c +++ b/src/gallium/winsys/r600/drm/r600_hw_context.c @@ -35,11 +35,95 @@ #include "xf86drm.h" #include "radeon_drm.h" #include "r600_priv.h" -#include "bof.h" #include "r600d.h" #define GROUP_FORCE_NEW_BLOCK 0 +/* Get backends mask */ +void r600_get_backend_mask(struct r600_context *ctx) +{ + struct r600_bo * buffer; + u32 * results; + unsigned num_backends = r600_get_num_backends(ctx->radeon); + unsigned i, mask = 0; + + /* if backend_map query is supported by the kernel */ + if (ctx->radeon->backend_map_valid) { + unsigned num_tile_pipes = r600_get_num_tile_pipes(ctx->radeon); + unsigned backend_map = r600_get_backend_map(ctx->radeon); + unsigned item_width, item_mask; + + if (ctx->radeon->chip_class >= EVERGREEN) { + item_width = 4; + item_mask = 0x7; + } else { + item_width = 2; + item_mask = 0x3; + } + + while(num_tile_pipes--) { + i = backend_map & item_mask; + mask |= (1<<i); + backend_map >>= item_width; + } + if (mask != 0) { + ctx->backend_mask = mask; + return; + } + } + + /* otherwise backup path for older kernels */ + + /* create buffer for event data */ + buffer = r600_bo(ctx->radeon, ctx->max_db*16, 1, 0, + PIPE_USAGE_STAGING); + if (!buffer) + goto err; + + /* initialize buffer with zeroes */ + results = r600_bo_map(ctx->radeon, buffer, PB_USAGE_CPU_WRITE, NULL); + if (results) { + memset(results, 0, ctx->max_db * 4 * 4); + r600_bo_unmap(ctx->radeon, buffer); + + /* emit EVENT_WRITE for ZPASS_DONE */ + ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2, 0); + ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1); + ctx->pm4[ctx->pm4_cdwords++] = 0; + ctx->pm4[ctx->pm4_cdwords++] = 0; + + ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0, 0); + ctx->pm4[ctx->pm4_cdwords++] = 0; + r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], buffer); + + /* execute */ + r600_context_flush(ctx); + + /* analyze results */ + results = r600_bo_map(ctx->radeon, buffer, PB_USAGE_CPU_READ, NULL); + if (results) { + for(i = 0; i < ctx->max_db; i++) { + /* at least highest bit will be set if backend is used */ + if (results[i*4 + 1]) + mask |= (1<<i); + } + r600_bo_unmap(ctx->radeon, buffer); + } + } + + r600_bo_reference(ctx->radeon, &buffer, NULL); + + if (mask != 0) { + ctx->backend_mask = mask; + return; + } + +err: + /* fallback to old method - set num_backends lower bits to 1 */ + ctx->backend_mask = (~((u32)0))>>(32-num_backends); + return; +} + static inline void r600_context_ps_partial_flush(struct r600_context *ctx) { if (!(ctx->flags & R600_CONTEXT_DRAW_PENDING)) @@ -62,6 +146,8 @@ void r600_init_cs(struct r600_context *ctx) ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_CONTEXT_CONTROL, 1, 0); ctx->pm4[ctx->pm4_cdwords++] = 0x80000000; ctx->pm4[ctx->pm4_cdwords++] = 0x80000000; + + ctx->init_dwords = ctx->pm4_cdwords; } static void INLINE r600_context_update_fenced_list(struct r600_context *ctx) @@ -897,6 +983,8 @@ int r600_context_init(struct r600_context *ctx, struct radeon *radeon) ctx->max_db = 4; + r600_get_backend_mask(ctx); + return 0; out_err: r600_context_fini(ctx); @@ -1467,7 +1555,7 @@ void r600_context_draw(struct r600_context *ctx, const struct r600_draw *draw) pm4[3] = draw->vgt_num_instances; if (draw->indices) { pm4[4] = PKT3(PKT3_DRAW_INDEX, 3, ctx->predicate_drawing); - pm4[5] = draw->indices_bo_offset + r600_bo_offset(draw->indices); + pm4[5] = draw->indices_bo_offset; pm4[6] = 0; pm4[7] = draw->vgt_num_indices; pm4[8] = draw->vgt_draw_initiator; @@ -1496,13 +1584,13 @@ void r600_context_flush(struct r600_context *ctx) int r; struct r600_block *enable_block = NULL; - if (!ctx->pm4_cdwords) + if (ctx->pm4_cdwords == ctx->init_dwords) return; /* suspend queries */ r600_context_queries_suspend(ctx); - if (ctx->radeon->family >= CHIP_CEDAR) + if (ctx->radeon->chip_class >= EVERGREEN) evergreen_context_flush_dest_caches(ctx); else r600_context_flush_dest_caches(ctx); @@ -1535,6 +1623,10 @@ void r600_context_flush(struct r600_context *ctx) chunk_array[1] = (uint64_t)(uintptr_t)&chunks[1]; r = drmCommandWriteRead(ctx->radeon->fd, DRM_RADEON_CS, &drmib, sizeof(struct drm_radeon_cs)); + if (r) { + fprintf(stderr, "radeon: The kernel rejected CS, " + "see dmesg for more information.\n"); + } #else *ctx->radeon->cfence = ctx->radeon->fence; #endif @@ -1563,7 +1655,7 @@ void r600_context_flush(struct r600_context *ctx) r600_init_cs(ctx); /* resume queries */ - r600_context_queries_resume(ctx); + r600_context_queries_resume(ctx, TRUE); /* set all valid group as dirty so they get reemited on * next draw command @@ -1609,122 +1701,44 @@ void r600_context_emit_fence(struct r600_context *ctx, struct r600_bo *fence_bo, r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], fence_bo); } -void r600_context_dump_bof(struct r600_context *ctx, const char *file) -{ - bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root; - unsigned i; - - root = device_id = bcs = blob = array = bo = size = handle = NULL; - root = bof_object(); - if (root == NULL) - goto out_err; - device_id = bof_int32(ctx->radeon->device); - if (device_id == NULL) - goto out_err; - if (bof_object_set(root, "device_id", device_id)) - goto out_err; - bof_decref(device_id); - device_id = NULL; - /* dump relocs */ - blob = bof_blob(ctx->creloc * 16, ctx->reloc); - if (blob == NULL) - goto out_err; - if (bof_object_set(root, "reloc", blob)) - goto out_err; - bof_decref(blob); - blob = NULL; - /* dump cs */ - blob = bof_blob(ctx->pm4_cdwords * 4, ctx->pm4); - if (blob == NULL) - goto out_err; - if (bof_object_set(root, "pm4", blob)) - goto out_err; - bof_decref(blob); - blob = NULL; - /* dump bo */ - array = bof_array(); - if (array == NULL) - goto out_err; - for (i = 0; i < ctx->creloc; i++) { - struct radeon_bo *rbo = ctx->bo[i]; - bo = bof_object(); - if (bo == NULL) - goto out_err; - size = bof_int32(rbo->size); - if (size == NULL) - goto out_err; - if (bof_object_set(bo, "size", size)) - goto out_err; - bof_decref(size); - size = NULL; - handle = bof_int32(rbo->handle); - if (handle == NULL) - goto out_err; - if (bof_object_set(bo, "handle", handle)) - goto out_err; - bof_decref(handle); - handle = NULL; - radeon_bo_map(ctx->radeon, rbo); - blob = bof_blob(rbo->size, rbo->data); - radeon_bo_unmap(ctx->radeon, rbo); - if (blob == NULL) - goto out_err; - if (bof_object_set(bo, "data", blob)) - goto out_err; - bof_decref(blob); - blob = NULL; - if (bof_array_append(array, bo)) - goto out_err; - bof_decref(bo); - bo = NULL; - } - if (bof_object_set(root, "bo", array)) - goto out_err; - bof_dump_file(root, file); -out_err: - bof_decref(blob); - bof_decref(array); - bof_decref(bo); - bof_decref(size); - bof_decref(handle); - bof_decref(device_id); - bof_decref(root); -} - static boolean r600_query_result(struct r600_context *ctx, struct r600_query *query, boolean wait) { + unsigned results_base = query->results_start; u64 start, end; - u32 *results; - int i; - int size; + u32 *results, *current_result; if (wait) - results = r600_bo_map(ctx->radeon, query->buffer, PB_USAGE_CPU_READ, NULL); + results = r600_bo_map(ctx->radeon, query->buffer, PIPE_TRANSFER_READ, NULL); else - results = r600_bo_map(ctx->radeon, query->buffer, PB_USAGE_DONTBLOCK | PB_USAGE_CPU_READ, NULL); + results = r600_bo_map(ctx->radeon, query->buffer, PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_READ, NULL); if (!results) return FALSE; - /* query->num_results contains how many dwords were used for the query */ - size = query->num_results; - for (i = 0; i < size; i += 4) { - start = (u64)results[i] | (u64)results[i + 1] << 32; - end = (u64)results[i + 2] | (u64)results[i + 3] << 32; + + /* count all results across all data blocks */ + while (results_base != query->results_end) { + current_result = (u32*)((char*)results + results_base); + + start = (u64)current_result[0] | (u64)current_result[1] << 32; + end = (u64)current_result[2] | (u64)current_result[3] << 32; if (((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL)) || query->type == PIPE_QUERY_TIME_ELAPSED) { query->result += end - start; } + + results_base += 4 * 4; + if (results_base >= query->buffer_size) + results_base = 0; } - r600_bo_unmap(ctx->radeon, query->buffer); - query->num_results = 0; + query->results_start = query->results_end; + r600_bo_unmap(ctx->radeon, query->buffer); return TRUE; } void r600_query_begin(struct r600_context *ctx, struct r600_query *query) { - unsigned required_space; - int num_backends = r600_get_num_backends(ctx->radeon); + unsigned required_space, new_results_end; /* query request needs 6/8 dwords for begin + 6/8 dwords for end */ if (query->type == PIPE_QUERY_TIME_ELAPSED) @@ -1737,25 +1751,44 @@ void r600_query_begin(struct r600_context *ctx, struct r600_query *query) r600_context_flush(ctx); } - /* if query buffer is full force a flush */ - if (query->num_results*4 >= query->buffer_size - 16) { - r600_context_flush(ctx); + if (query->type == PIPE_QUERY_OCCLUSION_COUNTER) { + /* Count queries emitted without flushes, and flush if more than + * half of buffer used, to avoid overwriting results which may be + * still in use. */ + if (query->state & R600_QUERY_STATE_FLUSHED) { + query->queries_emitted = 1; + } else { + if (++query->queries_emitted > query->buffer_size / query->result_size / 2) + r600_context_flush(ctx); + } + } + + new_results_end = query->results_end + query->result_size; + if (new_results_end >= query->buffer_size) + new_results_end = 0; + + /* collect current results if query buffer is full */ + if (new_results_end == query->results_start) { + if (!(query->state & R600_QUERY_STATE_FLUSHED)) + r600_context_flush(ctx); r600_query_result(ctx, query, TRUE); } - if (query->type == PIPE_QUERY_OCCLUSION_COUNTER && - num_backends > 0) { - /* as per info on ZPASS the driver must set the unusued DB top bits */ + if (query->type == PIPE_QUERY_OCCLUSION_COUNTER) { u32 *results; int i; - results = r600_bo_map(ctx->radeon, query->buffer, PB_USAGE_DONTBLOCK | PB_USAGE_CPU_WRITE, NULL); + results = r600_bo_map(ctx->radeon, query->buffer, PIPE_TRANSFER_WRITE, NULL); if (results) { - memset(results + (query->num_results * 4), 0, ctx->max_db * 4 * 4); - - for (i = num_backends; i < ctx->max_db; i++) { - results[(i * 4)+1] = 0x80000000; - results[(i * 4)+3] = 0x80000000; + results = (u32*)((char*)results + query->results_end); + memset(results, 0, query->result_size); + + /* Set top bits for unused backends */ + for (i = 0; i < ctx->max_db; i++) { + if (!(ctx->backend_mask & (1<<i))) { + results[(i * 4)+1] = 0x80000000; + results[(i * 4)+3] = 0x80000000; + } } r600_bo_unmap(ctx->radeon, query->buffer); } @@ -1765,14 +1798,14 @@ void r600_query_begin(struct r600_context *ctx, struct r600_query *query) if (query->type == PIPE_QUERY_TIME_ELAPSED) { ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE_EOP, 4, 0); ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5); - ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + r600_bo_offset(query->buffer); + ctx->pm4[ctx->pm4_cdwords++] = query->results_end; ctx->pm4[ctx->pm4_cdwords++] = (3 << 29); ctx->pm4[ctx->pm4_cdwords++] = 0; ctx->pm4[ctx->pm4_cdwords++] = 0; } else { ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2, 0); ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1); - ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + r600_bo_offset(query->buffer); + ctx->pm4[ctx->pm4_cdwords++] = query->results_end; ctx->pm4[ctx->pm4_cdwords++] = 0; } ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0, 0); @@ -1786,49 +1819,75 @@ void r600_query_begin(struct r600_context *ctx, struct r600_query *query) void r600_query_end(struct r600_context *ctx, struct r600_query *query) { - /* emit begin query */ + /* emit end query */ if (query->type == PIPE_QUERY_TIME_ELAPSED) { ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE_EOP, 4, 0); ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5); - ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + 8 + r600_bo_offset(query->buffer); + ctx->pm4[ctx->pm4_cdwords++] = query->results_end + 8; ctx->pm4[ctx->pm4_cdwords++] = (3 << 29); ctx->pm4[ctx->pm4_cdwords++] = 0; ctx->pm4[ctx->pm4_cdwords++] = 0; } else { ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2, 0); ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1); - ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + 8 + r600_bo_offset(query->buffer); + ctx->pm4[ctx->pm4_cdwords++] = query->results_end + 8; ctx->pm4[ctx->pm4_cdwords++] = 0; } ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0, 0); ctx->pm4[ctx->pm4_cdwords++] = 0; r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], query->buffer); - query->num_results += 4 * (query->type == PIPE_QUERY_OCCLUSION_COUNTER ? ctx->max_db : 1); + query->results_end += query->result_size; + if (query->results_end >= query->buffer_size) + query->results_end = 0; + query->state ^= R600_QUERY_STATE_STARTED; query->state |= R600_QUERY_STATE_ENDED; + query->state &= ~R600_QUERY_STATE_FLUSHED; + ctx->num_query_running--; } void r600_query_predication(struct r600_context *ctx, struct r600_query *query, int operation, int flag_wait) { - ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_SET_PREDICATION, 1, 0); - if (operation == PREDICATION_OP_CLEAR) { + if (ctx->pm4_cdwords + 3 > ctx->pm4_ndwords) + r600_context_flush(ctx); + + ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_SET_PREDICATION, 1, 0); ctx->pm4[ctx->pm4_cdwords++] = 0; ctx->pm4[ctx->pm4_cdwords++] = PRED_OP(PREDICATION_OP_CLEAR); } else { - int results_base = query->num_results - (4 * ctx->max_db); + unsigned results_base = query->results_start; + unsigned count; + u32 op; - if (results_base < 0) - results_base = 0; + /* find count of the query data blocks */ + count = query->buffer_size + query->results_end - query->results_start; + if (count >= query->buffer_size) count-=query->buffer_size; + count /= query->result_size; - ctx->pm4[ctx->pm4_cdwords++] = results_base*4 + r600_bo_offset(query->buffer); - ctx->pm4[ctx->pm4_cdwords++] = PRED_OP(operation) | (flag_wait ? PREDICATION_HINT_WAIT : PREDICATION_HINT_NOWAIT_DRAW) | PREDICATION_DRAW_VISIBLE; - ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0, 0); - ctx->pm4[ctx->pm4_cdwords++] = 0; - r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], query->buffer); + if (ctx->pm4_cdwords + 5 * count > ctx->pm4_ndwords) + r600_context_flush(ctx); + + op = PRED_OP(operation) | PREDICATION_DRAW_VISIBLE | + (flag_wait ? PREDICATION_HINT_WAIT : PREDICATION_HINT_NOWAIT_DRAW); + + /* emit predicate packets for all data blocks */ + while (results_base != query->results_end) { + ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_SET_PREDICATION, 1, 0); + ctx->pm4[ctx->pm4_cdwords++] = results_base; + ctx->pm4[ctx->pm4_cdwords++] = op; + ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0, 0); + ctx->pm4[ctx->pm4_cdwords++] = 0; + r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], query->buffer); + results_base += query->result_size; + if (results_base >= query->buffer_size) + results_base = 0; + /* set CONTINUE bit for all packets except the first */ + op |= PREDICATION_CONTINUE; + } } } @@ -1846,6 +1905,14 @@ struct r600_query *r600_context_query_create(struct r600_context *ctx, unsigned query->type = query_type; query->buffer_size = 4096; + if (query_type == PIPE_QUERY_OCCLUSION_COUNTER) + query->result_size = 4 * 4 * ctx->max_db; + else + query->result_size = 4 * 4; + + /* adjust buffer size to simplify offsets wrapping math */ + query->buffer_size -= query->buffer_size % query->result_size; + /* As of GL4, query buffers are normally read by the CPU after * being written by the gpu, hence staging is probably a good * usage pattern. @@ -1875,7 +1942,7 @@ boolean r600_context_query_result(struct r600_context *ctx, { uint64_t *result = (uint64_t*)vresult; - if (query->num_results) { + if (!(query->state & R600_QUERY_STATE_FLUSHED)) { r600_context_flush(ctx); } if (!r600_query_result(ctx, query, wait)) @@ -1900,11 +1967,14 @@ void r600_context_queries_suspend(struct r600_context *ctx) } } -void r600_context_queries_resume(struct r600_context *ctx) +void r600_context_queries_resume(struct r600_context *ctx, boolean flushed) { struct r600_query *query; LIST_FOR_EACH_ENTRY(query, &ctx->query_list, list) { + if (flushed) + query->state |= R600_QUERY_STATE_FLUSHED; + if (query->state & R600_QUERY_STATE_SUSPENDED) { r600_query_begin(ctx, query); query->state ^= R600_QUERY_STATE_SUSPENDED; diff --git a/src/gallium/winsys/r600/drm/r600_priv.h b/src/gallium/winsys/r600/drm/r600_priv.h index 69f7251c043..75115fdaed7 100644 --- a/src/gallium/winsys/r600/drm/r600_priv.h +++ b/src/gallium/winsys/r600/drm/r600_priv.h @@ -55,6 +55,9 @@ struct radeon { struct r600_bo *fence_bo; unsigned clock_crystal_freq; unsigned num_backends; + unsigned num_tile_pipes; + unsigned backend_map; + boolean backend_map_valid; unsigned minor_version; /* List of buffer handles and its mutex. */ diff --git a/src/gallium/winsys/r600/drm/r600d.h b/src/gallium/winsys/r600/drm/r600d.h index 80424818044..4a19dcf8ddf 100644 --- a/src/gallium/winsys/r600/drm/r600d.h +++ b/src/gallium/winsys/r600/drm/r600d.h @@ -114,6 +114,8 @@ #define PRED_OP(x) ((x) << 16) +#define PREDICATION_CONTINUE (1 << 31) + #define PREDICATION_HINT_WAIT (0 << 12) #define PREDICATION_HINT_NOWAIT_DRAW (1 << 12) diff --git a/src/gallium/winsys/radeon/drm/SConscript b/src/gallium/winsys/radeon/drm/SConscript index 39a8c711b84..2edb1e94645 100644 --- a/src/gallium/winsys/radeon/drm/SConscript +++ b/src/gallium/winsys/radeon/drm/SConscript @@ -8,11 +8,7 @@ radeon_sources = [ 'radeon_drm_winsys.c', ] -try: - env.ParseConfig('pkg-config --cflags libdrm') -except: - print 'warning: not building Gallium Radeon' - Return() +env.PkgUseModules('DRM') radeonwinsys = env.ConvenienceLibrary( target ='radeonwinsys', diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c index b6f12727e81..2eb9d134407 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.c @@ -89,7 +89,7 @@ static struct radeon_bo *get_radeon_bo(struct pb_buffer *_buf) static void radeon_bo_wait(struct pb_buffer *_buf) { - struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf)); + struct radeon_bo *bo = get_radeon_bo(_buf); struct drm_radeon_gem_wait_idle args = {}; while (p_atomic_read(&bo->num_active_ioctls)) { @@ -105,7 +105,7 @@ static void radeon_bo_wait(struct pb_buffer *_buf) static boolean radeon_bo_is_busy(struct pb_buffer *_buf) { - struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf)); + struct radeon_bo *bo = get_radeon_bo(_buf); struct drm_radeon_gem_busy args = {}; boolean busy; @@ -395,16 +395,14 @@ static void *radeon_bo_map(struct pb_buffer *buf, struct radeon_winsys_cs *cs, enum pipe_transfer_usage usage) { - struct pb_buffer *_buf = pb_buffer(buf); - - return pb_map(_buf, get_pb_usage_from_transfer_flags(usage), cs); + return pb_map(buf, get_pb_usage_from_transfer_flags(usage), cs); } static void radeon_bo_get_tiling(struct pb_buffer *_buf, enum radeon_bo_layout *microtiled, enum radeon_bo_layout *macrotiled) { - struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf)); + struct radeon_bo *bo = get_radeon_bo(_buf); struct drm_radeon_gem_set_tiling args = {}; args.handle = bo->handle; @@ -429,7 +427,7 @@ static void radeon_bo_set_tiling(struct pb_buffer *_buf, enum radeon_bo_layout macrotiled, uint32_t pitch) { - struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf)); + struct radeon_bo *bo = get_radeon_bo(_buf); struct radeon_drm_cs *cs = radeon_drm_cs(rcs); struct drm_radeon_gem_set_tiling args = {}; @@ -464,12 +462,10 @@ static struct radeon_winsys_cs_handle *radeon_drm_get_cs_handle( struct pb_buffer *_buf) { /* return radeon_bo. */ - return (struct radeon_winsys_cs_handle*) - get_radeon_bo(pb_buffer(_buf)); + return (struct radeon_winsys_cs_handle*)get_radeon_bo(_buf); } -static unsigned get_pb_usage_from_create_flags(unsigned bind, unsigned usage, - enum radeon_bo_domain domain) +static unsigned get_pb_usage_from_create_flags(enum radeon_bo_domain domain) { unsigned res = 0; @@ -487,7 +483,6 @@ radeon_winsys_bo_create(struct radeon_winsys *rws, unsigned size, unsigned alignment, unsigned bind, - unsigned usage, enum radeon_bo_domain domain) { struct radeon_drm_winsys *ws = radeon_drm_winsys(rws); @@ -497,10 +492,11 @@ radeon_winsys_bo_create(struct radeon_winsys *rws, memset(&desc, 0, sizeof(desc)); desc.alignment = alignment; - desc.usage = get_pb_usage_from_create_flags(bind, usage, domain); + desc.usage = get_pb_usage_from_create_flags(domain); /* Assign a buffer manager. */ - if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER)) + if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER | + PIPE_BIND_CONSTANT_BUFFER)) provider = ws->cman; else provider = ws->kman; @@ -587,7 +583,7 @@ static boolean radeon_winsys_bo_get_handle(struct pb_buffer *buffer, struct winsys_handle *whandle) { struct drm_gem_flink flink = {}; - struct radeon_bo *bo = get_radeon_bo(pb_buffer(buffer)); + struct radeon_bo *bo = get_radeon_bo(buffer); if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) { if (!bo->flinked) { diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_bo.h b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h index b94881bc4ce..f4ea73a2210 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_bo.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_bo.h @@ -80,10 +80,4 @@ void radeon_bo_reference(struct radeon_bo **dst, struct radeon_bo *src) pb_reference((struct pb_buffer**)dst, (struct pb_buffer*)src); } -static INLINE struct pb_buffer * -pb_buffer(struct pb_buffer *buffer) -{ - return (struct pb_buffer *)buffer; -} - #endif diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c index 0139de1973a..f0f4a70be3f 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c @@ -308,8 +308,8 @@ static boolean radeon_drm_cs_validate(struct radeon_winsys_cs *rcs) { struct radeon_drm_cs *cs = radeon_drm_cs(rcs); - return cs->csc->used_gart < cs->ws->gart_size * 0.8 && - cs->csc->used_vram < cs->ws->vram_size * 0.8; + return cs->csc->used_gart < cs->ws->info.gart_size * 0.8 && + cs->csc->used_vram < cs->ws->info.vram_size * 0.8; } static void radeon_drm_cs_write_reloc(struct radeon_winsys_cs *rcs, diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.h b/src/gallium/winsys/radeon/drm/radeon_drm_cs.h index 339beedc6ab..ea2a820b30a 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_cs.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.h @@ -88,8 +88,9 @@ static INLINE boolean radeon_bo_is_referenced_by_cs(struct radeon_drm_cs *cs, struct radeon_bo *bo) { - return bo->num_cs_references == bo->rws->num_cs || - (bo->num_cs_references && radeon_get_reloc(cs->csc, bo) != -1); + int num_refs = bo->num_cs_references; + return num_refs == bo->rws->num_cs || + (num_refs && radeon_get_reloc(cs->csc, bo) != -1); } static INLINE boolean @@ -111,7 +112,7 @@ radeon_bo_is_referenced_by_cs_for_write(struct radeon_drm_cs *cs, static INLINE boolean radeon_bo_is_referenced_by_any_cs(struct radeon_bo *bo) { - return bo->num_cs_references; + return bo->num_cs_references != 0; } void radeon_drm_cs_sync_flush(struct radeon_drm_cs *cs); diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c index 0474b381ade..5983e86c570 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c @@ -103,17 +103,31 @@ static boolean radeon_set_fd_access(struct radeon_drm_cs *applier, return FALSE; } +static boolean radeon_get_drm_value(int fd, unsigned request, + const char *name, uint32_t *out) +{ + struct drm_radeon_info info = {0}; + int retval; + + info.value = (unsigned long)out; + info.request = request; + + retval = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)); + if (retval) { + fprintf(stderr, "%s: Failed to get %s, error number %d\n", + __func__, name, retval); + return FALSE; + } + return TRUE; +} + /* Helper function to do the ioctls needed for setup and init. */ -static void do_ioctls(struct radeon_drm_winsys *winsys) +static boolean do_winsys_init(struct radeon_drm_winsys *ws) { struct drm_radeon_gem_info gem_info = {0}; - struct drm_radeon_info info = {0}; - int target = 0; int retval; drmVersionPtr version; - info.value = (unsigned long)⌖ - /* We do things in a specific order here. * * DRM version first. We need to be sure we're running on a KMS chipset. @@ -123,71 +137,76 @@ static void do_ioctls(struct radeon_drm_winsys *winsys) * for all Radeons. If this fails, we probably got handed an FD for some * non-Radeon card. * + * The GEM info is actually bogus on the kernel side, as well as our side + * (see radeon_gem_info_ioctl in radeon_gem.c) but that's alright because + * we don't actually use the info for anything yet. + * * The GB and Z pipe requests should always succeed, but they might not * return sensical values for all chipsets, but that's alright because * the pipe drivers already know that. - * - * The GEM info is actually bogus on the kernel side, as well as our side - * (see radeon_gem_info_ioctl in radeon_gem.c) but that's alright because - * we don't actually use the info for anything yet. */ + */ - version = drmGetVersion(winsys->fd); + /* Get DRM version. */ + version = drmGetVersion(ws->fd); if (version->version_major != 2 || version->version_minor < 3) { fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " - "only compatible with 2.3.x (kernel 2.6.34) and later.\n", + "only compatible with 2.3.x (kernel 2.6.34) or later.\n", __FUNCTION__, version->version_major, version->version_minor, version->version_patchlevel); drmFreeVersion(version); - exit(1); + return FALSE; } - winsys->drm_major = version->version_major; - winsys->drm_minor = version->version_minor; - winsys->drm_patchlevel = version->version_patchlevel; + ws->info.drm_major = version->version_major; + ws->info.drm_minor = version->version_minor; + ws->info.drm_patchlevel = version->version_patchlevel; + drmFreeVersion(version); - info.request = RADEON_INFO_DEVICE_ID; - retval = drmCommandWriteRead(winsys->fd, DRM_RADEON_INFO, &info, sizeof(info)); - if (retval) { - fprintf(stderr, "%s: Failed to get PCI ID, " - "error number %d\n", __FUNCTION__, retval); - exit(1); - } - winsys->pci_id = target; + /* Get PCI ID. */ + if (!radeon_get_drm_value(ws->fd, RADEON_INFO_DEVICE_ID, "PCI ID", + &ws->info.pci_id)) + return FALSE; - info.request = RADEON_INFO_NUM_GB_PIPES; - retval = drmCommandWriteRead(winsys->fd, DRM_RADEON_INFO, &info, sizeof(info)); - if (retval) { - fprintf(stderr, "%s: Failed to get GB pipe count, " - "error number %d\n", __FUNCTION__, retval); - exit(1); - } - winsys->gb_pipes = target; + /* Check PCI ID. */ + switch (ws->info.pci_id) { +#define CHIPSET(pci_id, name, family) case pci_id: +#include "pci_ids/r300_pci_ids.h" +#undef CHIPSET + break; - info.request = RADEON_INFO_NUM_Z_PIPES; - retval = drmCommandWriteRead(winsys->fd, DRM_RADEON_INFO, &info, sizeof(info)); - if (retval) { - fprintf(stderr, "%s: Failed to get Z pipe count, " - "error number %d\n", __FUNCTION__, retval); - exit(1); + default: + fprintf(stderr, "radeon: Invalid PCI ID.\n"); + return FALSE; } - winsys->z_pipes = target; - retval = drmCommandWriteRead(winsys->fd, DRM_RADEON_GEM_INFO, + /* Get GEM info. */ + retval = drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_INFO, &gem_info, sizeof(gem_info)); if (retval) { fprintf(stderr, "%s: Failed to get MM info, error number %d\n", __FUNCTION__, retval); - exit(1); + return FALSE; } - winsys->gart_size = gem_info.gart_size; - winsys->vram_size = gem_info.vram_size; + ws->info.gart_size = gem_info.gart_size; + ws->info.vram_size = gem_info.vram_size; - drmFreeVersion(version); + ws->num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + + /* Generation-specific queries. */ + if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_GB_PIPES, + "GB pipe count", + &ws->info.r300_num_gb_pipes)) + return FALSE; - winsys->num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + if (!radeon_get_drm_value(ws->fd, RADEON_INFO_NUM_Z_PIPES, + "Z pipe count", + &ws->info.r300_num_z_pipes)) + return FALSE; + + return TRUE; } static void radeon_winsys_destroy(struct radeon_winsys *rws) @@ -202,34 +221,10 @@ static void radeon_winsys_destroy(struct radeon_winsys *rws) FREE(rws); } -static uint32_t radeon_get_value(struct radeon_winsys *rws, - enum radeon_value_id id) +static void radeon_query_info(struct radeon_winsys *rws, + struct radeon_info *info) { - struct radeon_drm_winsys *ws = (struct radeon_drm_winsys *)rws; - - switch(id) { - case RADEON_VID_PCI_ID: - return ws->pci_id; - case RADEON_VID_R300_GB_PIPES: - return ws->gb_pipes; - case RADEON_VID_R300_Z_PIPES: - return ws->z_pipes; - case RADEON_VID_GART_SIZE: - return ws->gart_size; - case RADEON_VID_VRAM_SIZE: - return ws->vram_size; - case RADEON_VID_DRM_MAJOR: - return ws->drm_major; - case RADEON_VID_DRM_MINOR: - return ws->drm_minor; - case RADEON_VID_DRM_PATCHLEVEL: - return ws->drm_patchlevel; - case RADEON_VID_DRM_2_6_0: - return ws->drm_major*100 + ws->drm_minor >= 206; - case RADEON_VID_DRM_2_8_0: - return ws->drm_major*100 + ws->drm_minor >= 208; - } - return 0; + *info = ((struct radeon_drm_winsys *)rws)->info; } static boolean radeon_cs_request_feature(struct radeon_winsys_cs *rcs, @@ -239,7 +234,7 @@ static boolean radeon_cs_request_feature(struct radeon_winsys_cs *rcs, struct radeon_drm_cs *cs = radeon_drm_cs(rcs); switch (fid) { - case RADEON_FID_HYPERZ_RAM_ACCESS: + case RADEON_FID_R300_HYPERZ_ACCESS: if (debug_get_bool_option("RADEON_HYPERZ", FALSE)) { return radeon_set_fd_access(cs, &cs->ws->hyperz_owner, &cs->ws->hyperz_owner_mutex, @@ -248,7 +243,7 @@ static boolean radeon_cs_request_feature(struct radeon_winsys_cs *rcs, return FALSE; } - case RADEON_FID_CMASK_RAM_ACCESS: + case RADEON_FID_R300_CMASK_ACCESS: if (debug_get_bool_option("RADEON_CMASK", FALSE)) { return radeon_set_fd_access(cs, &cs->ws->cmask_owner, &cs->ws->cmask_owner_mutex, @@ -268,16 +263,9 @@ struct radeon_winsys *radeon_drm_winsys_create(int fd) } ws->fd = fd; - do_ioctls(ws); - switch (ws->pci_id) { -#define CHIPSET(pci_id, name, family) case pci_id: -#include "pci_ids/r300_pci_ids.h" -#undef CHIPSET - break; - default: - goto fail; - } + if (!do_winsys_init(ws)) + goto fail; /* Create managers. */ ws->kman = radeon_bomgr_create(ws); @@ -289,7 +277,7 @@ struct radeon_winsys *radeon_drm_winsys_create(int fd) /* Set functions. */ ws->base.destroy = radeon_winsys_destroy; - ws->base.get_value = radeon_get_value; + ws->base.query_info = radeon_query_info; ws->base.cs_request_feature = radeon_cs_request_feature; radeon_bomgr_init_functions(ws); diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h index d5186bc4d17..347e1f1d11a 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h @@ -31,7 +31,6 @@ #define RADEON_DRM_WINSYS_H #include "radeon_winsys.h" - #include "os/os_thread.h" struct radeon_drm_winsys { @@ -40,20 +39,13 @@ struct radeon_drm_winsys { int fd; /* DRM file descriptor */ int num_cs; /* The number of command streams created. */ + struct radeon_info info; + struct pb_manager *kman; struct pb_manager *cman; - uint32_t pci_id; /* PCI ID */ - uint32_t gb_pipes; /* GB pipe count */ - uint32_t z_pipes; /* Z pipe count (rv530 only) */ - uint32_t gart_size; /* GART size. */ - uint32_t vram_size; /* VRAM size. */ uint32_t num_cpus; /* Number of CPUs. */ - unsigned drm_major; - unsigned drm_minor; - unsigned drm_patchlevel; - struct radeon_drm_cs *hyperz_owner; pipe_mutex hyperz_owner_mutex; struct radeon_drm_cs *cmask_owner; diff --git a/src/gallium/winsys/radeon/drm/radeon_winsys.h b/src/gallium/winsys/radeon/drm/radeon_winsys.h index 3a64e4abc35..f8a4d3abd43 100644 --- a/src/gallium/winsys/radeon/drm/radeon_winsys.h +++ b/src/gallium/winsys/radeon/drm/radeon_winsys.h @@ -26,6 +26,20 @@ /* The public winsys interface header for the radeon driver. */ +/* R300 features in DRM. + * + * 2.6.0: + * - Hyper-Z + * - GB_Z_PEQ_CONFIG on rv350->r4xx + * - R500 FG_ALPHA_VALUE + * + * 2.8.0: + * - R500 US_FORMAT regs + * - R500 ARGB2101010 colorbuffer + * - CMask and AA regs + * - R16F/RG16F + */ + #include "pipebuffer/pb_bufmgr.h" #include "pipe/p_defines.h" #include "pipe/p_state.h" @@ -55,43 +69,22 @@ struct radeon_winsys_cs { uint32_t *buf; /* The command buffer. */ }; -enum radeon_value_id { - RADEON_VID_PCI_ID, - RADEON_VID_R300_GB_PIPES, - RADEON_VID_R300_Z_PIPES, - RADEON_VID_GART_SIZE, - RADEON_VID_VRAM_SIZE, - RADEON_VID_DRM_MAJOR, - RADEON_VID_DRM_MINOR, - RADEON_VID_DRM_PATCHLEVEL, - - /* These should probably go away: */ - - /* R300 features: - * - Hyper-Z - * - GB_Z_PEQ_CONFIG on rv350->r4xx - * - R500 FG_ALPHA_VALUE - * - * R600 features: - * - TBD - */ - RADEON_VID_DRM_2_6_0, +struct radeon_info { + uint32_t pci_id; + uint32_t gart_size; + uint32_t vram_size; - /* R300 features: - * - R500 US_FORMAT regs - * - R500 ARGB2101010 colorbuffer - * - CMask and AA regs - * - R16F/RG16F - * - * R600 features: - * - TBD - */ - RADEON_VID_DRM_2_8_0, + uint32_t drm_major; /* version */ + uint32_t drm_minor; + uint32_t drm_patchlevel; + + uint32_t r300_num_gb_pipes; + uint32_t r300_num_z_pipes; }; enum radeon_feature_id { - RADEON_FID_HYPERZ_RAM_ACCESS, /* ZMask + HiZ */ - RADEON_FID_CMASK_RAM_ACCESS, + RADEON_FID_R300_HYPERZ_ACCESS, /* ZMask + HiZ */ + RADEON_FID_R300_CMASK_ACCESS, }; struct radeon_winsys { @@ -103,13 +96,13 @@ struct radeon_winsys { void (*destroy)(struct radeon_winsys *ws); /** - * Query a system value from a winsys. + * Query an info structure from winsys. * * \param ws The winsys this function is called from. - * \param vid One of the RADEON_VID_* enums. + * \param info Return structure */ - uint32_t (*get_value)(struct radeon_winsys *ws, - enum radeon_value_id vid); + void (*query_info)(struct radeon_winsys *ws, + struct radeon_info *info); /************************************************************************** * Buffer management. Buffer attributes are mostly fixed over its lifetime. @@ -126,7 +119,6 @@ struct radeon_winsys { * \param size The size to allocate. * \param alignment An alignment of the buffer in memory. * \param bind A bitmask of the PIPE_BIND_* flags. - * \param usage A bitmask of the PIPE_USAGE_* flags. * \param domain A bitmask of the RADEON_DOMAIN_* flags. * \return The created buffer object. */ @@ -134,7 +126,6 @@ struct radeon_winsys { unsigned size, unsigned alignment, unsigned bind, - unsigned usage, enum radeon_bo_domain domain); struct radeon_winsys_cs_handle *(*buffer_get_cs_handle)( @@ -306,7 +297,7 @@ struct radeon_winsys { */ void (*cs_set_flush)(struct radeon_winsys_cs *cs, void (*flush)(void *ctx, unsigned flags), - void *user); + void *ctx); /** * Return TRUE if a buffer is referenced by a command stream. @@ -321,7 +312,8 @@ struct radeon_winsys { * Request access to a feature for a command stream. * * \param cs A command stream. - * \param fid A winsys buffer. + * \param fid Feature ID, one of RADEON_FID_* + * \param enable Whether to enable or disable the feature. */ boolean (*cs_request_feature)(struct radeon_winsys_cs *cs, enum radeon_feature_id fid, diff --git a/src/gallium/winsys/svga/drm/SConscript b/src/gallium/winsys/svga/drm/SConscript index b049ea60aa8..3e25c8aa748 100644 --- a/src/gallium/winsys/svga/drm/SConscript +++ b/src/gallium/winsys/svga/drm/SConscript @@ -2,7 +2,7 @@ Import('*') env = env.Clone() -env.ParseConfig('pkg-config --cflags libdrm') +env.PkgUseModules('DRM') if env['gcc']: env.Append(CCFLAGS = ['-fvisibility=hidden']) diff --git a/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.c b/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.c index f4f4cd7969b..38d88f63aa2 100644 --- a/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.c +++ b/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.c @@ -54,10 +54,8 @@ struct fbdev_sw_winsys struct sw_winsys base; int fd; - enum pipe_format format; struct fb_fix_screeninfo finfo; - void *fbmem; unsigned rows; unsigned stride; }; @@ -77,22 +75,53 @@ fbdev_sw_winsys(struct sw_winsys *ws) static void fbdev_displaytarget_display(struct sw_winsys *ws, struct sw_displaytarget *dt, - void *context_private) + void *winsys_private) { struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws); - struct fbdev_sw_displaytarget *fbdt = fbdev_sw_displaytarget(dt); - unsigned rows, len, i; + struct fbdev_sw_displaytarget *src = fbdev_sw_displaytarget(dt); + const struct fbdev_sw_drawable *dst = + (const struct fbdev_sw_drawable *) winsys_private; + unsigned height, row_offset, row_len, i; + void *fbmem; + + /* FIXME format conversion */ + if (dst->format != src->format) { + assert(0); + return; + } - rows = MIN2(fbdt->height, fbdev->rows); - len = util_format_get_stride(fbdt->format, fbdt->width); - len = MIN2(len, fbdev->stride); + height = dst->height; + if (dst->y + dst->height > fbdev->rows) { + /* nothing to copy */ + if (dst->y >= fbdev->rows) + return; - for (i = 0; i < rows; i++) { - void *dst = fbdev->fbmem + fbdev->stride * i; - void *src = fbdt->data + fbdt->stride * i; + height = fbdev->rows - dst->y; + } + + row_offset = util_format_get_stride(dst->format, dst->x); + row_len = util_format_get_stride(dst->format, dst->width); + if (row_offset + row_len > fbdev->stride) { + /* nothing to copy */ + if (row_offset >= fbdev->stride) + return; - memcpy(dst, src, len); + row_len = fbdev->stride - row_offset; } + + fbmem = mmap(0, fbdev->finfo.smem_len, + PROT_WRITE, MAP_SHARED, fbdev->fd, 0); + if (fbmem == MAP_FAILED) + return; + + for (i = 0; i < height; i++) { + char *from = (char *) src->data + src->stride * i; + char *to = (char *) fbmem + fbdev->stride * (dst->y + i) + row_offset; + + memcpy(to, from, row_len); + } + + munmap(fbmem, fbdev->finfo.smem_len); } static void @@ -133,13 +162,9 @@ fbdev_displaytarget_create(struct sw_winsys *ws, unsigned alignment, unsigned *stride) { - struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws); struct fbdev_sw_displaytarget *fbdt; unsigned nblocksy, size, format_stride; - if (fbdev->format != format) - return NULL; - fbdt = CALLOC_STRUCT(fbdev_sw_displaytarget); if (!fbdt) return NULL; @@ -170,8 +195,7 @@ fbdev_is_displaytarget_format_supported(struct sw_winsys *ws, unsigned tex_usage, enum pipe_format format) { - struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws); - return (fbdev->format == format); + return TRUE; } static void @@ -179,12 +203,11 @@ fbdev_destroy(struct sw_winsys *ws) { struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws); - munmap(fbdev->fbmem, fbdev->finfo.smem_len); FREE(fbdev); } struct sw_winsys * -fbdev_create_sw_winsys(int fd, enum pipe_format format) +fbdev_create_sw_winsys(int fd) { struct fbdev_sw_winsys *fbdev; @@ -193,19 +216,11 @@ fbdev_create_sw_winsys(int fd, enum pipe_format format) return NULL; fbdev->fd = fd; - fbdev->format = format; if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo)) { FREE(fbdev); return NULL; } - fbdev->fbmem = mmap(0, fbdev->finfo.smem_len, - PROT_WRITE, MAP_SHARED, fbdev->fd, 0); - if (fbdev->fbmem == MAP_FAILED) { - FREE(fbdev); - return NULL; - } - fbdev->rows = fbdev->finfo.smem_len / fbdev->finfo.line_length; fbdev->stride = fbdev->finfo.line_length; diff --git a/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.h b/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.h index d958ab9db3e..59d8a8f5cfe 100644 --- a/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.h +++ b/src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.h @@ -32,7 +32,14 @@ struct sw_winsys; enum pipe_format; +/* for pipe_screen::flush_frontbuffer */ +struct fbdev_sw_drawable { + enum pipe_format format; + unsigned x, y; + unsigned width, height; +}; + struct sw_winsys * -fbdev_create_sw_winsys(int fd, enum pipe_format format); +fbdev_create_sw_winsys(int fd); #endif /* FBDEV_SW_WINSYS */ diff --git a/src/gallium/winsys/sw/wayland/wayland_sw_winsys.h b/src/gallium/winsys/sw/wayland/wayland_sw_winsys.h index 5e3cfd0bf23..bedd2408f05 100644 --- a/src/gallium/winsys/sw/wayland/wayland_sw_winsys.h +++ b/src/gallium/winsys/sw/wayland/wayland_sw_winsys.h @@ -27,6 +27,7 @@ #define WAYLAND_SW_WINSYS struct sw_winsys; +struct wl_display; struct winsys_handle { int fd; |