Skip to content
Browse files

Update master branch to next

  • Loading branch information...
1 parent 83e1597 commit 9852ce28826889e50c4d6786b942f51bccccac54 Dom Cobley committed
Showing with 6,896 additions and 953 deletions.
  1. +16 −4 CMakeLists.txt
  2. +4 −1 helpers/v3d/v3d_ver.h
  3. +7 −1 helpers/vc_image/metadata_fourcc.h
  4. +2 −1 helpers/vc_image/vc_image.h
  5. +7 −6 host_applications/linux/apps/gencmd/gencmd.c
  6. +2 −3 host_applications/linux/apps/hello_pi/hello_tiger/CMakeLists.txt
  7. +270 −63 host_applications/linux/apps/tvservice/tvservice.c
  8. +24 −16 host_support/include/vc_debug_sym.h
  9. +1 −0 interface/khronos/common/khrn_int_common.h
  10. +22 −3 interface/khronos/common/linux/khrn_client_rpc_linux.c
  11. +669 −360 interface/khronos/wf/wfc_client.c
  12. +17 −20 interface/khronos/wf/wfc_client_ipc.c
  13. +177 −26 interface/khronos/wf/wfc_client_server_api.c
  14. +616 −194 interface/khronos/wf/wfc_client_stream.c
  15. +9 −2 interface/khronos/wf/wfc_client_stream.h
  16. +83 −1 interface/khronos/wf/wfc_int.h
  17. +75 −10 interface/khronos/wf/wfc_ipc.h
  18. +78 −14 interface/khronos/wf/wfc_server_api.h
  19. +2 −0 interface/mmal/core/CMakeLists.txt
  20. +35 −5 interface/mmal/core/mmal_buffer.c
  21. +11 −0 interface/mmal/core/mmal_buffer_private.h
  22. +802 −0 interface/mmal/core/mmal_clock.c
  23. +205 −0 interface/mmal/core/mmal_clock_private.h
  24. +98 −14 interface/mmal/core/mmal_component.c
  25. +7 −0 interface/mmal/core/mmal_component_private.h
  26. +7 −1 interface/mmal/core/mmal_format.c
  27. +15 −0 interface/mmal/core/mmal_pool.c
  28. +196 −23 interface/mmal/core/mmal_port.c
  29. +584 −0 interface/mmal/core/mmal_port_clock.c
  30. +141 −0 interface/mmal/core/mmal_port_private.h
  31. +15 −4 interface/mmal/core/mmal_queue.c
  32. +49 −0 interface/mmal/mmal_buffer.h
  33. +98 −0 interface/mmal/mmal_clock.h
  34. +3 −0 interface/mmal/mmal_common.h
  35. +7 −1 interface/mmal/mmal_component.h
  36. +105 −0 interface/mmal/mmal_encodings.h
  37. +20 −3 interface/mmal/mmal_format.h
  38. +3 −3 interface/mmal/mmal_logging.h
  39. +57 −2 interface/mmal/mmal_parameters.h
  40. +64 −0 interface/mmal/mmal_parameters_audio.h
  41. +184 −1 interface/mmal/mmal_parameters_camera.h
  42. +77 −0 interface/mmal/mmal_parameters_clock.h
  43. +37 −1 interface/mmal/mmal_parameters_common.h
  44. +115 −6 interface/mmal/mmal_parameters_video.h
  45. +10 −0 interface/mmal/mmal_pool.h
  46. +3 −1 interface/mmal/mmal_port.h
  47. +3 −0 interface/mmal/mmal_types.h
  48. +2 −0 interface/mmal/util/CMakeLists.txt
  49. +28 −10 interface/mmal/util/mmal_connection.c
  50. +4 −0 interface/mmal/util/mmal_connection.h
  51. +279 −68 interface/mmal/util/mmal_graph.c
  52. +28 −2 interface/mmal/util/mmal_graph.h
  53. +351 −3 interface/mmal/util/mmal_il.c
  54. +76 −1 interface/mmal/util/mmal_il.h
  55. +218 −0 interface/mmal/util/mmal_list.c
  56. +94 −21 interface/mmal/util/mmal_list.h
  57. +3 −2 interface/mmal/util/mmal_param_convert.c
  58. +7 −0 interface/mmal/util/mmal_param_convert.h
  59. +24 −1 interface/mmal/util/mmal_util.c
  60. +9 −1 interface/mmal/util/mmal_util.h
  61. +77 −8 interface/mmal/util/mmal_util_params.c
  62. +68 −2 interface/mmal/util/mmal_util_params.h
  63. +150 −0 interface/mmal/util/mmal_util_rational.c
  64. +118 −0 interface/mmal/util/mmal_util_rational.h
  65. +1 −1 interface/mmal/vc/CMakeLists.txt
  66. +209 −40 interface/mmal/vc/mmal_vc_api.c
  67. +12 −3 interface/mmal/vc/mmal_vc_api.h
  68. +77 −0 interface/mmal/vc/mmal_vc_api_drm.c
  69. +29 −0 interface/{vcos/pthreads/vchost_config.h → mmal/vc/mmal_vc_api_drm.h}
Sorry, we could not display the entire diff because it was too big.
View
20 CMakeLists.txt
@@ -3,7 +3,11 @@ cmake_minimum_required(VERSION 2.8)
project(vmcs_host_apps)
set(BUILD_MMAL TRUE)
-set(BUILD_MMAL_APPS FALSE)
+if (ALL_APPS)
+ set(BUILD_MMAL_APPS TRUE)
+else()
+ set(BUILD_MMAL_APPS FALSE)
+endif()
set(vmcs_root ${PROJECT_SOURCE_DIR})
get_filename_component(VIDEOCORE_ROOT . ABSOLUTE)
@@ -39,7 +43,7 @@ add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE)
# do we actually need this?
add_definitions(-D__VIDEOCORE4__)
-
+add_definitions(-DTV_SUPPORTED_MODE_NO_DEPRECATED)
# add_definitions(-DKHRONOS_CLIENT_LOGGING)
@@ -59,8 +63,10 @@ if(BUILD_MMAL)
include_directories(interface/mmal)
add_subdirectory(interface/mmal)
endif()
+if(BUILD_MMAL_APPS)
+ add_subdirectory(containers)
+endif()
-#add_subdirectory(containers)
add_subdirectory(middleware/openmaxil)
# 3d demo code
@@ -84,7 +90,9 @@ add_subdirectory(interface/usbdk)
# VMCS Host Applications
#add_subdirectory(host_applications/framework)
-#add_subdirectory(host_applications/vmcs)
+if(BUILD_MMAL_APPS)
+ add_subdirectory(host_applications/vmcs)
+endif()
# add_subdirectory(interface/vchiq/test/win32)
@@ -95,6 +103,10 @@ add_subdirectory(interface/usbdk)
# add linux apps
add_subdirectory(host_applications/linux)
+# Debug sym for mmal-vc-diag and vcdbg
+#add_subdirectory(host_applications/linux/libs/debug_sym)
+
+
set(vmcs_host_apps_VERSION_MAJOR 1)
set(vmcs_host_apps_VERSION_MINOR 0)
View
5 helpers/v3d/v3d_ver.h
@@ -45,8 +45,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#elif defined(__BCM2708B0__)
/* 2708 b0 */
#define V3D_REVISION 2
+ #elif defined(__BCM2708C0__) || defined(__BCM2708C1__)
+ /* 2708 c0/1 */
+ #define V3D_REVISION 3
#else
- /* fiji */
+ /* capri */
#define V3D_REVISION 6
#endif
#endif
View
8 helpers/vc_image/metadata_fourcc.h
@@ -55,6 +55,7 @@ typedef enum {
METADATA_AGC_DEBUG = ('A'<<24)+('G'<<16)+('C'<<8)+('D'), // 'AGCD' struct ISP_TUNER_BRCM_AGC_DEBUG_T in /middleware/ISP/tuner/isp_tuner_agc.h
METADATA_FOCUS_REGION = ('F'<<24)+('R'<<16)+('G'<<8)+('N'), // 'FRGN' struct ISP_TUNER_BRCM_AF_STATISTICS_PARAMS_T in /middleware/ISP/tuner/isp_tuner_brcm_common.h
METADATA_FOCUS_WOI = ('F'<<24)+('W'<<16)+('O'<<8)+('I'), // 'FWOI' struct ISP_WOI_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
+ METADATA_FOCUS_CAF = ('F'<<24)+('C'<<16)+('A'<<8)+('F'), // 'FCAF' struct ISP_CAF_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
METADATA_AUTOFOCUS = ( 0 <<24)+( 0 <<16)+('A'<<8)+('F'), // '\x00\x00AF' struct ISP_AF_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
METADATA_EV = ('E'<<24)+('V'<<16)+('M'<<8)+('D'), // 'EVMD' struct ISP_TUNER_BRCM_EV_METADATA_T in /middleware/ISP/tuner/isp_tuner_brcm_common.h
METADATA_ISP = ('I'<<24)+('S'<<16)+('P'<<8)+('M'), // 'ISPM' struct ISP_ISP_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
@@ -64,7 +65,8 @@ typedef enum {
METADATA_SCENEDETECTION = ( 0 <<24)+('A'<<16)+('S'<<8)+('D'), // '\x00ASD' struct ASD_METADATA_T defined in /middleware/camplus/sw/asd_metadata.h
METADATA_TUNER_SYNC = ('S'<<24)+('Y'<<16)+('N'<<8)+('C'), // 'SYNC' NULL data, just adds the item header.
METADATA_DARK_FRAME_CORRECT = ('D'<<24)+('F'<<16)+('R'<<8)+('C'), // 'DFRC' 5 byte literal string "dfrc"
- METADATA_DARK_FRAME_SUB = ('D'<<24)+('F'<<16)+('S'<<8)+('B'), // 'DFSB' 3 byte literal string "on"
+ METADATA_DARK_FRAME_SUB = ('D'<<24)+('F'<<16)+('S'<<8)+('B'), // 'DFSB' 3 byte literal string "on"
+ METADATA_TUNER_DROP_FRAME = ('T'<<24)+('D'<<16)+('R'<<8)+('P'),
METADATA_ABL = ( 0 <<24)+('A'<<16)+('B'<<8)+('L'), // '\x00ABL' struct ISP_TUNER_BRCM_BLACK_LEVEL_ABL_T defined in /middleware/ISP/tuner/isp_tuner_brcm_black_level.h
METADATA_DRC = ( 0 <<24)+('D'<<16)+('R'<<8)+('C'), // 'DRC' struct DRC_METADATA_T defined in /middleware/camplus/sw/drc/drc.h
METADATA_REGISTRATION = ( 0 <<24)+('R'<<16)+('E'<<8)+('G'), // 'REG' struct REGISTRATION_OFFSETS_T defined in /middleware/camplus/sw/registration/registration.h
@@ -96,6 +98,10 @@ typedef enum {
METADATA_ACUTE_AWB_LOG = ('A'<<24)+('E'<<16)+('L'<<8)+('C'), // 'AELC' : ISP_ACUTE_AWB_LOG
METADATA_DF = ( 0 <<24)+( 0<<16)+('D'<<8)+('F'), // '\x00\x00DF' : DF_METADATA_T defined in /middleware/camplus/sw/df/df_metadata.h
METADATA_MAGIC_MEASURE = ('S'<<24)+('S'<<16)+('M'<<8) + ('M'), // 'SSMM' : A statistic from the ISP used to determine the JPEG quality setting for a certain customer.
+ METADATA_SNAPSHOT_JPEG_QUANTISER = ('S'<<24)+('S'<<16)+('J'<<8) + ('S'), // 'SSJQ' : The size of the snapshot frame when JPEG-encoded.
+
+ METADATA_SUPPLEMENTARY_INFO = ('S'<<24)+('U'<<16)+('P'<<8) + ('P'), // 'SUPP' : Supplimentary info defined in /codecs/video/hw/enc/venc_supplementary_info.h
+
METADATA_UNKNOWN = ('U'<<24)+('N'<<16)+('K'<<8)+('N') // 'UNKN'
} METADATA_CODE_T;
View
3 helpers/vc_image/vc_image.h
@@ -135,6 +135,7 @@ extern "C" {
VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5, /* Society of Motion Picture and Television Engineers 240M (1999) */
VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6, /* ITU-R BT.470-2 System M */
VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7, /* ITU-R BT.470-2 System B,G */
+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8, /* JPEG JFIF, but with 16..255 luma */
VC_IMAGE_YUVINFO_CSC_CUSTOM = 15, /* Custom colour matrix follows header */
VC_IMAGE_YUVINFO_CSC_SMPTE_170M = VC_IMAGE_YUVINFO_CSC_ITUR_BT601,
@@ -157,7 +158,7 @@ extern "C" {
bits should be zero and enforce this in vc_image functions to catch people
who aren't initialising the VC_IMAGE_T structure nicely; update when other
bits are added */
-#define VC_IMAGE_INFO_VALIDBITS 0x9F07
+#define VC_IMAGE_INFO_VALIDBITS 0x9F0F
/* Define the bits of info used to denote the colourspace */
#define VC_IMAGE_INFO_COLOURSPACE 0x0F
View
13 host_applications/linux/apps/gencmd/gencmd.c
@@ -40,7 +40,7 @@ int main( int argc, char **argv )
{
int instNum = 0;
VCHI_INSTANCE_T vchi_instance;
- VCHI_CONNECTION_T *vchi_connection;
+ VCHI_CONNECTION_T *vchi_connection = NULL;
if ( argc > 1 )
{
@@ -73,32 +73,33 @@ int main( int argc, char **argv )
{
int i = 1;
char buffer[ 1024 ];
+ size_t buffer_offset = 0;
clock_t before=0, after=0;
double time_diff;
uint32_t show_time = 0;
int ret;
//reset the string
- strcpy( buffer, "" );
+ buffer[0] = '\0';
//first, strip out a potential leading -t
if( strcmp( argv[1], "-t" ) == 0 )
{
show_time = 1;
i++;
- }
+ }
for (; i <= argc-1; i++)
{
- strcat( buffer, argv[i] );
- strcat( buffer, " " );
+ buffer_offset = vcos_safe_strcpy( buffer, argv[i], sizeof(buffer), buffer_offset );
+ buffer_offset = vcos_safe_strcpy( buffer, " ", sizeof(buffer), buffer_offset );
}
if( show_time )
before = clock();
//send the gencmd for the argument
- if (( ret = vc_gencmd_send( buffer )) != 0 )
+ if (( ret = vc_gencmd_send( "%s", buffer )) != 0 )
{
printf( "vc_gencmd_send returned %d\n", ret );
}
View
5 host_applications/linux/apps/hello_pi/hello_tiger/CMakeLists.txt
@@ -1,10 +1,9 @@
set(EXEC hello_tiger.bin)
-set(SRCS tiger.c main.c)
+set(SRCS main.c tiger.c)
+add_definitions(-D__RASPBERRYPI__)
add_executable(${EXEC} ${SRCS})
target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
-add_definitions(-D__RASPBERRYPI__)
-
install(TARGETS ${EXEC}
RUNTIME DESTINATION bin)
View
333 host_applications/linux/apps/tvservice/tvservice.c
@@ -39,6 +39,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "interface/vmcs_host/vc_tvservice.h"
+#define TV_SUPPORTED_MODE_T TV_SUPPORTED_MODE_NEW_T
+#define vc_tv_hdmi_get_supported_modes vc_tv_hdmi_get_supported_modes_new
+#define vc_tv_hdmi_power_on_explicit vc_tv_hdmi_power_on_explicit_new
+
// ---- Public Variables ----------------------------------------------------
// ---- Private Constants and Types -----------------------------------------
@@ -55,6 +59,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Maximum length of option string (3 characters max for each option + NULL)
#define OPTSTRING_LEN ( sizeof( long_opts ) / sizeof( *long_opts ) * 3 + 1 )
+// Maximum mode ID
+#define MAX_MODE_ID (127)
+
// ---- Private Variables ---------------------------------------------------
enum
@@ -101,11 +108,11 @@ static void show_usage( void )
{
LOG_STD( "Usage: tvservice [OPTION]..." );
LOG_STD( " -p, --preferred Power on HDMI with preferred settings" );
- LOG_STD( " -e, --explicit=\"GROUP MODE\" Power on HDMI with explicit GROUP (CEA, DMT, CEA_3D)\n"
+ LOG_STD( " -e, --explicit=\"GROUP MODE\" Power on HDMI with explicit GROUP (CEA, DMT, CEA_3D_SBS, CEA_3D_TAB)\n"
" and MODE (see --modes)" );
LOG_STD( " -n, --sdtvon=\"MODE ASPECT\" Power on SDTV with MODE (PAL or NTSC) and ASPECT (4:3 14:9 or 16:9)" );
LOG_STD( " -o, --off Power off the display" );
- LOG_STD( " -m, --modes=GROUP Get supported modes for GROUP (CEA, DMT, CEA_3D)" );
+ LOG_STD( " -m, --modes=GROUP Get supported modes for GROUP (CEA, DMT)" );
LOG_STD( " -M, --monitor Monitor HDMI events" );
LOG_STD( " -s, --status Get HDMI status" );
LOG_STD( " -a, --audio Get supported audio information" );
@@ -140,20 +147,85 @@ static void create_optstring( char *optstring )
*short_opts++ = '\0';
}
-static int get_modes( HDMI_RES_GROUP_T group )
+/* Return the string presentation of aspect ratio */
+static const char *aspect_ratio_str(HDMI_ASPECT_T aspect_ratio) {
+ switch(aspect_ratio) {
+ case HDMI_ASPECT_4_3:
+ return "4:3";
+ case HDMI_ASPECT_14_9:
+ return "14:9";
+ case HDMI_ASPECT_16_9:
+ return "16:9";
+ case HDMI_ASPECT_5_4:
+ return "5:4";
+ case HDMI_ASPECT_16_10:
+ return "16:10";
+ case HDMI_ASPECT_15_9:
+ return "15:9";
+ case HDMI_ASPECT_64_27:
+ return "64:27 (21:9)";
+ default:
+ return "unknown AR";
+ }
+}
+
+/* Return the string presentation of aspect ratio */
+static const char *aspect_ratio_sd_str(SDTV_ASPECT_T aspect_ratio) {
+ switch(aspect_ratio) {
+ case SDTV_ASPECT_4_3:
+ return "4:3";
+ case SDTV_ASPECT_14_9:
+ return "14:9";
+ case SDTV_ASPECT_16_9:
+ return "16:9";
+ default:
+ return "unknown AR";
+ }
+}
+
+/* Return the string representation of 3D support bit mask */
+static const char* threed_str(uint32_t struct_3d_mask) {
+#define THREE_D_FORMAT_NAME_MAX_LEN 10 //Including the separator
+ static const char* three_d_format_names[] = { //See HDMI_3D_STRUCT_T bit fields
+ "FP", "F-Alt", "L-Alt", "SbS-Full",
+ "Ldep", "Ldep+Gfx", "TopBot", "SbS-HH",
+ "SbS-OLOR", "SbS-OLER", "SbS-ELOR", "SbS-ELER"
+ };
+ //Longest possible string is the concatenation of all of the above
+ static char struct_desc[vcos_countof(three_d_format_names)*THREE_D_FORMAT_NAME_MAX_LEN+4] = {0};
+ char *p = &struct_desc[0];
+ char * const p_end = p + sizeof struct_desc;
+ size_t j, added = 0;
+ p += snprintf(p, p_end - p, "3D:");
+ if(struct_3d_mask) {
+ for(j = 0; j < vcos_countof(three_d_format_names); j++) {
+ if(struct_3d_mask & (1 << j)) {
+ p += snprintf(p, p_end - p, "%s|", three_d_format_names[j]);
+ added++;
+ }
+ }
+ if(added > 0)
+ *(--p) = '\0'; //Get rid of final "|"
+ }
+ if(!added)
+ p += snprintf(p, p_end - p, "none");
+
+ return struct_desc;
+}
+
+static int get_modes( HDMI_RES_GROUP_T group)
{
- TV_SUPPORTED_MODE_T supported_modes[TV_MAX_SUPPORTED_MODES];
+ static TV_SUPPORTED_MODE_T supported_modes[MAX_MODE_ID] = {{0}};
HDMI_RES_GROUP_T preferred_group;
uint32_t preferred_mode;
int num_modes;
int i;
vcos_assert(( group == HDMI_RES_GROUP_CEA ) ||
- ( group == HDMI_RES_GROUP_DMT ) ||
- ( group == HDMI_RES_GROUP_CEA_3D ));
+ ( group == HDMI_RES_GROUP_DMT ));
num_modes = vc_tv_hdmi_get_supported_modes( group, supported_modes,
- TV_MAX_SUPPORTED_MODES,
+ vcos_countof(supported_modes),
&preferred_group,
&preferred_mode );
if ( num_modes < 0 )
@@ -163,70 +235,172 @@ static int get_modes( HDMI_RES_GROUP_T group )
}
LOG_STD( "Group %s has %u modes:",
- group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CEA_3D", num_modes );
+ HDMI_RES_GROUP_NAME(group), num_modes );
for ( i = 0; i < num_modes; i++ )
{
- LOG_STD( "%s mode %u: %ux%u @ %uHz, %s",
+ char p[8] = {0};
+ if( supported_modes[i].pixel_rep )
+ snprintf(p, sizeof(p)-1, "x%d ", supported_modes[i].pixel_rep);
+ else
+ snprintf(p, sizeof(p)-1, " ");
+
+ LOG_STD( "%s mode %u: %ux%u @ %uHz %s, clock:%luMHz %s%s %s",
supported_modes[i].native ? " (native)" : " ",
supported_modes[i].code, supported_modes[i].width,
supported_modes[i].height, supported_modes[i].frame_rate,
- supported_modes[i].scan_mode ? "interlaced" : "progressive" );
+ aspect_ratio_str(supported_modes[i].aspect_ratio),
+ supported_modes[i].pixel_freq / 1000000UL, p,
+ supported_modes[i].scan_mode ? "interlaced" : "progressive",
+ supported_modes[i].struct_3d_mask ? threed_str(supported_modes[i].struct_3d_mask) : "");
}
return 0;
}
-static int get_status( void )
-{
- TV_GET_STATE_RESP_T tvstate = {0};
- static const char *status_str[] = {
- "HPD low",
- "HPD high",
- "DVI mode",
- "HDMI mode",
- "HDCP off",
- "HDCP on",
- "", "", "", "", "", "", "", "", "", "", //end of HDMI states
- "", "", //Currently we don't have a way to detect these
- "NTSC mode", "PAL mode",
- "composite CP off", "composite CP on",
- "", "", "", "", "", "", "", "", "", ""
- };
- static char status[256] = {0};
- char *s = &status[0];
- int i;
-
- vc_tv_get_state( &tvstate );
- for(i = 0; i < 16; i++) {
- if(tvstate.state & (1 << i)) {
- s += sprintf(s, "%s|", status_str[i]);
+static const char *status_mode( TV_DISPLAY_STATE_T *tvstate ) {
+ static char mode_str[96] = {0};
+ char *s = &mode_str[0];
+ int chars_left = sizeof(mode_str) - 1, tmp = 0;
+ if(tvstate->state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) {
+ //HDMI or DVI on
+ if(tvstate->state & VC_HDMI_HDMI) {
+ tmp = snprintf(s, chars_left, "HDMI");
+ chars_left -= tmp; s += tmp;
+ switch(tvstate->display.hdmi.group) {
+ case HDMI_RES_GROUP_CEA:
+ tmp = snprintf(s, chars_left, " CEA (%d)", tvstate->display.hdmi.mode); break;
+ case HDMI_RES_GROUP_DMT:
+ tmp = snprintf(s, chars_left, " DMT (%d)", tvstate->display.hdmi.mode); break;
+ default:
+ tmp = 0;
+ }
+ chars_left -= tmp; s += tmp;
+
+ if(tvstate->display.hdmi.format_3d) {
+ switch(tvstate->display.hdmi.format_3d) {
+ case HDMI_3D_FORMAT_SBS_HALF:
+ tmp = snprintf(s, chars_left, " 3D SbS"); break;
+ case HDMI_3D_FORMAT_TB_HALF:
+ tmp = snprintf(s, chars_left, " 3D T&B"); break;
+ default:
+ tmp = 0; break;
+ }
+ chars_left -= tmp; s += tmp;
+ }
+
+ //Only HDMI mode can signal pixel encoding in AVI infoframe
+ switch(tvstate->display.hdmi.pixel_encoding) {
+ case HDMI_PIXEL_ENCODING_RGB_LIMITED:
+ tmp = snprintf(s, chars_left, " RGB lim"); break;
+ case HDMI_PIXEL_ENCODING_RGB_FULL:
+ tmp = snprintf(s, chars_left, " RGB full"); break;
+ case HDMI_PIXEL_ENCODING_YCbCr444_LIMITED:
+ tmp = snprintf(s, chars_left, " YCbCr444 lim"); break;
+ case HDMI_PIXEL_ENCODING_YCbCr444_FULL:
+ tmp = snprintf(s, chars_left, " YCbCr444 full"); break;
+ case HDMI_PIXEL_ENCODING_YCbCr422_LIMITED:
+ tmp = snprintf(s, chars_left, " YCbCr422 lim"); break;
+ case HDMI_PIXEL_ENCODING_YCbCr422_FULL:
+ tmp = snprintf(s, chars_left, " YCbCr422 full"); break;
+ default:
+ tmp = 0; break;
+ }
+ chars_left -= tmp; s += tmp;
+
+ } else {
+ //DVI will always be RGB, and CEA mode will have limited range, DMT mode full range
+ tmp = snprintf(s, chars_left, "DVI %s",
+ (tvstate->display.hdmi.group == HDMI_RES_GROUP_CEA)?
+ " RGB lim" : " RGB full");
+ chars_left -= tmp; s += tmp;
}
- }
- if((tvstate.state & (VC_HDMI_DVI|VC_HDMI_HDMI)) == 0)
- s += sprintf(s, "HDMI off|");
+ //This is the format's aspect ratio, not the one
+ //signaled in the AVI infoframe
+ tmp = snprintf(s, chars_left, " %s", aspect_ratio_str(tvstate->display.hdmi.aspect_ratio));
+ chars_left -= tmp; s += tmp;
- if(tvstate.state & (VC_SDTV_NTSC|VC_SDTV_PAL)) {
- for(i = 18; i < 31; i++) {
- if(tvstate.state & (1 << i)) {
- s += sprintf(s, "%s|", status_str[i]);
- }
+ if(tvstate->display.hdmi.pixel_rep) {
+ tmp = snprintf(s, chars_left, " x%d", tvstate->display.hdmi.pixel_rep);
+ chars_left -= tmp; s += tmp;
}
+
+ if(tvstate->state & VC_HDMI_HDCP_AUTH) {
+ tmp = snprintf(s, chars_left, " HDCP");
+ chars_left -= tmp; s += tmp;
+ }
+ } else if(tvstate->state & ( VC_SDTV_NTSC | VC_SDTV_PAL )) {
+ if(tvstate->state & VC_SDTV_NTSC) {
+ tmp = snprintf(s, chars_left, "NTSC");
+ chars_left -= tmp; s += tmp;
+ } else {
+ tmp = snprintf(s, chars_left, "PAL");
+ chars_left -= tmp; s += tmp;
+ }
+
+ if(tvstate->display.sdtv.cp_mode) {
+ switch(tvstate->display.sdtv.cp_mode) {
+ case SDTV_CP_MACROVISION_TYPE1:
+ tmp = snprintf(s, chars_left, " Macrovision type 1"); break;
+ case SDTV_CP_MACROVISION_TYPE2:
+ tmp = snprintf(s, chars_left, " Macrovision type 2"); break;
+ case SDTV_CP_MACROVISION_TYPE3:
+ tmp = snprintf(s, chars_left, " Macrovision type 3"); break;
+ case SDTV_CP_MACROVISION_TEST1:
+ tmp = snprintf(s, chars_left, " Macrovision test 1"); break;
+ case SDTV_CP_MACROVISION_TEST2:
+ tmp = snprintf(s, chars_left, " Macrovision test 2"); break;
+ case SDTV_CP_CGMS_COPYFREE:
+ tmp = snprintf(s, chars_left, " CGMS copy free"); break;
+ case SDTV_CP_CGMS_COPYNOMORE:
+ tmp = snprintf(s, chars_left, " CGMS copy no more"); break;
+ case SDTV_CP_CGMS_COPYONCE:
+ tmp = snprintf(s, chars_left, " CGMS copy once"); break;
+ case SDTV_CP_CGMS_COPYNEVER:
+ tmp = snprintf(s, chars_left, " CGMS copy never"); break;
+ case SDTV_CP_WSS_COPYFREE:
+ tmp = snprintf(s, chars_left, " WSS copy free"); break;
+ case SDTV_CP_WSS_COPYRIGHT_COPYFREE:
+ tmp = snprintf(s, chars_left, " WSS (c) copy free"); break;
+ case SDTV_CP_WSS_NOCOPY:
+ tmp = snprintf(s, chars_left, " WSS no copy"); break;
+ case SDTV_CP_WSS_COPYRIGHT_NOCOPY:
+ tmp = snprintf(s, chars_left, " WSS (c) no copy"); break;
+ default:
+ tmp = 0; break;
+ }
+ chars_left -= tmp; s += tmp;
+ }
+ //This is the format's aspect ratio
+ tmp = snprintf(s, chars_left, " %s", aspect_ratio_str(tvstate->display.sdtv.display_options.aspect));
+ chars_left -= tmp; s += tmp;
} else {
- s += sprintf(s, "composite off|");
+ tmp = snprintf(s, chars_left, "TV is off");
+ chars_left -= tmp; s += tmp;
}
- *(--s) = '\0';
+ return mode_str;
+}
- if(tvstate.width && tvstate.height) {
- LOG_STD( "state: %s (0x%x), %ux%u @ %uHz, %s", status, tvstate.state,
- tvstate.width, tvstate.height, tvstate.frame_rate,
- tvstate.scan_mode ? "interlaced" : "progressive" );
+static int get_status( void )
+{
+ TV_DISPLAY_STATE_T tvstate;
+ if( vc_tv_get_display_state( &tvstate ) == 0) {
+ //The width/height parameters are in the same position in the union
+ //for HDMI and SDTV
+ if(tvstate.display.hdmi.width && tvstate.display.hdmi.height) {
+ LOG_STD( "state 0x%x [%s], %ux%u @ %uHz, %s", tvstate.state,
+ status_mode(&tvstate),
+ tvstate.display.hdmi.width, tvstate.display.hdmi.height,
+ tvstate.display.hdmi.frame_rate,
+ tvstate.display.hdmi.scan_mode ? "interlaced" : "progressive" );
+ } else {
+ LOG_STD( "state 0x%x [%s]", tvstate.state, status_mode(&tvstate));
+ }
} else {
- LOG_STD( "state: %s (0x%x), HDMI powered off", status, tvstate.state);
+ LOG_STD( "Error getting current display state");
}
-
- return 0;
+ return 0;
}
static int get_audiosup( void )
@@ -267,7 +441,8 @@ static int get_audiosup( void )
static int dump_edid( const char *filename )
{
uint8_t buffer[128];
- int written = 0, offset = 0, i, extensions = 0;
+ size_t written = 0, offset = 0;
+ int i, extensions = 0;
FILE *fp = fopen(filename, "wb");
int siz = vc_tv_hdmi_ddc_read(offset, sizeof (buffer), buffer);
offset += sizeof( buffer);
@@ -402,18 +577,34 @@ static int power_on_explicit( HDMI_RES_GROUP_T group,
int ret;
LOG_STD( "Powering on HDMI with explicit settings (%s mode %u)",
- group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CEA_3D", mode );
+ group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CUSTOM", mode );
ret = vc_tv_hdmi_power_on_explicit( HDMI_MODE_HDMI, group, mode );
if ( ret != 0 )
{
LOG_ERR( "Failed to power on HDMI with explicit settings (%s mode %u)",
- group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CEA_3D", mode );
+ group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CUSTOM", mode );
}
return ret;
}
+static int set_property(HDMI_PROPERTY_T prop, uint32_t param1, uint32_t param2)
+{
+ int ret;
+ HDMI_PROPERTY_PARAM_T property;
+ property.property = prop;
+ property.param1 = param1;
+ property.param2 = param2;
+ LOG_STD( "Setting property %d with params %d, %d", prop, param1, param2);
+ ret = vc_tv_hdmi_set_property(&property);
+ if(ret != 0)
+ {
+ LOG_ERR( "Failed to set property %d", prop);
+ }
+ return ret;
+}
+
static int power_on_sdtv( SDTV_MODE_T mode,
SDTV_ASPECT_T aspect )
{
@@ -466,6 +657,7 @@ int main( int argc, char **argv )
int opt_audiosup = 0;
int opt_dumpedid = 0;
int opt_showinfo = 0;
+ int opt_3d = 0;
char *dumpedid_filename = NULL;
VCHI_INSTANCE_T vchi_instance;
VCHI_CONNECTION_T *vchi_connection;
@@ -501,7 +693,8 @@ int main( int argc, char **argv )
{
char group_str[32];
- if ( sscanf( optarg, "%s %u", group_str,
+ /* coverity[secure_coding] String length specified, so can't overflow */
+ if ( sscanf( optarg, "%31s %u", group_str,
&power_on_explicit_mode ) != 2 )
{
LOG_ERR( "Invalid arguments '%s'", optarg );
@@ -517,9 +710,16 @@ int main( int argc, char **argv )
{
power_on_explicit_group = HDMI_RES_GROUP_DMT;
}
- else if ( vcos_strcasecmp( "CEA_3D", group_str ) == 0 )
+ else if ( vcos_strcasecmp( "CEA_3D", group_str ) == 0 ||
+ vcos_strcasecmp( "CEA_3D_SBS", group_str ) == 0)
+ {
+ power_on_explicit_group = HDMI_RES_GROUP_CEA;
+ opt_3d = 1;
+ }
+ else if ( vcos_strcasecmp( "CEA_3D_TAB", group_str ) == 0 )
{
- power_on_explicit_group = HDMI_RES_GROUP_CEA_3D;
+ power_on_explicit_group = HDMI_RES_GROUP_CEA;
+ opt_3d = 2;
}
else
{
@@ -528,7 +728,7 @@ int main( int argc, char **argv )
}
// Then check if mode is a sane number
- if ( power_on_explicit_mode > 256 )
+ if ( power_on_explicit_mode > MAX_MODE_ID )
{
LOG_ERR( "Invalid mode '%u'", power_on_explicit_mode );
goto err_out;
@@ -602,10 +802,6 @@ int main( int argc, char **argv )
{
get_modes_group = HDMI_RES_GROUP_DMT;
}
- else if ( vcos_strcasecmp( "CEA_3D", optarg ) == 0 )
- {
- get_modes_group = HDMI_RES_GROUP_CEA_3D;
- }
else
{
LOG_ERR( "Invalid group '%s'", optarg );
@@ -644,6 +840,7 @@ int main( int argc, char **argv )
default:
{
LOG_ERR( "Unrecognized option '%d'\n", opt );
+ goto err_usage;
}
case '?':
case OPT_HELP:
@@ -710,7 +907,7 @@ int main( int argc, char **argv )
if ( opt_modes == 1 )
{
- if ( get_modes( get_modes_group ) != 0 )
+ if ( get_modes( get_modes_group) != 0 )
{
goto err_stop_service;
}
@@ -725,6 +922,16 @@ int main( int argc, char **argv )
}
else if ( opt_explicit == 1 )
{
+ //Distinguish between turning on 3D side by side and 3D top/bottom
+ if(opt_3d == 1 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_SBS_HALF, 0) != 0)
+ {
+ goto err_stop_service;
+ }
+ else if(opt_3d == 2 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_TB_HALF, 0) != 0)
+ {
+ goto err_stop_service;
+ }
+
if ( power_on_explicit( power_on_explicit_group,
power_on_explicit_mode ) != 0 )
{
View
40 host_support/include/vc_debug_sym.h
@@ -43,6 +43,10 @@ typedef struct
} VC_DEBUG_SYMBOL_T;
+/*
+ * Debug header+params are constructed by makefiles/internals/memorymap.mk
+ * (first .text section) and stored in the VC binary
+ */
typedef struct
{
uint32_t symbolTableOffset;
@@ -52,7 +56,7 @@ typedef struct
typedef struct
{
- uint32_t vcMemBase;
+ uint32_t vcMemBase; /* base address of loaded binary */
uint32_t vcMemSize;
uint32_t vcEntryPoint;
uint32_t symbolTableLength;
@@ -63,7 +67,7 @@ typedef struct
// Offset within the videocore memory map to get the address of the debug header.
#define VC_DEBUG_HEADER_OFFSET 0x2800
-#if defined( __VC4_BIG_ISLAND__ ) || defined (PLATFORM_RASPBERRYPI)
+#if (defined( __VC4_BIG_ISLAND__ ) || defined (PLATFORM_RASPBERRYPI)) && !defined( __COVERITY__ )
/* Use of the debug symbols only makes sense on machines which have
* some type of shared memory architecture.
@@ -75,9 +79,9 @@ typedef struct
#endif
#if USE_VC_DEBUG_SYMS
-# define PRAGMA(foo) pragma foo
+# define VCDBG_PRAGMA(foo) pragma foo
#else
-# define PRAGMA(foo)
+# define VCDBG_PRAGMA(foo)
#endif
/*
@@ -87,9 +91,9 @@ typedef struct
#if USE_VC_DEBUG_SYMS
#define VC_DEBUG_SYMBOL(name,label,addr,size) \
- PRAGMA( Data(LIT, ".init.vc_debug_sym" ); ) \
+ VCDBG_PRAGMA( Data(LIT, ".init.vc_debug_sym" ); ) \
static const VC_DEBUG_SYMBOL_T vc_sym_##name = { label, (uint32_t)addr, size }; \
- PRAGMA( Data )
+ VCDBG_PRAGMA( Data )
#else
#define VC_DEBUG_SYMBOL(name,label,addr,size)
#endif
@@ -115,30 +119,34 @@ typedef struct
*/
#define VC_DEBUG_DECLARE_UNCACHED_VAR(var_type,var_name,var_init) \
- PRAGMA( Data(".ucdata"); ) \
+ VCDBG_PRAGMA( Data(".ucdata"); ) \
var_type var_name = (var_init); \
- PRAGMA( Data(); ) \
+ VCDBG_PRAGMA( Data(); ) \
var_type *vc_var_ptr_##var_name = &var_name; \
VC_DEBUG_VAR(var_name)
+#define VC_DEBUG_EXTERN_UNCACHED_VAR(var_type,var_name) \
+ extern var_type var_name; \
+ static var_type *vc_var_ptr_##var_name = &var_name
+
#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR(var_type,var_name,var_init) \
- PRAGMA( Data(".ucdata"); ) \
+ VCDBG_PRAGMA( Data(".ucdata"); ) \
static var_type var_name = (var_init); \
- PRAGMA( Data(); ) \
+ VCDBG_PRAGMA( Data(); ) \
static var_type *vc_var_ptr_##var_name = &var_name; \
VC_DEBUG_VAR(var_name)
#define VC_DEBUG_DECLARE_UNCACHED_VAR_ZERO(var_type,var_name) \
- PRAGMA( Data(".ucdata"); ) \
+ VCDBG_PRAGMA( Data(".ucdata"); ) \
var_type var_name = {0}; \
- PRAGMA( Data(); ) \
+ VCDBG_PRAGMA( Data(); ) \
var_type *vc_var_ptr_##var_name = &var_name; \
VC_DEBUG_VAR(var_name)
#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR_ZERO(var_type,var_name) \
- PRAGMA( Data(".ucdata"); ) \
+ VCDBG_PRAGMA( Data(".ucdata"); ) \
static var_type var_name = {0}; \
- PRAGMA( Data(); ) \
+ VCDBG_PRAGMA( Data(); ) \
static var_type *vc_var_ptr_##var_name = &var_name; \
VC_DEBUG_VAR(var_name)
@@ -160,9 +168,9 @@ typedef struct
*/
#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR_NO_PTR(var_type,var_name,var_init) \
- PRAGMA( Data(".init.ucdata"); ) \
+ VCDBG_PRAGMA( Data(".init.ucdata"); ) \
static var_type var_name = (var_init); \
- PRAGMA( Data(); ) \
+ VCDBG_PRAGMA( Data(); ) \
VC_DEBUG_VAR(var_name)
/* ---- Variable Externs ------------------------------------------------- */
View
1 interface/khronos/common/khrn_int_common.h
@@ -33,6 +33,7 @@ extern "C" {
#include "helpers/v3d/v3d_ver.h"
+#define VC_KHRN_VERSION 1
//#define KHRN_NOT_REALLY_DUALCORE // Use dual core codebase but switch master thread to vpu1
//#define KHRN_SIMPLE_MULTISAMPLE
//#define USE_CTRL_FOR_DATA
View
25 interface/khronos/common/linux/khrn_client_rpc_linux.c
@@ -188,9 +188,28 @@ void vc_vchi_khronos_init()
exit(1);
}
- if (vchiq_open_service(khrn_vchiq_instance, FOURCC_KHAN, khan_callback, NULL, &vchiq_khan_service) != VCHIQ_SUCCESS ||
- vchiq_open_service(khrn_vchiq_instance, FOURCC_KHRN, khrn_callback, NULL, &vchiq_khrn_service) != VCHIQ_SUCCESS ||
- vchiq_open_service(khrn_vchiq_instance, FOURCC_KHHN, khhn_callback, NULL, &vchiq_khhn_service) != VCHIQ_SUCCESS)
+ VCHIQ_STATUS_T khan_return, khrn_return, khhn_return;
+ VCHIQ_SERVICE_PARAMS_T params;
+
+ params.userdata = NULL;
+ params.version = VC_KHRN_VERSION;
+ params.version_min = VC_KHRN_VERSION;
+
+ params.fourcc = FOURCC_KHAN;
+ params.callback = khan_callback;
+ khan_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khan_service);
+
+ params.fourcc = FOURCC_KHRN;
+ params.callback = khrn_callback;
+ khrn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khrn_service);
+
+ params.fourcc = FOURCC_KHHN;
+ params.callback = khhn_callback;
+ khhn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khhn_service);
+
+ if (khan_return != VCHIQ_SUCCESS ||
+ khrn_return != VCHIQ_SUCCESS ||
+ khhn_return != VCHIQ_SUCCESS)
{
vcos_log_error("* failed to add service - already in use?");
View
1,029 interface/khronos/wf/wfc_client.c
669 additions, 360 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
37 interface/khronos/wf/wfc_client_ipc.c
@@ -148,10 +148,12 @@ static WFC_WAITER_T *wfc_client_ipc_get_waiter(WFC_CLIENT_IPC_T *client)
break;
}
- vcos_assert(i != WFC_CLIENT_IPC_MAX_WAITERS); /* If we get here, semaphore isn't working */
-
- waiter = client->waitpool.waiters + i;
- waiter->inuse = 1;
+ /* If this fails, the semaphore isn't working */
+ if (vcos_verify(i != WFC_CLIENT_IPC_MAX_WAITERS))
+ {
+ waiter = client->waitpool.waiters + i;
+ waiter->inuse = 1;
+ }
vcos_mutex_unlock(&client->lock);
return waiter;
@@ -199,6 +201,7 @@ static VCHIQ_STATUS_T wfc_client_ipc_vchiq_callback(VCHIQ_REASON_T reason,
/* Call the client function */
(*cb_func)(callback_msg->callback_data.ptr);
}
+ vchiq_release_message(service, vchiq_header);
}
else
{
@@ -228,12 +231,18 @@ static VCHIQ_STATUS_T wfc_client_ipc_vchiq_callback(VCHIQ_REASON_T reason,
case VCHIQ_BULK_RECEIVE_ABORTED:
case VCHIQ_BULK_TRANSMIT_ABORTED:
{
- vcos_assert(!"bulk messages not used");
+ vcos_assert_msg(0, "bulk messages not used");
vchiq_release_message(service, vchiq_header);
}
break;
+ case VCHIQ_SERVICE_OPENED:
+ vcos_log_trace("%s: service %p opened", VCOS_FUNCTION, service);
+ break;
+ case VCHIQ_SERVICE_CLOSED:
+ vcos_log_trace("%s: service %p closed", VCOS_FUNCTION, service);
+ break;
default:
- vcos_assert(!"unexpected message reason");
+ vcos_assert_msg(0, "unexpected message reason");
break;
}
return VCHIQ_SUCCESS;
@@ -391,27 +400,15 @@ VCOS_STATUS_T wfc_client_ipc_init(void)
vchiq_params.fourcc = WFC_IPC_CONTROL_FOURCC();
vchiq_params.callback = wfc_client_ipc_vchiq_callback;
vchiq_params.userdata = &wfc_client_ipc;
- vchiq_params.version = WFC_IPC_VER_MAJOR;
+ vchiq_params.version = WFC_IPC_VER_CURRENT;
vchiq_params.version_min = WFC_IPC_VER_MINIMUM;
- vchiq_status = vchiq_open_service_params(wfc_client_ipc_vchiq_instance, &vchiq_params, &wfc_client_ipc.service);
+ vchiq_status = vchiq_open_service(wfc_client_ipc_vchiq_instance, &vchiq_params, &wfc_client_ipc.service);
if (vchiq_status != VCHIQ_SUCCESS)
{
vcos_log_error("%s: could not open vchiq service: %d", VCOS_FUNCTION, vchiq_status);
goto error;
}
-
- if (wfc_client_ipc.service == NULL)
- {
- vcos_log_error("%s: vchiq service is NULL, but open returned VCHIQ_SUCCESS?", VCOS_FUNCTION);
- goto error;
- }
-
- if (wfc_client_ipc.service == NULL)
- {
- vcos_log_error("%s: vchiq service is NULL, but open returned VCHIQ_SUCCESS?", VCOS_FUNCTION);
- goto error;
- }
service_initialised = true;
status = wfc_client_ipc_create_waitpool(&wfc_client_ipc.waitpool);
View
203 interface/khronos/wf/wfc_client_server_api.c
@@ -172,30 +172,30 @@ void wfc_server_destroy_context(WFCContext context)
/* ------------------------------------------------------------------------- */
-uint32_t wfc_server_compose_scene(WFCContext context, const WFC_SCENE_T *scene,
- WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data)
+uint32_t wfc_server_commit_scene(WFCContext context, const WFC_SCENE_T *scene,
+ uint32_t flags, WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data)
{
- WFC_IPC_MSG_COMPOSE_SCENE_T msg;
+ WFC_IPC_MSG_COMMIT_SCENE_T msg;
VCOS_STATUS_T status = VCOS_SUCCESS;
uint32_t result = VCOS_ENOSYS;
size_t result_len = sizeof(result);
uint32_t i;
- vcos_log_trace("%s: context 0x%x elements %u wait %d scene_taken_cb %p _data %p",
- VCOS_FUNCTION, context, scene->element_count, scene->wait, scene_taken_cb,
- scene_taken_data);
+ vcos_log_trace("%s: context 0x%x commit %u elements %u flags 0x%x",
+ VCOS_FUNCTION, context, scene->commit_count, scene->element_count, flags);
for (i = 0; i < scene->element_count; i++)
{
vcos_log_trace("%s: element[%u] stream 0x%x", VCOS_FUNCTION, i, scene->elements[i].source_stream);
}
- msg.header.type = WFC_IPC_MSG_COMPOSE_SCENE;
+ msg.header.type = WFC_IPC_MSG_COMMIT_SCENE;
msg.context = context;
+ msg.flags = flags;
msg.scene_taken_cb.ptr = scene_taken_cb;
msg.scene_taken_data.ptr = scene_taken_data;
memcpy(&msg.scene, scene, sizeof(*scene));
- if (scene->wait)
+ if (flags & WFC_SERVER_COMMIT_WAIT)
{
/* Caller will wait for callback, call cannot fail */
vcos_assert(scene_taken_cb != NULL);
@@ -265,16 +265,18 @@ void wfc_server_set_deferral_stream(WFCContext context, WFCNativeStreamType stre
WFCNativeStreamType wfc_server_stream_create(WFCNativeStreamType stream, uint32_t flags, uint32_t pid_lo, uint32_t pid_hi)
{
- WFC_IPC_MSG_SS_CREATE_T msg;
+ WFC_IPC_MSG_SS_CREATE_INFO_T msg;
VCOS_STATUS_T status;
WFCNativeStreamType result = WFC_INVALID_HANDLE;
size_t result_len = sizeof(result);
vcos_log_trace("%s: stream 0x%x flags 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, flags, pid_hi, pid_lo);
- msg.header.type = WFC_IPC_MSG_SS_CREATE;
+ msg.header.type = WFC_IPC_MSG_SS_CREATE_INFO;
msg.stream = stream;
- msg.flags = flags;
+ memset(&msg.info, 0, sizeof(msg.info));
+ msg.info.size = sizeof(msg.info);
+ msg.info.flags = flags;
msg.pid_lo = pid_lo;
msg.pid_hi = pid_hi;
@@ -290,13 +292,61 @@ WFCNativeStreamType wfc_server_stream_create(WFCNativeStreamType stream, uint32_
/* ------------------------------------------------------------------------- */
-void wfc_server_stream_destroy(WFCNativeStreamType stream)
+WFCNativeStreamType wfc_server_stream_create_info(WFCNativeStreamType stream, const WFC_STREAM_INFO_T *info, uint32_t pid_lo, uint32_t pid_hi)
{
+ WFC_IPC_MSG_SS_CREATE_INFO_T msg;
+ uint32_t copy_size;
+ VCOS_STATUS_T status;
+ WFCNativeStreamType result = WFC_INVALID_HANDLE;
+ size_t result_len = sizeof(result);
+
+ if (!info)
+ {
+ vcos_log_error("%s: NULL info pointer passed", VCOS_FUNCTION);
+ return WFC_INVALID_HANDLE;
+ }
+
+ if (info->size < sizeof(uint32_t))
+ {
+ vcos_log_error("%s: invalid info pointer passed (size:%u)", VCOS_FUNCTION, info->size);
+ return WFC_INVALID_HANDLE;
+ }
+
+ vcos_log_trace("%s: stream 0x%x flags 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, info->flags, pid_hi, pid_lo);
+
+ msg.header.type = WFC_IPC_MSG_SS_CREATE_INFO;
+ msg.stream = stream;
+ copy_size = vcos_min(info->size, sizeof(msg.info));
+ memcpy(&msg.info, info, copy_size);
+ msg.info.size = copy_size;
+ msg.pid_lo = pid_lo;
+ msg.pid_hi = pid_hi;
+
+ status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
+
+ vcos_log_trace("%s: status 0x%x, result 0x%x", VCOS_FUNCTION, status, result);
+
+ if (status != VCOS_SUCCESS)
+ result = WFC_INVALID_HANDLE;
+
+ return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_destroy(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
+{
+ WFC_IPC_MSG_SS_DESTROY_T msg;
VCOS_STATUS_T status;
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
- status = wfc_client_server_api_send_stream(WFC_IPC_MSG_SS_DESTROY, stream);
+ msg.header.type = WFC_IPC_MSG_SS_DESTROY;
+ msg.stream = stream;
+ msg.pid_lo = pid_lo;
+ msg.pid_hi = pid_hi;
+
+ status = wfc_client_ipc_send(&msg.header, sizeof(msg));
vcos_assert(status == VCOS_SUCCESS);
}
@@ -333,8 +383,8 @@ uint32_t wfc_server_stream_get_rects(WFCNativeStreamType stream, int32_t rects[W
size_t rects_len = sizeof(reply) - sizeof(WFC_IPC_MSG_HEADER_T);
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
-
- status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_RECTS, stream, &reply.header + 1, &rects_len);
+ memset(&reply, 0, sizeof(reply));
+ status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_RECTS, stream, &reply.result, &rects_len);
if (status == VCOS_SUCCESS)
{
@@ -342,7 +392,7 @@ uint32_t wfc_server_stream_get_rects(WFCNativeStreamType stream, int32_t rects[W
if (result == VCOS_SUCCESS)
{
- memcpy(rects, reply.rects, sizeof(rects));
+ memcpy(rects, reply.rects, WFC_SERVER_STREAM_RECTS_SIZE * sizeof(*rects));
vcos_log_trace("%s: rects (%d,%d,%d,%d) (%d,%d,%d,%d)", VCOS_FUNCTION,
rects[0], rects[1], rects[2], rects[3], rects[4], rects[5], rects[6], rects[7]);
}
@@ -409,16 +459,27 @@ bool wfc_server_stream_allocate_images(WFCNativeStreamType stream, uint32_t widt
/* ------------------------------------------------------------------------- */
-void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream, EGLImageKHR image_handle)
+void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream,
+ uint32_t ustorage, uint32_t width, uint32_t height, uint32_t stride,
+ uint32_t offset, uint32_t format, uint32_t flags, bool flip)
{
WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T msg;
VCOS_STATUS_T status;
- vcos_log_trace("%s: stream 0x%x image 0x%x", VCOS_FUNCTION, stream, (unsigned int)image_handle);
-
+ memset(&msg, 0, sizeof msg);
msg.header.type = WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA;
msg.stream = stream;
- msg.image_handle = image_handle;
+ msg.ustorage = ustorage;
+ msg.width = width;
+ msg.height = height;
+ msg.stride = stride;
+ msg.offset = offset;
+ msg.format = format;
+ msg.flags = flags;
+ msg.flip = flip;
+
+ vcos_log_trace("%s: stream 0x%x image storage 0x%x",
+ VCOS_FUNCTION, stream, ustorage);
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
@@ -446,13 +507,15 @@ void wfc_server_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t
/* ------------------------------------------------------------------------- */
void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
- uint32_t handle, uint32_t format, uint32_t width, uint32_t height, uint32_t pitch)
+ uint32_t handle, uint32_t format, uint32_t width, uint32_t height,
+ uint32_t pitch, uint32_t vpitch)
{
WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T msg;
VCOS_STATUS_T status;
- vcos_log_trace("%s: stream 0x%x image 0x%x format 0x%x width %u height %u pitch %u",
- VCOS_FUNCTION, stream, handle, format, width, height, pitch);
+ vcos_log_trace("%s: stream 0x%x image 0x%x format 0x%x width %u height %u"
+ " pitch %u vpitch %u",
+ VCOS_FUNCTION, stream, handle, format, width, height, pitch, vpitch);
msg.header.type = WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS;
msg.stream = stream;
@@ -461,6 +524,38 @@ void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
msg.width = width;
msg.height = height;
msg.pitch = pitch;
+ msg.vpitch = vpitch;
+
+ status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+ vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+void wfc_server_stream_signal_image(WFCNativeStreamType stream,
+ const WFC_STREAM_IMAGE_T *image)
+{
+ WFC_IPC_MSG_SS_SIGNAL_IMAGE_T msg;
+ VCOS_STATUS_T status;
+
+ vcos_log_trace("%s: stream 0x%x type 0x%x handle 0x%x "
+ " format 0x%x protection 0x%x width %u height %u "
+ " pitch %u vpitch %u",
+ VCOS_FUNCTION, stream, image->type, image->handle,
+ image->format, image->protection, image->width, image->height,
+ image->pitch, image->vpitch);
+
+ msg.header.type = WFC_IPC_MSG_SS_SIGNAL_IMAGE;
+ msg.stream = stream;
+ if vcos_verify(image->length <= sizeof(msg.image))
+ {
+ msg.image = *image;
+ }
+ else
+ {
+ /* Client is newer than VC ? */
+ memcpy(&msg.image, image, sizeof(msg.image));
+ msg.image.length = sizeof(msg.image);
+ }
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
@@ -488,19 +583,75 @@ void wfc_server_stream_register(WFCNativeStreamType stream, uint32_t pid_lo, uin
/* ------------------------------------------------------------------------- */
-void wfc_server_stream_unregister(WFCNativeStreamType stream)
+void wfc_server_stream_unregister(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
{
+ WFC_IPC_MSG_SS_UNREGISTER_T msg;
VCOS_STATUS_T status;
- vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+ vcos_log_trace("%s: stream 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, pid_hi, pid_lo);
- status = wfc_client_server_api_send_stream(WFC_IPC_MSG_SS_UNREGISTER, stream);
+ msg.header.type = WFC_IPC_MSG_SS_UNREGISTER;
+ msg.stream = stream;
+ msg.pid_lo = pid_lo;
+ msg.pid_hi = pid_hi;
+
+ status = wfc_client_ipc_send(&msg.header, sizeof(msg));
vcos_assert(status == VCOS_SUCCESS);
}
/* ------------------------------------------------------------------------- */
+uint32_t wfc_server_stream_get_info(WFCNativeStreamType stream, WFC_STREAM_INFO_T *info)
+{
+ uint32_t result;
+ VCOS_STATUS_T status;
+ WFC_IPC_MSG_SS_GET_INFO_T reply;
+ size_t info_len = sizeof(reply) - sizeof(WFC_IPC_MSG_HEADER_T);
+
+ if (!info)
+ {
+ vcos_log_error("%s: NULL info pointer passed", VCOS_FUNCTION);
+ return WFC_INVALID_HANDLE;
+ }
+
+ if (info->size < sizeof(uint32_t))
+ {
+ vcos_log_error("%s: invalid info pointer passed (size:%u)", VCOS_FUNCTION, info->size);
+ return WFC_INVALID_HANDLE;
+ }
+
+ vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+ memset(&reply, 0, sizeof(reply));
+ status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_INFO, stream, &reply.result, &info_len);
+
+ if (status == VCOS_SUCCESS)
+ {
+ result = reply.result;
+
+ if (result == VCOS_SUCCESS)
+ {
+ uint32_t copy_size = vcos_min(info->size, reply.info.size);
+ memcpy(info, &reply.info, copy_size);
+ info->size = copy_size;
+ vcos_log_trace("%s: copied %u bytes", VCOS_FUNCTION, copy_size);
+ }
+ else
+ {
+ vcos_log_error("%s: result %d", VCOS_FUNCTION, result);
+ }
+ }
+ else
+ {
+ vcos_log_error("%s: send msg status %d", VCOS_FUNCTION, status);
+ result = status;
+ }
+
+ return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
void wfc_server_stream_on_image_available(WFCNativeStreamType stream, WFC_CALLBACK_T image_available_cb, void *image_available_data)
{
WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE_T msg;
View
810 interface/khronos/wf/wfc_client_stream.c
@@ -28,9 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define VCOS_VERIFY_BKPTS 1 // TODO remove
#define VCOS_LOG_CATEGORY (&log_cat)
-#include "interface/khronos/common/khrn_client_platform.h"
-#include "interface/khronos/common/khrn_client_pointermap.h"
+#include "interface/khronos/common/khrn_client.h"
#include "interface/vcos/vcos.h"
+#ifdef KHRN_FRUIT_DIRECT
+#include "middleware/khronos/egl/egl_server.h"
+#include "middleware/khronos/ext/egl_khr_image.h"
+#include "middleware/khronos/common/khrn_umem.h"
+#endif
#include "interface/khronos/wf/wfc_client_stream.h"
#include "interface/khronos/wf/wfc_server_api.h"
@@ -44,38 +48,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//==============================================================================
-//!@name Numbers of various things (all fixed size for now)
+//!@name Stream data block pool sizes
+//!@{
+#define WFC_STREAM_BLOCK_SIZE (WFC_MAX_STREAMS_PER_CLIENT / 8)
+#define WFC_STREAM_MAX_EXTENSIONS 7
+#define WFC_STREAM_MAX_STREAMS (WFC_STREAM_BLOCK_SIZE * (WFC_STREAM_MAX_EXTENSIONS + 1))
+//!@}
+
+//!@name Global lock to protect global data (stream data list, next stream ID)
//!@{
-#define WFC_STREAM_NUM_OF_BUFFERS 8
-#define WFC_STREAM_NUM_OF_SOURCES_OR_MASKS 8
-#define WFC_STREAM_NUM_OF_CONTEXT_INPUTS 8
+#define GLOBAL_LOCK() do {vcos_once(&wfc_stream_initialise_once, wfc_stream_initialise); vcos_mutex_lock(&wfc_stream_global_lock);} while (0)
+#define GLOBAL_UNLOCK() do {vcos_mutex_unlock(&wfc_stream_global_lock);} while (0)
//!@}
-//!@name Stream-specific mutex
+//!@name Stream-specific mutex. Global lock must already be held when acquiring this lock.
//!@{
-#define STREAM_LOCK(stream_ptr) (platform_mutex_acquire(&stream_ptr->mutex))
-#define STREAM_UNLOCK(stream_ptr) (platform_mutex_release(&stream_ptr->mutex))
+#define STREAM_LOCK(stream_ptr) do {vcos_mutex_lock(&stream_ptr->mutex);} while (0)
+#define STREAM_UNLOCK(stream_ptr) do {vcos_mutex_unlock(&stream_ptr->mutex);} while (0)
//!@}
+//! Period in milliseconds to wait for an existing stream handle to be released
+//! when creating a new one.
+#define WFC_STREAM_RETRY_DELAY_MS 1
+//! Number of attempts allowed to create a stream with a given handle.
+#define WFC_STREAM_RETRIES 50
+
//==============================================================================
//! Top-level stream type
-typedef struct
+typedef struct WFC_STREAM_tag
{
//! Handle; may be assigned by window manager.
WFCNativeStreamType handle;
- //! Flag, indicating that the stream has been created on the server.
- bool has_been_created;
+ //! Number of times this stream has been registered in the process. Creation implies registration
+ uint32_t registrations;
- //! Flag indicating that destruction has been requested, but stream is still in use.
- bool destroy_pending;
+ //! Flag to indicate entry is no longer in use and imminently due for destruction.
+ bool to_be_deleted;
//! Mutex, for thread safety.
- PLATFORM_MUTEX_T mutex;
+ VCOS_MUTEX_T mutex;
- //! Configuration flags.
- uint32_t flags;
+ //! Configuration info.
+ WFC_STREAM_INFO_T info;
//!@brief Image providers to which this stream sends data; recorded so we do
//! not destroy this stream if it is still associated with a source or mask.
@@ -91,24 +107,37 @@ typedef struct
WFC_STREAM_REQ_RECT_CALLBACK_T req_rect_callback;
//! Argument to callback function
void *req_rect_cb_args;
+
+ //! Pointer to next stream
+ struct WFC_STREAM_tag *next;
+ //! Pointer to previous stream
+ struct WFC_STREAM_tag *prev;
} WFC_STREAM_T;
//==============================================================================
-//! Map containing all created streams.
-static KHRN_POINTER_MAP_T stream_map;
+//! Blockpool containing all created streams.
+static VCOS_BLOCKPOOL_T wfc_stream_blockpool;
//! Next stream handle, allocated by wfc_stream_get_next().
-static WFCNativeStreamType wfc_next_stream = (1 << 31);
+static WFCNativeStreamType wfc_stream_next_handle = (1 << 31);
static VCOS_LOG_CAT_T log_cat = VCOS_LOG_INIT("wfc_client_stream", WFC_LOG_LEVEL);
+//! Ensure lock and blockpool are only initialised once
+static VCOS_ONCE_T wfc_stream_initialise_once;
+//! The global (process-wide) lock
+static VCOS_MUTEX_T wfc_stream_global_lock;
+//! Pointer to the first stream data block
+static WFC_STREAM_T *wfc_stream_head;
+
//==============================================================================
//!@name Static functions
//!@{
-static bool wfc_stream_initialise(void);
-static void wfc_stream_create_internal(WFC_STREAM_T *stream_ptr, uint32_t flags);
-static WFC_STREAM_T *wfc_stream_get_ptr_or_create_placeholder(WFCNativeStreamType stream);
-static bool wfc_stream_destroy_actual(WFCNativeStreamType stream, WFC_STREAM_T *stream_ptr);
+static void wfc_stream_initialise(void);
+static WFC_STREAM_T *wfc_stream_global_lock_and_find_stream_ptr(WFCNativeStreamType stream);
+static WFC_STREAM_T *wfc_stream_create_stream_ptr(WFCNativeStreamType stream, bool allow_duplicate);
+static WFC_STREAM_T *wfc_stream_find_stream_ptr(WFCNativeStreamType stream);
+static void wfc_stream_destroy_if_ready(WFC_STREAM_T *stream_ptr);
static void *wfc_stream_rect_req_thread(void *arg);
static void wfc_client_stream_post_sem(void *cb_data);
//!@}
@@ -120,10 +149,15 @@ WFCNativeStreamType wfc_stream_get_next(void)
// In cases where the caller doesn't want to assign a stream number, provide
// one for it.
{
- WFCNativeStreamType next_stream = wfc_next_stream;
- wfc_next_stream++;
+ GLOBAL_LOCK();
+
+ WFCNativeStreamType next_stream = wfc_stream_next_handle;
+ wfc_stream_next_handle++;
+
+ GLOBAL_UNLOCK();
+
return next_stream;
-} // wfc_stream_get_next()
+}
//------------------------------------------------------------------------------
@@ -132,35 +166,58 @@ uint32_t wfc_stream_create(WFCNativeStreamType stream, uint32_t flags)
// window manager). Return zero if OK.
{
WFC_STREAM_T *stream_ptr;
+ uint32_t result = 0;
- vcos_log_trace("%s: stream 0x%x flags 0x%x", VCOS_FUNCTION, stream, flags);
+ vcos_log_info("%s: stream 0x%x flags 0x%x", VCOS_FUNCTION, stream, flags);
// Create stream
- stream_ptr = wfc_stream_get_ptr_or_create_placeholder(stream);
- if(stream_ptr == NULL) {return 1;}
+ stream_ptr = wfc_stream_create_stream_ptr(stream, false);
+ if(stream_ptr == NULL)
+ {
+ vcos_log_error("%s: unable to create data block for stream 0x%x", VCOS_FUNCTION, stream);
+ return VCOS_ENOMEM;
+ }
- STREAM_LOCK(stream_ptr);
+ uint64_t pid = vcos_process_id_current();
+ uint32_t pid_lo = (uint32_t) pid;
+ uint32_t pid_hi = (uint32_t) (pid >> 32);
+ int stream_in_use_retries = WFC_STREAM_RETRIES;
+ WFC_STREAM_INFO_T info;
+
+ memset(&info, 0, sizeof(info));
+ info.size = sizeof(info);
+ info.flags = flags;
- if(!stream_ptr->has_been_created)
+ do
{
- vcos_log_info("wfc_stream_create_from_image: stream %X", stream);
- // Stream did not previously exist.
- wfc_stream_create_internal(stream_ptr, flags);
+ stream_ptr->handle = wfc_server_stream_create_info(stream, &info, pid_lo, pid_hi);
+ vcos_log_trace("%s: server create returned 0x%x", VCOS_FUNCTION, stream_ptr->handle);
- vcos_assert(stream_ptr->handle == stream);
- } // if
+ // If a handle is re-used rapidly, it may still be in use in the server temporarily
+ // Retry after a short delay
+ if (stream_ptr->handle == WFC_INVALID_HANDLE)
+ vcos_sleep(WFC_STREAM_RETRY_DELAY_MS);
+ }
+ while (stream_ptr->handle == WFC_INVALID_HANDLE && stream_in_use_retries-- > 0);
+
+ if (stream_ptr->handle == WFC_INVALID_HANDLE)
+ {
+ // Even after the retries, stream handle was still in use. Fail.
+ vcos_log_error("%s: stream 0x%x already exists in server", VCOS_FUNCTION, stream);
+ result = VCOS_EEXIST;
+ wfc_stream_destroy_if_ready(stream_ptr);
+ }
else
{
- // Stream already exists, so nothing else to do.
- vcos_log_warn("wfc_stream_create_from_image: already exists: stream: %X", stream);
-
- vcos_assert(stream_ptr->flags == flags);
- } // else
+ vcos_assert(stream_ptr->handle == stream);
- STREAM_UNLOCK(stream_ptr);
+ stream_ptr->registrations++;
+ stream_ptr->info.flags = flags;
+ STREAM_UNLOCK(stream_ptr);
+ }
- return 0;
-} // wfc_stream_create_from_image()
+ return result;
+}
//------------------------------------------------------------------------------
@@ -170,9 +227,16 @@ WFCNativeStreamType wfc_stream_create_assign_id(uint32_t flags)
WFCNativeStreamType stream = wfc_stream_get_next();
uint32_t failure = wfc_stream_create(stream, flags);
+ if (failure == VCOS_EEXIST)
+ {
+ // If a duplicate stream exists, give it one more go with a new ID
+ stream = wfc_stream_get_next();
+ failure = wfc_stream_create(stream, flags);
+ }
+
if(failure) {return WFC_INVALID_HANDLE;}
else {return stream;}
-} // wfc_stream_create_assign_id()
+}
//------------------------------------------------------------------------------
@@ -188,10 +252,12 @@ uint32_t wfc_stream_create_req_rect
uint32_t failure;
failure = wfc_stream_create(stream, flags | WFC_STREAM_FLAGS_REQ_RECT);
+ if (failure)
+ return failure;
- WFC_STREAM_T *stream_ptr = wfc_stream_get_ptr_or_create_placeholder(stream);
-
- STREAM_LOCK(stream_ptr);
+ WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+ // Stream just created, so ought to be found
+ vcos_assert(stream_ptr);
// There's no point creating this type of stream if you don't supply a callback
// to update the src/dest rects via WF-C.
@@ -208,34 +274,40 @@ uint32_t wfc_stream_create_req_rect
STREAM_UNLOCK(stream_ptr);
- return failure;
-} // wfc_stream_create_req_rect()
+ return 0;
+}
//------------------------------------------------------------------------------
-void wfc_stream_register_source_or_mask(WFCNativeStreamType stream, bool add_source_or_mask)
+bool wfc_stream_register_source_or_mask(WFCNativeStreamType stream, bool add_source_or_mask)
// Indicate that a source or mask is now associated with this stream, or should
// now be removed from such an association.
{
- vcos_log_trace("%s: stream 0x%x add %d", VCOS_FUNCTION, stream, add_source_or_mask);
+ WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
- WFC_STREAM_T *stream_ptr = wfc_stream_get_ptr_or_create_placeholder(stream);
- bool still_exists = true;
+ if (!stream_ptr)
+ return false;
- STREAM_LOCK(stream_ptr);
+ vcos_log_trace("%s: stream 0x%x %d->%d", VCOS_FUNCTION, stream,
+ stream_ptr->num_of_sources_or_masks,
+ add_source_or_mask ? stream_ptr->num_of_sources_or_masks + 1 : stream_ptr->num_of_sources_or_masks - 1);
if(add_source_or_mask)
- {stream_ptr->num_of_sources_or_masks++;}
+ {
+ stream_ptr->num_of_sources_or_masks++;
+ STREAM_UNLOCK(stream_ptr);
+ }
else
{
if(vcos_verify(stream_ptr->num_of_sources_or_masks > 0))
{stream_ptr->num_of_sources_or_masks--;}
- still_exists = wfc_stream_destroy_actual(stream, stream_ptr);
- } // else
- if(still_exists) {STREAM_UNLOCK(stream_ptr);}
+ // Stream is unlocked by destroy_if_ready
+ wfc_stream_destroy_if_ready(stream_ptr);
+ }
-} // wfc_stream_register_off_screen()
+ return true;
+}
//------------------------------------------------------------------------------
@@ -244,9 +316,11 @@ void wfc_stream_await_buffer(WFCNativeStreamType stream)
{
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
- WFC_STREAM_T *stream_ptr = wfc_stream_get_ptr_or_create_placeholder(stream);
+ WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+ if (!stream_ptr)
+ return;
- if(vcos_verify(stream_ptr->flags & WFC_STREAM_FLAGS_BUF_AVAIL))
+ if(vcos_verify(stream_ptr->info.flags & WFC_STREAM_FLAGS_BUF_AVAIL))
{
VCOS_SEMAPHORE_T image_available_sem;
VCOS_STATUS_T status;
@@ -266,9 +340,11 @@ void wfc_stream_await_buffer(WFCNativeStreamType stream)
vcos_semaphore_delete(&image_available_sem);
wfc_server_release_keep_alive();
- } // if
+ }
-} // wfc_stream_await_buffer()
+ STREAM_UNLOCK(stream_ptr);
+
+}
//------------------------------------------------------------------------------
@@ -276,32 +352,34 @@ void wfc_stream_destroy(WFCNativeStreamType stream)
// Destroy a stream - unless it is still in use, in which case, mark it for
// destruction once all users have finished with it.
{
- vcos_log_info("wfc_stream_destroy: stream: %X", stream);
+ vcos_log_info("%s: stream: %X", VCOS_FUNCTION, stream);
- WFC_STREAM_T *stream_ptr;
+ WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
- // Look up stream
- stream_ptr = (WFC_STREAM_T *) khrn_pointer_map_lookup(&stream_map, stream);
-
- if(stream_ptr != NULL)
+ if (stream_ptr)
{
- /* If stream is still in use (i.e. it's attached to at least one source/mask
+ /* If stream is still in use (e.g. it's attached to at least one source/mask
* which is associated with at least one element) then destruction is delayed
- * until it's no longer in use.
- * Element-source/mask associations must be dealt with in wfc_client.c. */
- STREAM_LOCK(stream_ptr);
-
- stream_ptr->destroy_pending = true;
+ * until it's no longer in use. */
+ if (stream_ptr->registrations> 0)
+ {
+ stream_ptr->registrations--;
+ vcos_log_trace("%s: stream: %X ready to destroy?", VCOS_FUNCTION, stream);
+ }
+ else
+ {
+ vcos_log_error("%s: stream: %X destroyed when unregistered", VCOS_FUNCTION, stream);
+ }
- if(wfc_stream_destroy_actual(stream, stream_ptr))
- {STREAM_UNLOCK(stream_ptr);}
- } // if
+ // Stream is unlocked by destroy_if_ready
+ wfc_stream_destroy_if_ready(stream_ptr);
+ }
else
{
- vcos_log_warn("wfc_stream_destroy: stream %X doesn't exist", stream);
- } // else
+ vcos_log_warn("%s: stream %X doesn't exist", VCOS_FUNCTION, stream);
+ }
-} // wfc_stream_destroy()
+}
//------------------------------------------------------------------------------
//!@name
@@ -320,22 +398,46 @@ uint32_t wfc_stream_create_for_context_nbufs
(WFCNativeStreamType stream, uint32_t width, uint32_t height, uint32_t nbufs)
// Create a stream for an off-screen context to output to, with a specific number of buffers.
{
- // Create stream
- wfc_stream_create(stream, WFC_STREAM_FLAGS_NONE);
+ WFC_STREAM_T *stream_ptr;
+ bool stream_created = false;
+
if(!vcos_verify(stream != WFC_INVALID_HANDLE))
{return 1;}
+ stream_ptr = wfc_stream_find_stream_ptr(stream);
+ if (stream_ptr)
+ {
+ uint32_t flags = stream_ptr->info.flags;
+
+ // Stream already exists, check flags match expected
+ STREAM_UNLOCK(stream_ptr);
+
+ if (flags != WFC_STREAM_FLAGS_NONE)
+ {
+ vcos_log_error("%s: stream flags mismatch (expected 0x%x, got 0x%x)", VCOS_FUNCTION, WFC_STREAM_FLAGS_NONE, flags);
+ return 1;
+ }
+ }
+ else
+ {
+ // Create stream
+ if (wfc_stream_create(stream, WFC_STREAM_FLAGS_NONE) != 0)
+ return 1;
+ stream_created = true;
+ }
+
// Allocate buffers on the server.
if (!wfc_server_stream_allocate_images(stream, width, height, nbufs))
{
// Failed to allocate buffers
vcos_log_warn("%s: failed to allocate %u buffers for stream %X size %ux%u", VCOS_FUNCTION, nbufs, stream, width, height);
- wfc_stream_destroy(stream);
+ if (stream_created)
+ wfc_stream_destroy(stream);
return 1;
}
return 0;
-} // wfc_stream_create_from_context()
+}
//------------------------------------------------------------------------------
@@ -347,9 +449,9 @@ bool wfc_stream_used_for_off_screen(WFCNativeStreamType stream)
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
- WFC_STREAM_T *stream_ptr = wfc_stream_get_ptr_or_create_placeholder(stream);
-
- STREAM_LOCK(stream_ptr);
+ WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+ if (!stream_ptr)
+ return false;
used_for_off_screen = stream_ptr->used_for_off_screen;
@@ -357,7 +459,7 @@ bool wfc_stream_used_for_off_screen(WFCNativeStreamType stream)
return used_for_off_screen;
-} // wfc_stream_used_for_off_screen()
+}
//------------------------------------------------------------------------------
@@ -370,150 +472,289 @@ void wfc_stream_register_off_screen(WFCNativeStreamType stream, bool used_for_of
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
- WFC_STREAM_T *stream_ptr = wfc_stream_get_ptr_or_create_placeholder(stream);
- bool still_exists = true;
-
- STREAM_LOCK(stream_ptr);
+ WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+ if (!stream_ptr)
+ return;
stream_ptr->used_for_off_screen = used_for_off_screen;
- if(!used_for_off_screen)
- {still_exists = wfc_stream_destroy_actual(stream, stream_ptr);}
-
- if(still_exists) {STREAM_UNLOCK(stream_ptr);}
-
-} // wfc_stream_register_off_screen()
+ if (used_for_off_screen)
+ STREAM_UNLOCK(stream_ptr);
+ else
+ {
+ // Stream is unlocked by destroy_if_ready
+ wfc_stream_destroy_if_ready(stream_ptr);
+ }
+}
//!@} // Off-screen composition functions
//!@} // Public functions
//==============================================================================
-static bool wfc_stream_initialise(void)
-//! Initialise logging and stream_map the first time around. Return true if OK.
+/** Initialise logging and global mutex */
+static void wfc_stream_initialise(void)
{
- if(stream_map.storage == NULL) {
- // Logging
- vcos_log_set_level(&log_cat, WFC_LOG_LEVEL);
- vcos_log_register("wfc_client_stream", &log_cat);
- // Stream map
- if(!vcos_verify(khrn_pointer_map_init(&stream_map, 8)))
- return false;
- }
+ VCOS_STATUS_T status;
- return true;
-} // wfc_stream_initialise()
+ vcos_log_set_level(&log_cat, WFC_LOG_LEVEL);
+ vcos_log_register("wfc_client_stream", &log_cat);
+
+ vcos_log_trace("%s", VCOS_FUNCTION);
+
+ status = vcos_mutex_create(&wfc_stream_global_lock, "WFC stream global lock");
+ vcos_assert(status == VCOS_SUCCESS);
+
+ status = vcos_blockpool_create_on_heap(&wfc_stream_blockpool,
+ WFC_STREAM_BLOCK_SIZE, sizeof(WFC_STREAM_T),
+ VCOS_BLOCKPOOL_ALIGN_DEFAULT, VCOS_BLOCKPOOL_FLAG_NONE,
+ "wfc stream pool");
+ vcos_assert(status == VCOS_SUCCESS);
+
+ status = vcos_blockpool_extend(&wfc_stream_blockpool,
+ WFC_STREAM_MAX_EXTENSIONS, WFC_STREAM_BLOCK_SIZE);
+ vcos_assert(status == VCOS_SUCCESS);
+}
//------------------------------------------------------------------------------
-static void wfc_stream_create_internal(WFC_STREAM_T *stream_ptr, uint32_t flags)
-//! Create stream, etc.
+/** Take the global lock and then search for the stream data for a given handle.
+ * The global lock is not released on return and the stream is not locked.
+ *
+ * @param stream The stream handle.
+ * @return The pointer to the stream structure, or NULL if not found.
+ */
+static WFC_STREAM_T *wfc_stream_global_lock_and_find_stream_ptr(WFCNativeStreamType stream)
{
- stream_ptr->has_been_created = true;
- stream_ptr->flags = flags;
+ WFC_STREAM_T *stream_ptr;
- uint64_t pid = vcos_process_id_current();
- uint32_t pid_lo = (uint32_t) pid;
- uint32_t pid_hi = (uint32_t) (pid >> 32);
+ GLOBAL_LOCK();
- stream_ptr->handle = wfc_server_stream_create(stream_ptr->handle, flags, pid_lo, pid_hi);
-} // wfc_stream_create_internal()
+ stream_ptr = wfc_stream_head;
+ while (stream_ptr && stream_ptr->handle != stream)
+ stream_ptr = stream_ptr->next;
+
+ return stream_ptr;
+}
//------------------------------------------------------------------------------
-static WFC_STREAM_T *wfc_stream_get_ptr_or_create_placeholder(WFCNativeStreamType stream)
-//!@brief Return the pointer to the stream structure corresponding to the specified
-//! stream handle. If it doesn't exist, create it.
+/** Create a stream structure corresponding to the specified stream handle. If
+ * the stream structure already exists or there is an error allocating it, the
+ * function returns NULL. On success, the stream pointer is left locked.
+ *
+ * @param stream The stream handle.
+ * @param allow_duplicate True to allow an existing entry
+ * @return The pointer to the new stream structure, or NULL on error.
+ */
+static WFC_STREAM_T *wfc_stream_create_stream_ptr(WFCNativeStreamType stream, bool allow_duplicate)
{
- WFC_STREAM_T *stream_ptr = NULL;
-
- if (!wfc_stream_initialise()) return NULL;
+ WFC_STREAM_T *stream_ptr = wfc_stream_global_lock_and_find_stream_ptr(stream);
- if (khrn_pointer_map_get_count(&stream_map) == 0)
- if (wfc_server_connect() != VCOS_SUCCESS)
- return NULL;
+ vcos_log_trace("%s: stream handle 0x%x", VCOS_FUNCTION, stream);
- // Look up stream
- stream_ptr = (WFC_STREAM_T *) khrn_pointer_map_lookup(&stream_map, stream);
+ if (stream_ptr && !stream_ptr->to_be_deleted)
+ {
+ if (!allow_duplicate)
+ {
+ vcos_log_error("%s: attempt to create duplicate of stream handle 0x%x", VCOS_FUNCTION, stream);
+ // Stream already exists, return NULL
+ stream_ptr = NULL;
+ }
+ else
+ {
+ vcos_log_trace("%s: duplicate of stream handle 0x%x created", VCOS_FUNCTION, stream);
- // If it doesn't exist, then create it, and insert into the map
- if(stream_ptr == NULL)
+ STREAM_LOCK(stream_ptr);
+ }
+ }
+ else
{
- bool is_in_use = false;
- uint32_t in_use_timeout = 10;
+ if (stream_ptr)
+ {
+ vcos_log_trace("%s: recycling data block for stream handle 0x%x", VCOS_FUNCTION, stream);
+
+ // Recycle existing entry
+ stream_ptr->to_be_deleted = false;
- do
+ STREAM_LOCK(stream_ptr);
+ }
+ else
{
- // In case this stream number is being re-used, block until the server
- // side has finished destroying it, or time out otherwise.
- is_in_use = wfc_server_stream_is_in_use(stream);
- in_use_timeout--;
- if(is_in_use) {vcos_sleep(1);}
+ vcos_log_trace("%s: allocating block for stream handle 0x%x", VCOS_FUNCTION, stream);
+
+ // Create new block and insert it into the list
+ stream_ptr = vcos_blockpool_calloc(&wfc_stream_blockpool);
+
+ if (stream_ptr)
+ {
+ VCOS_STATUS_T status;
+
+ status = vcos_mutex_create(&stream_ptr->mutex, "WFC_STREAM_T mutex");
+ if (vcos_verify(status == VCOS_SUCCESS))
+ {
+ STREAM_LOCK(stream_ptr);
+
+ // First stream in this process, connect
+ if (!wfc_stream_head)
+ wfc_server_connect();
+
+ stream_ptr->handle = stream;
+ stream_ptr->info.size = sizeof(stream_ptr->info);
+
+ // Insert data into list
+ stream_ptr->next = wfc_stream_head;
+ if (wfc_stream_head)
+ wfc_stream_head->prev = stream_ptr;
+ wfc_stream_head = stream_ptr;
+ }
+ else
+ {
+ vcos_log_error("%s: unable to create mutex for stream handle 0x%x", VCOS_FUNCTION, stream);
+ vcos_blockpool_free(stream_ptr);
+ stream_ptr = NULL;
+ }
+ }
+ else
+ {
+ vcos_log_error("%s: unable to allocate data for stream handle 0x%x", VCOS_FUNCTION, stream);
+ }
}
- while(is_in_use && (in_use_timeout > 0));
+ }
+
+ GLOBAL_UNLOCK();
+
+ return stream_ptr;
+}
- if(!vcos_verify(in_use_timeout > 0))
+//------------------------------------------------------------------------------
+
+/** Destroys a stream structure identified by stream handle. If the stream is not
+ * found or the stream has not been marked for deletion, the operation has no
+ * effect.
+ *
+ * @param stream The stream handle.
+ */
+static void wfc_stream_destroy_stream_ptr(WFCNativeStreamType stream)
+{
+ WFC_STREAM_T *stream_ptr = wfc_stream_global_lock_and_find_stream_ptr(stream);
+
+ vcos_log_trace("%s: stream handle 0x%x", VCOS_FUNCTION, stream);
+
+ if (stream_ptr)
+ {
+ if (stream_ptr->to_be_deleted)
{
- vcos_log_warn("get_stream_ptr timeout");
- return NULL;
- } // if
+ STREAM_LOCK(stream_ptr);
+
+ vcos_log_trace("%s: unlinking from list", VCOS_FUNCTION);
- // Allocate memory for stream_ptr
- stream_ptr = (WFC_STREAM_T *) khrn_platform_malloc(sizeof(WFC_STREAM_T), "WFC_STREAM_T");
+ if (stream_ptr->next)
+ stream_ptr->next->prev = stream_ptr->prev;
+ if (stream_ptr->prev)
+ stream_ptr->prev->next = stream_ptr->next;
+ else
+ wfc_stream_head = stream_ptr->next;
- if(vcos_verify(stream_ptr != NULL))
+ // No streams left in this process, disconnect
+ if (wfc_stream_head == NULL)
+ wfc_server_disconnect();
+ }
+ else
{
- // Initialise new stream
- memset(stream_ptr, 0, sizeof(WFC_STREAM_T));
- platform_mutex_create(&stream_ptr->mutex);
- stream_ptr->handle = stream;
- // Insert stream into map
- khrn_pointer_map_insert(&stream_map, stream, stream_ptr);
- } // if
- } // if
+ vcos_log_trace("%s: stream 0x%x recycled before destruction", VCOS_FUNCTION, stream);
+ stream_ptr = NULL;
+ }
+ }
+ else
+ {
+ vcos_log_error("%s: stream 0x%x not found", VCOS_FUNCTION, stream);
+ }
- return stream_ptr;
-} // wfc_stream_get_ptr_or_create_placeholder()
+ GLOBAL_UNLOCK();
+
+ if (stream_ptr)
+ {
+ // Stream data block no longer in list, can safely destroy it
+ STREAM_UNLOCK(stream_ptr);
+
+ // Wait for rectangle request thread to complete
+ if(stream_ptr->info.flags & WFC_STREAM_FLAGS_REQ_RECT)
+ vcos_thread_join(&stream_ptr->rect_req_thread_data, NULL);
+
+ // Destroy mutex
+ vcos_mutex_delete(&stream_ptr->mutex);
+
+ // Delete
+ vcos_blockpool_free(stream_ptr);
+ }
+}
//------------------------------------------------------------------------------
-static bool wfc_stream_destroy_actual(WFCNativeStreamType stream, WFC_STREAM_T *stream_ptr)
-//!@brief Actually destroy the stream, _if_ it is no longer in use. Stream is already
-//! locked before this function is called. If stream was destroyed, returns FALSE.
+/** Return a pointer to the stream structure corresponding to the specified stream
+ * handle. On success, the stream pointer is locked.
+ *
+ * @param stream The stream handle.
+ * @return The pointer to the stream structure, or NULL on error.
+ */
+static WFC_STREAM_T *wfc_stream_find_stream_ptr(WFCNativeStreamType stream)
{
- if((stream_ptr == NULL)
- || !stream_ptr->destroy_pending
- || (stream_ptr->num_of_sources_or_masks > 0)
- || stream_ptr->used_for_off_screen)
- {return true;}
+ WFC_STREAM_T *stream_ptr = wfc_stream_global_lock_and_find_stream_ptr(stream);