You've already forked Microtransactions64
mirror of
https://github.com/Print-and-Panic/Microtransactions64.git
synced 2026-01-21 10:17:19 -08:00
*it still lags*
This commit is contained in:
2
Makefile
2
Makefile
@@ -230,7 +230,7 @@ ACTOR_DIR := actors
|
||||
LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h)))
|
||||
|
||||
# Directories containing source files
|
||||
SRC_DIRS := src src/usb src/engine src/game src/audio src/menu src/buffers actors levels bin data assets asm lib sound
|
||||
SRC_DIRS := src src/usb src/engine src/game src/hvqm src/audio src/menu src/buffers actors levels bin data assets asm lib sound
|
||||
BIN_DIRS := bin bin/$(VERSION)
|
||||
|
||||
# File dependencies and variables for specific files
|
||||
|
||||
5
sm64.ld
5
sm64.ld
@@ -85,6 +85,9 @@ SECTIONS
|
||||
BEGIN_NOLOAD(buffers)
|
||||
{
|
||||
BUILD_DIR/src/buffers/buffers.o(.bss*);
|
||||
BUILD_DIR/src/buffers/hvqmwork.o(.bss*);
|
||||
BUILD_DIR/src/buffers/adpcmbuf.o(.bss*);
|
||||
BUILD_DIR/src/buffers/hvqbuf.o(.bss*);
|
||||
BUILD_DIR/src/audio/globals_start.o(.bss*);
|
||||
BUILD_DIR/src/audio/synthesis.o(.bss*);
|
||||
BUILD_DIR/src/audio/heap.o(.bss*);
|
||||
@@ -116,6 +119,7 @@ SECTIONS
|
||||
BUILD_DIR/asm/entry.o(.text);
|
||||
|
||||
BUILD_DIR/src/game*.o(.text);
|
||||
BUILD_DIR/src/hvqm*.o(.text);
|
||||
#ifdef UNF
|
||||
BUILD_DIR/src/usb*.o(.text);
|
||||
#endif
|
||||
@@ -164,6 +168,7 @@ SECTIONS
|
||||
{
|
||||
BUILD_DIR/src/game*.o(.bss*);
|
||||
BUILD_DIR/src/game*.o(.sbss*);
|
||||
BUILD_DIR/src/hvqm*.o(.bss*);
|
||||
BUILD_DIR/src/usb*.o(.bss*);
|
||||
BUILD_DIR/src/usb*.o(.sbss*);
|
||||
BUILD_DIR/src/audio*.o(.bss*);
|
||||
|
||||
@@ -927,7 +927,7 @@ f32 D_EU_802298D0;
|
||||
s32 gRefreshRate;
|
||||
#endif
|
||||
|
||||
s16 *gAiBuffers[NUMAIBUFFERS];
|
||||
ALIGNED8 s16 *gAiBuffers[NUMAIBUFFERS];
|
||||
s16 gAiBufferLengths[NUMAIBUFFERS];
|
||||
|
||||
#if defined(VERSION_JP) || defined(VERSION_US)
|
||||
|
||||
23
src/buffers/adpcmbuf.c
Normal file
23
src/buffers/adpcmbuf.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* N64-HVQM2 library Sample program
|
||||
*
|
||||
* FILE : adpcmbuf.c
|
||||
*
|
||||
* Copyright (C) 1998,1999 NINTENDO Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 1999-02-22 */
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <HVQM2File.h>
|
||||
#include <macros.h>
|
||||
#include <hvqm/hvqm.h>
|
||||
|
||||
/*
|
||||
* Buffer for audio records (ADPCM data) read from the HVQM2 data.
|
||||
* (Note) Please locate at a 16byte aligned address with the spec file.
|
||||
*/
|
||||
ALIGNED16 u8 adpcmbuf[AUDIO_RECORD_SIZE_MAX];
|
||||
|
||||
/* end */
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <hvqm2dec.h>
|
||||
|
||||
#include "buffers.h"
|
||||
#include <game/hvqm.h>
|
||||
#include <hvqm/hvqm.h>
|
||||
#include "config.h"
|
||||
|
||||
ALIGNED8 u8 gDecompressionHeap[0xD000];
|
||||
@@ -42,14 +42,3 @@ ALIGNED8 u8 gAudioSPTaskYieldBuffer[OS_YIELD_AUDIO_SIZE];
|
||||
#if !defined(F3DEX_GBI_SHARED) && !defined(VERSION_EU)
|
||||
ALIGNED8 u8 gUnusedThread2Stack[0x1400];
|
||||
#endif
|
||||
|
||||
ALIGNED16 u8 hvqbuf[HVQ_DATASIZE_MAX];
|
||||
|
||||
ALIGNED16 u64 hvq_yieldbuf[HVQM2_YIELD_DATA_SIZE/8];
|
||||
ALIGNED16 u8 adpcmbuf[AUDIO_RECORD_SIZE_MAX];
|
||||
ALIGNED16 u16 hvqwork[(MAXWIDTH/8)*(MAXHEIGHT/4)*4];
|
||||
|
||||
// Data area for the HVQ microcode
|
||||
ALIGNED16 HVQM2Info hvq_spfifo[HVQ_SPFIFO_SIZE];
|
||||
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
#include "config.h"
|
||||
|
||||
// 0x70800 bytes
|
||||
u16 gFrameBuffers[3][SCREEN_WIDTH * SCREEN_HEIGHT];
|
||||
__attribute__((aligned (64))) u16 gFrameBuffers[3][SCREEN_WIDTH * SCREEN_HEIGHT];
|
||||
|
||||
24
src/buffers/hvqbuf.c
Normal file
24
src/buffers/hvqbuf.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* N64-HVQM2 library Sample program
|
||||
*
|
||||
* FILE : hvqbuf.c
|
||||
*
|
||||
* Copyright (C) 1998,1999 NINTENDO Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 1999-02-22 */
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <macros.h>
|
||||
#include <HVQM2File.h>
|
||||
#include <hvqm/hvqm.h>
|
||||
|
||||
/*
|
||||
* Buffer for video records (HVQM2 compressed data) read from
|
||||
* the HVQM2 data.
|
||||
* (Note) Please locate at a 16byte aligned address with the spec file.
|
||||
*/
|
||||
ALIGNED16 u8 hvqbuf[HVQ_DATASIZE_MAX];
|
||||
|
||||
/* end */
|
||||
43
src/buffers/hvqmwork.c
Normal file
43
src/buffers/hvqmwork.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* N64-HVQM2 library Sample program
|
||||
*
|
||||
* FILE : hvqmwork.c
|
||||
*
|
||||
* Copyright (C) 1998,1999 NINTENDO Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 1999-02-12 */
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <hvqm2dec.h>
|
||||
#include <hvqm/hvqm.h>
|
||||
|
||||
/*
|
||||
* Work area needed by the HVQM2 library
|
||||
*
|
||||
* (Note) MAXWIDTH and MAXHEIGHT are set with Makefile
|
||||
*/
|
||||
#if 0
|
||||
/*
|
||||
* If the compressed data for decoding is only in 4:1:1 format:
|
||||
*/
|
||||
u16 hvqwork[(MAXWIDTH/8)*(MAXHEIGHT/8)*6];
|
||||
#else
|
||||
/*
|
||||
* If 4:2:2 data will (also) be decoded:
|
||||
*/
|
||||
u16 hvqwork[(MAXWIDTH/8)*(MAXHEIGHT/4)*4];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Data area for the HVQ microcode
|
||||
*/
|
||||
HVQM2Info hvq_spfifo[HVQ_SPFIFO_SIZE];
|
||||
|
||||
/*
|
||||
* Buffer for RSP task yield
|
||||
*/
|
||||
u64 hvq_yieldbuf[HVQM2_YIELD_DATA_SIZE/8];
|
||||
|
||||
/* end */
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "segment2.h"
|
||||
#include "segment_symbols.h"
|
||||
#include "rumble_init.h"
|
||||
#include "hvqm.h"
|
||||
#include <hvqm/hvqm.h>
|
||||
#include "usb/usb.h"
|
||||
#include "usb/debug.h"
|
||||
#include <prevent_bss_reordering.h>
|
||||
@@ -354,7 +354,7 @@ void display_and_vsync(void) {
|
||||
|
||||
// this function records distinct inputs over a 255-frame interval to RAM locations and was likely
|
||||
// used to record the demo sequences seen in the final game. This function is unused.
|
||||
static void record_demo(void) {
|
||||
UNUSED static void record_demo(void) {
|
||||
// record the player's button mask and current rawStickX and rawStickY.
|
||||
u8 buttonMask =
|
||||
((gPlayer1Controller->buttonDown & (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON)) >> 8)
|
||||
|
||||
110
src/hvqm/cfbkeep.c
Normal file
110
src/hvqm/cfbkeep.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* N64-HVQM2 library Sample program
|
||||
*
|
||||
* FILE : cfbkeep.c (frame buffer management)
|
||||
*
|
||||
* Copyright (C) 1998,1999 NINTENDO Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 1998-12-16 */
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <HVQM2File.h>
|
||||
#include "hvqm.h"
|
||||
#include "buffers/framebuffers.h"
|
||||
|
||||
/***********************************************************************
|
||||
* Array maintaining the state of the frame buffer
|
||||
* (cfb_status[N] corresponds to the frame buffer itself cfb[N]
|
||||
***********************************************************************/
|
||||
u32 cfb_status[NUM_CFBs];
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* void init_cfb(void)
|
||||
*
|
||||
* Explanation
|
||||
* Clears all frame buffers and initializes state of frame buffer
|
||||
*
|
||||
***********************************************************************/
|
||||
void init_cfb(void) {
|
||||
int i, j;
|
||||
|
||||
for ( i = 0; i < NUM_CFBs; i++ ) {
|
||||
for ( j = 0; j < SCREEN_WD*SCREEN_HT; j++ ) gFrameBuffers[i][j] = 0;
|
||||
cfb_status[i] = CFB_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* void keep_cfb(int cfbno)
|
||||
*
|
||||
* Explanation
|
||||
* Frame buffer indicated by the index cfbno is protected by
|
||||
* being made unavailable.
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
keep_cfb( int cfbno )
|
||||
{
|
||||
cfb_status[cfbno] |= CFB_PRECIOUS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* void release_cfb(int cfbno)
|
||||
*
|
||||
* Explanation
|
||||
* Frame buffer indicated by the index cfbno is released
|
||||
* from protection.
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
release_cfb( int bufno )
|
||||
{
|
||||
if ( bufno >= 0 ) cfb_status[bufno] &= ~CFB_PRECIOUS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* void release_all_cfb(void)
|
||||
*
|
||||
* Explanation
|
||||
* All frame buffers are released from protection.
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
release_all_cfb(void)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < NUM_CFBs; i++ ) cfb_status[i] &= ~CFB_PRECIOUS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* int get_cfb()
|
||||
*
|
||||
* Explanation
|
||||
* Search for available frame buffer and return that index.
|
||||
* Thread yields until an available frame buffer is found.
|
||||
*
|
||||
* Returned value
|
||||
* The index of the available frame buffer.
|
||||
*
|
||||
***********************************************************************/
|
||||
int
|
||||
get_cfb()
|
||||
{
|
||||
int cfbno;
|
||||
|
||||
for ( ; ; ) {
|
||||
for ( cfbno = 0; cfbno < NUM_CFBs; cfbno++ )
|
||||
if ( cfb_status[cfbno] == 0 )
|
||||
return cfbno;
|
||||
osYieldThread();
|
||||
}
|
||||
}
|
||||
|
||||
/* end */
|
||||
77
src/hvqm/getrecord.c
Normal file
77
src/hvqm/getrecord.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* N64-HVQM2 library Sample program
|
||||
*
|
||||
* FILE : getrecord.c (module for reading HVQM2 records)
|
||||
*
|
||||
* Copyright (C) 1998,1999 NINTENDO Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 1999-02-22 */
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <HVQM2File.h>
|
||||
#include "hvqm.h"
|
||||
|
||||
/*
|
||||
* u8 *get_record(HVQM2Record *headerbuf, void *bodybuf,
|
||||
* u16 type, u8 *stream, OSIoMesg *mb, OSMesgQueue *mq)
|
||||
*
|
||||
* Arguments
|
||||
* headerbuf Buffer storing the record header (HVQM2Record structure)
|
||||
* bodybuf Buffer storing the record's data (record body)
|
||||
* type The requested record type
|
||||
* stream The current HVQM2 record address
|
||||
* mb I/O message block request sent to PI manager
|
||||
* mq Message queue receiving notice of DMA end from PI manager
|
||||
*
|
||||
* Explanation:
|
||||
* Finds the next record of the specified "type" from the HVQM2 data
|
||||
* address "stream" in ROM, and reads the record header into "headerbuf"
|
||||
* and the data body into "bodybuf." Specify HVQM2_AUDIO for "type" to
|
||||
* read an audio record, and specify HVQM2_VIDEO to read a video record.
|
||||
*
|
||||
* This function assumes that the reading of audio records and video
|
||||
* records is performed in parallel by separate threads. Accordingly,
|
||||
* you must prepare in advance a separate mb (I/O message block request
|
||||
* sent to PI manager) and separate mq (message queue receiving notice
|
||||
* of DMA end from PI manager) for audio records and video records.
|
||||
*
|
||||
* The reading of audio records has priority over the reading of
|
||||
* video records.
|
||||
*
|
||||
* "stream" must have 2byte alignment. Please give headerbuf and
|
||||
* bodybuf 16byte alignment to conform with the R4300 data cache line
|
||||
* size.
|
||||
*
|
||||
* Please be sure to reserve sufficient space for bodybuf.
|
||||
*
|
||||
*
|
||||
* Returned value:
|
||||
* The address of the next record
|
||||
*/
|
||||
u8 *
|
||||
get_record( HVQM2Record *headerbuf, void *bodybuf, u16 type, u8 *stream, OSIoMesg *mb, OSMesgQueue *mq )
|
||||
{
|
||||
u16 record_type;
|
||||
u32 record_size;
|
||||
s32 pri;
|
||||
|
||||
pri = (type == HVQM2_AUDIO) ? OS_MESG_PRI_HIGH : OS_MESG_PRI_NORMAL;
|
||||
for ( ; ; ) {
|
||||
romcpy( headerbuf, stream, sizeof(HVQM2Record), pri, mb, mq );
|
||||
stream += sizeof(HVQM2Record);
|
||||
record_type = load16( headerbuf->type );
|
||||
record_size = load32( headerbuf->size );
|
||||
if ( record_type == type ) break;
|
||||
stream += record_size;
|
||||
}
|
||||
|
||||
if ( record_size > 0 ) {
|
||||
romcpy( bodybuf, stream, record_size, pri, mb, mq );
|
||||
stream += record_size;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
/* end */
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <adpcmdec.h>
|
||||
#include "hvqm.h"
|
||||
|
||||
#define AUDIO_DMA_MSG_SIZE 1
|
||||
static OSIoMesg audioDmaMesgBlock;
|
||||
static OSMesgQueue audioDmaMessageQ;
|
||||
static OSMesg audioDmaMessages[AUDIO_DMA_MSG_SIZE];
|
||||
@@ -57,77 +58,6 @@ static ADPCMstate adpcm_state; /* Buffer for state information passed to the ADP
|
||||
extern u8 _capcomSegmentRomStart[];
|
||||
extern u8 _seinSegmentRomStart[];
|
||||
|
||||
u32 cfb_status[NUM_CFBs];
|
||||
|
||||
// Clears all frame buffers and initializes state of frame buffer
|
||||
void init_cfb(void) {
|
||||
int i, j;
|
||||
|
||||
for ( i = 0; i < NUM_CFBs; i++ ) {
|
||||
for ( j = 0; j < SCREEN_WD*SCREEN_HT; j++ ) gFrameBuffers[i][j] = 0;
|
||||
cfb_status[i] = CFB_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
// Frame buffer indicated by the index cfbno is protected by being made unavailable.
|
||||
void keep_cfb( int cfbno ) {
|
||||
cfb_status[cfbno] |= CFB_PRECIOUS;
|
||||
}
|
||||
|
||||
//Frame buffer indicated by the index cfbno is released from protection.
|
||||
void release_cfb( int bufno ) {
|
||||
if ( bufno >= 0 ) cfb_status[bufno] &= ~CFB_PRECIOUS;
|
||||
}
|
||||
|
||||
// All frame buffers are released from protection.
|
||||
void release_all_cfb(void) {
|
||||
int i;
|
||||
for ( i = 0; i < NUM_CFBs; i++ ) cfb_status[i] &= ~CFB_PRECIOUS;
|
||||
}
|
||||
|
||||
// Search for available frame buffer and return that index.
|
||||
// Thread yields until an available frame buffer is found.
|
||||
int get_cfb() {
|
||||
int cfbno;
|
||||
|
||||
for ( ; ; ) {
|
||||
for ( cfbno = 0; cfbno < NUM_CFBs; cfbno++ )
|
||||
if ( cfb_status[cfbno] == CFB_FREE )
|
||||
return cfbno;
|
||||
osYieldThread();
|
||||
}
|
||||
}
|
||||
|
||||
void romcpy(void *dest, void *src, u32 len, s32 pri, OSIoMesg *mb, OSMesgQueue *mq) {
|
||||
osInvalDCache(dest, (s32)len);
|
||||
while (osPiStartDma(mb, pri, OS_READ, (u32)src, dest, len, mq) == -1) {}
|
||||
osRecvMesg(mq, (OSMesg *)NULL, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
u8 *get_record(HVQM2Record *headerbuf, void *bodybuf, u16 type, u8 *stream, OSIoMesg *mb, OSMesgQueue *mq) {
|
||||
u16 record_type;
|
||||
u32 record_size;
|
||||
s32 pri, i;
|
||||
|
||||
pri = (type == HVQM2_AUDIO) ? OS_MESG_PRI_HIGH : OS_MESG_PRI_NORMAL;
|
||||
|
||||
while (1) {
|
||||
romcpy(headerbuf, stream, sizeof(HVQM2Record), pri, mb, mq);
|
||||
stream += sizeof(HVQM2Record);
|
||||
record_type = load16(headerbuf->type);
|
||||
record_size = load32(headerbuf->size);
|
||||
if (record_type == type) break;
|
||||
stream += record_size;
|
||||
}
|
||||
|
||||
if (record_size > 0) {
|
||||
romcpy(bodybuf, stream, record_size, pri, mb, mq);
|
||||
stream += record_size;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static u32 next_audio_record( void *pcmbuf ) {
|
||||
ALIGNED16 u8 header_buffer[sizeof(HVQM2Record)+16];
|
||||
HVQM2Record *record_header;
|
||||
@@ -30,26 +30,11 @@
|
||||
|
||||
#define APP_GFX_UCODE_HVQ 6 /* HVQ2 microcode */
|
||||
|
||||
#define AUDIO_DMA_MSG_SIZE 1
|
||||
|
||||
|
||||
#define CFB_FREE 0 /* Available */
|
||||
#define CFB_PRECIOUS (1<<0) /* Constrained for decoding of next frame */
|
||||
#define CFB_SHOWING (1<<1) /* Waiting to display or displaying */
|
||||
|
||||
|
||||
typedef u32 (*tkAudioProc)(void *pcmbuf);
|
||||
typedef tkAudioProc (*tkRewindProc)(void);
|
||||
|
||||
void createTimekeeper();
|
||||
void tkStart(tkRewindProc rewind, u32 samples_per_sec);
|
||||
void tkPushVideoframe(void *vaddr, u32 *statP, u64 disptime);
|
||||
u64 tkGetTime(void);
|
||||
void tkStop(void);
|
||||
void createHvqmThread(void);
|
||||
|
||||
|
||||
|
||||
#define NUM_CFBs 3
|
||||
#define STACKSIZE 0x2000
|
||||
#define PCM_CHANNELS 2 /* Number of channels */
|
||||
@@ -72,6 +57,12 @@ void createHvqmThread(void);
|
||||
#define PCMBUF_ALIGNED ((PCMBUF_SPREAD+(PCM_ALIGN-1))&(~(PCM_ALIGN-1))) /* pcmbuf[i] address is aligned */
|
||||
#define PCMBUF_SIZE 0xA00
|
||||
|
||||
/*
|
||||
* Macro for loading multi-byte data from buffer holding data from stream
|
||||
*/
|
||||
#define load32(from) (*(u32*)&(from))
|
||||
#define load16(from) (*(u16*)&(from))
|
||||
|
||||
/*
|
||||
* Thread ID and priority
|
||||
*/
|
||||
@@ -92,5 +83,36 @@ void createHvqmThread(void);
|
||||
typedef u32 (*tkAudioProc)(void *pcmbuf);
|
||||
typedef tkAudioProc (*tkRewindProc)(void);
|
||||
|
||||
void createTimekeeper();
|
||||
void tkStart(tkRewindProc rewind, u32 samples_per_sec);
|
||||
void tkPushVideoframe(void *vaddr, u32 *statP, u64 disptime);
|
||||
u64 tkGetTime(void);
|
||||
void tkStop(void);
|
||||
void createHvqmThread(void);
|
||||
|
||||
/*
|
||||
* in system.c
|
||||
*/
|
||||
void romcpy(void *dest, void *src, u32 len, s32 pri, OSIoMesg *mb, OSMesgQueue *mq);
|
||||
|
||||
/*
|
||||
* in getrecord.c
|
||||
*/
|
||||
u8 *get_record(HVQM2Record *headerbuf, void *bodybuf, u16 type, u8 *stream, OSIoMesg *mb, OSMesgQueue *mq);
|
||||
|
||||
/*
|
||||
* in cfbkeep.c
|
||||
*/
|
||||
extern u32 cfb_status[NUM_CFBs];
|
||||
|
||||
void init_cfb(void);
|
||||
void keep_cfb(int cfbno);
|
||||
void release_cfb(int cfbno);
|
||||
void release_all_cfb(void);
|
||||
int get_cfb();
|
||||
|
||||
typedef u32 (*tkAudioProc)(void *pcmbuf);
|
||||
typedef tkAudioProc (*tkRewindProc)(void);
|
||||
|
||||
|
||||
#endif // HVQM_H
|
||||
46
src/hvqm/system.c
Normal file
46
src/hvqm/system.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* N64-HVQM2 library Sample program
|
||||
*
|
||||
* FILE : system.c (boot program/system utility)
|
||||
*
|
||||
* Copyright (C) 1998,1999 NINTENDO Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 1998-12-15 */
|
||||
|
||||
#include <ultra64.h>
|
||||
#include <HVQM2File.h>
|
||||
#include "hvqm.h"
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* void romcpy(void *dest, void *src, u32 len, s32 pri, OSIoMesg *mb,
|
||||
* OSMesgQueue *mq)
|
||||
*
|
||||
* Arguments
|
||||
* dest DRAM address
|
||||
* src PI device (ROM) address
|
||||
* len Transfer length (bytes)
|
||||
* pri Priority of the transfer request
|
||||
* mb I/O message block request
|
||||
* mq Message queue receiving notification of end of DMA
|
||||
*
|
||||
* Explanation
|
||||
* DMA transfers "len" bytes from ROM address "SRC" to DRAM
|
||||
* address "dest" and returns after waiting for end of DMA. The
|
||||
* data cache of the transfer destination in DRAM is invalidated
|
||||
* ahead of time.
|
||||
*
|
||||
* The parameters have the same meaning as for osPiStartDma()
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
romcpy(void *dest, void *src, u32 len, s32 pri, OSIoMesg *mb, OSMesgQueue *mq)
|
||||
{
|
||||
osInvalDCache( dest, (s32)len );
|
||||
while ( osPiStartDma( mb, pri, OS_READ, (u32)src, dest, len, mq ) == -1 ) {}
|
||||
osRecvMesg( mq, (OSMesg *)NULL, OS_MESG_BLOCK );
|
||||
}
|
||||
|
||||
/* end */
|
||||
@@ -1,42 +1,9 @@
|
||||
#include <ultra64.h>
|
||||
#include <HVQM2File.h>
|
||||
#include "hvqm.h"
|
||||
#include "audio/data.h"
|
||||
#include "buffers/framebuffers.h"
|
||||
|
||||
#define NUM_CFBs 3
|
||||
#define STACKSIZE 0x2000
|
||||
#define PCM_CHANNELS 2 /* Number of channels */
|
||||
#define PCM_CHANNELS_SHIFT 1 /* log2(PCM_CHANNELS) */
|
||||
#define PCM_ALIGN 2 /* Alignment of number of samples to send */
|
||||
#define PCM_BYTES_PER_SAMPLE (2 * PCM_CHANNELS) /* Number of bytes in one sample */
|
||||
#define PCM_BYTES_PER_SAMPLE_SHIFT 2 /* log2(PCM_BYTES_PER_SAMPLE) */
|
||||
|
||||
/*
|
||||
* Audio record definitions
|
||||
*/
|
||||
#define AUDIO_SAMPLE_BITS 4
|
||||
#define AUDIO_SAMPLES_MAX (((AUDIO_RECORD_SIZE_MAX-sizeof(HVQM2Audio))*8/AUDIO_SAMPLE_BITS)+1) /* Maximum number of records per sample */
|
||||
|
||||
/*
|
||||
* Thread ID and priority
|
||||
*/
|
||||
#define IDLE_THREAD_ID 1
|
||||
#define MAIN_THREAD_ID 3
|
||||
#define HVQM_THREAD_ID 7
|
||||
#define TIMEKEEPER_THREAD_ID 8
|
||||
#define DA_COUNTER_THREAD_ID 9
|
||||
|
||||
#define IDLE_PRIORITY 10
|
||||
#define MAIN_PRIORITY 10
|
||||
#define HVQM_PRIORITY 11
|
||||
#define TIMEKEEPER_PRIORITY 12
|
||||
#define DA_COUNTER_PRIORITY 13
|
||||
|
||||
#define PI_COMMAND_QUEUE_SIZE 4
|
||||
|
||||
typedef u32 (*tkAudioProc)(void *pcmbuf);
|
||||
typedef tkAudioProc (*tkRewindProc)(void);
|
||||
|
||||
/***********************************************************************
|
||||
* Timekeeper thread
|
||||
***********************************************************************/
|
||||
@@ -158,14 +125,22 @@ static u64 samples_played;
|
||||
***********************************************************************/
|
||||
static OSTime last_time;
|
||||
|
||||
#define OS_CLOCK_RATE 62500000LL
|
||||
#define OS_CPU_COUNTER (OS_CLOCK_RATE*3/4)
|
||||
#define OS_NSEC_TO_CYCLES(n) (((u64)(n)*(OS_CPU_COUNTER/15625000LL))/(1000000000LL/15625000LL))
|
||||
#define OS_USEC_TO_CYCLES(n) (((u64)(n)*(OS_CPU_COUNTER/15625LL))/(1000000LL/15625LL))
|
||||
#define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL))
|
||||
#define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL))
|
||||
|
||||
u64 tkGetTime(void) {
|
||||
/***********************************************************************
|
||||
*
|
||||
* u64 tkGetTime(void)
|
||||
*
|
||||
* Explanation
|
||||
* The time that has passed since the start of HVQM2 movie playback
|
||||
* is calculated back from the number of samples that have finished
|
||||
* playing (samples_played) and the sampling rate (samples_per_sec).
|
||||
* The time after samples_played was first updated is supplemented
|
||||
* with osGetTime().
|
||||
*
|
||||
* Returned value
|
||||
* The time that has passed since playback of the HVQM2 movie started
|
||||
*
|
||||
***********************************************************************/
|
||||
u64 tkGetTime(void){
|
||||
u64 retval;
|
||||
|
||||
if (!clock_alive) return 0;
|
||||
@@ -175,28 +150,62 @@ u64 tkGetTime(void) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void tkClockDisable(void) {
|
||||
clock_alive = 0;
|
||||
/***********************************************************************
|
||||
*
|
||||
* void tkClockDisable(void)
|
||||
*
|
||||
* Explanation
|
||||
* Disable measurement of time from start of HVQM2 movie playback
|
||||
*
|
||||
***********************************************************************/
|
||||
static void tkClockDisable(void)
|
||||
{
|
||||
clock_alive = 0;
|
||||
}
|
||||
|
||||
static void tkClockStart(void) {
|
||||
samples_played = 0;
|
||||
/***********************************************************************
|
||||
*
|
||||
* void tkClockStart(void)
|
||||
*
|
||||
* Explanation
|
||||
* Start measurement of time from start of HVQM2 movie playback
|
||||
*
|
||||
***********************************************************************/
|
||||
static void tkClockStart(void)
|
||||
{
|
||||
samples_played = 0;
|
||||
last_time = osGetTime();
|
||||
clock_alive = 1;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* daCounterProc - Audio DA counter thread procedure
|
||||
*
|
||||
* Counts the number of audio samples that have finished playing.
|
||||
*
|
||||
***********************************************************************/
|
||||
static void daCounterProc(void UNUSED*argument)
|
||||
{
|
||||
for ( ; ; ) {
|
||||
osRecvMesg( &aiMessageQ, NULL, OS_MESG_BLOCK );
|
||||
last_time = osGetTime();
|
||||
clock_alive = 1;
|
||||
if ( aiDAsamples > 0 ) --pcmBufferCount;
|
||||
samples_played += aiDAsamples;
|
||||
aiDAsamples = aiFIFOsamples;
|
||||
aiFIFOsamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void daCounterProc(void *argument) {
|
||||
while (1) {
|
||||
osRecvMesg( &aiMessageQ, NULL, OS_MESG_BLOCK );
|
||||
last_time = osGetTime();
|
||||
if (aiDAsamples > 0) --pcmBufferCount;
|
||||
samples_played += aiDAsamples;
|
||||
aiDAsamples = aiFIFOsamples;
|
||||
aiFIFOsamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void timekeeperProc(void *argument) {
|
||||
/***********************************************************************
|
||||
*
|
||||
* timekeeperProc - Timekeeper thread procedure
|
||||
*
|
||||
* Plays the HVQM2 movie's audio records and takes charge of
|
||||
* completed frame buffers, displaying them at the scheduled times.
|
||||
*
|
||||
***********************************************************************/
|
||||
static void timekeeperProc(void UNUSED*argument) {
|
||||
TKCMD *cmd;
|
||||
void *showing_cfb = NULL; /* Frame buffer being displayed */
|
||||
u32 *showing_cfb_statP = NULL; /* Pointer to state flag of the frame buffer being displayed */
|
||||
@@ -211,6 +220,7 @@ static void timekeeperProc(void *argument) {
|
||||
tkAudioProc audioproc;
|
||||
OSTime present_vtime;
|
||||
|
||||
/* Acquire retrace event */
|
||||
osCreateMesgQueue( &viMessageQ, viMessages, VI_MSG_SIZE );
|
||||
osViSetEvent( &viMessageQ, 0, 1 );
|
||||
|
||||
@@ -228,9 +238,12 @@ static void timekeeperProc(void *argument) {
|
||||
|
||||
osRecvMesg(&tkCmdMesgQ, (OSMesg *)&cmd, OS_MESG_BLOCK);
|
||||
|
||||
while (cmd == NULL) {
|
||||
osSendMesg(&tkResMesgQ, NULL, OS_MESG_BLOCK);
|
||||
osRecvMesg(&tkCmdMesgQ, (OSMesg *)&cmd, OS_MESG_BLOCK);
|
||||
/*
|
||||
* Wait for movie playback command
|
||||
*/
|
||||
while ( cmd == NULL ) {
|
||||
osSendMesg( &tkResMesgQ, NULL, OS_MESG_BLOCK );
|
||||
osRecvMesg( &tkCmdMesgQ, (OSMesg *)&cmd, OS_MESG_BLOCK );
|
||||
}
|
||||
|
||||
tkClockDisable();
|
||||
@@ -259,7 +272,7 @@ static void timekeeperProc(void *argument) {
|
||||
next_pcmbufno = 0;
|
||||
pcm_mod_samples = 0;
|
||||
|
||||
osSendMesg(&tkResMesgQ, NULL, OS_MESG_BLOCK);
|
||||
osSendMesg( &tkResMesgQ, NULL, OS_MESG_BLOCK ); /* Notification that playback preparations are finished */
|
||||
|
||||
present_vtime = osGetTime();
|
||||
|
||||
@@ -267,7 +280,9 @@ static void timekeeperProc(void *argument) {
|
||||
!audio_done || audioRingCount > 0 || aiFIFOsamples > 0) {
|
||||
u64 present_time;
|
||||
OSTime last_vtime;
|
||||
|
||||
/*
|
||||
* Block until retrace comes
|
||||
*/
|
||||
osRecvMesg(&viMessageQ, NULL, OS_MESG_BLOCK);
|
||||
|
||||
last_vtime = present_vtime;
|
||||
@@ -297,89 +312,118 @@ static void timekeeperProc(void *argument) {
|
||||
pushed_cfb_statP = NULL;
|
||||
}
|
||||
|
||||
if ( video_started || audioRingCount > 0 || audio_done ) {
|
||||
while ( videoRingCount ) {
|
||||
void *next_cfb;
|
||||
if ( videoRing[videoRingRead].disptime > present_time ) break;
|
||||
if ( pushed_cfb_statP != NULL ) *pushed_cfb_statP &= ~CFB_SHOWING;
|
||||
pushed_cfb = videoRing[videoRingRead].vaddr;
|
||||
pushed_cfb_statP = videoRing[videoRingRead].statP;
|
||||
*pushed_cfb_statP |= CFB_SHOWING;
|
||||
osViSwapBuffer( pushed_cfb );
|
||||
if ( ++videoRingRead == VIDEO_RING_SIZE ) videoRingRead = 0;
|
||||
--videoRingCount;
|
||||
}
|
||||
/*
|
||||
* Push the next frame buffer to the VI
|
||||
*
|
||||
* Before the start of video display (video_started == 0),
|
||||
* wait until audio data is prepared for playback
|
||||
* (audioRingCount > 0).
|
||||
*/
|
||||
if ( video_started || audioRingCount > 0 || audio_done ) {
|
||||
while ( videoRingCount ) {
|
||||
if ( videoRing[videoRingRead].disptime > present_time ) break;
|
||||
if ( pushed_cfb_statP != NULL ) *pushed_cfb_statP &= ~CFB_SHOWING;
|
||||
pushed_cfb = videoRing[videoRingRead].vaddr;
|
||||
pushed_cfb_statP = videoRing[videoRingRead].statP;
|
||||
*pushed_cfb_statP |= CFB_SHOWING;
|
||||
osViSwapBuffer( pushed_cfb );
|
||||
if ( ++videoRingRead == VIDEO_RING_SIZE ) videoRingRead = 0;
|
||||
--videoRingCount;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Push the next PCM data to the AI
|
||||
*
|
||||
* Before the start of video display (video_started == 0)
|
||||
* wait until the display of the first image frame
|
||||
* has begun (video_started == 1).
|
||||
*/
|
||||
if ( video_started ) {
|
||||
osSetThreadPri( NULL, (OSPri)(DA_COUNTER_PRIORITY + 1) );
|
||||
while ( audioRingCount > 0 && aiFIFOsamples == 0 ) {
|
||||
void *buffer = audioRing[audioRingRead].buf;
|
||||
u32 length = audioRing[audioRingRead].len;
|
||||
if ( osAiGetStatus() & AI_STATUS_FIFO_FULL ) break;
|
||||
if ( osAiSetNextBuffer( buffer, length ) == -1 ) break;
|
||||
aiFIFOsamples = length >> PCM_BYTES_PER_SAMPLE_SHIFT;
|
||||
if ( ! audio_started ) {
|
||||
/*
|
||||
* Audio playback has begun.
|
||||
* Here the time count starts to synchronize audio and video
|
||||
*/
|
||||
audio_started = 1;
|
||||
tkClockStart();
|
||||
}
|
||||
|
||||
if ( video_started ) {
|
||||
osSetThreadPri( NULL, (OSPri)(DA_COUNTER_PRIORITY + 1) );
|
||||
while ( audioRingCount > 0 && aiFIFOsamples == 0 ) {
|
||||
void *buffer = audioRing[audioRingRead].buf;
|
||||
u32 length = audioRing[audioRingRead].len;
|
||||
//!if ( osAiGetStatus() & AI_STATUS_AI_FULL ) break;
|
||||
if ( osAiSetNextBuffer( buffer, length ) == -1 ) break;
|
||||
aiFIFOsamples = length >> PCM_BYTES_PER_SAMPLE_SHIFT;
|
||||
if ( ! audio_started ) {
|
||||
/*
|
||||
* Audio playback has begun.
|
||||
* Here the time count starts to synchronize audio and video
|
||||
*/
|
||||
audio_started = 1;
|
||||
tkClockStart();
|
||||
}
|
||||
if ( ++audioRingRead == AUDIO_RING_BUFFER_SIZE ) audioRingRead = 0;
|
||||
--audioRingCount;
|
||||
}
|
||||
osSetThreadPri( NULL, (OSPri)TIMEKEEPER_PRIORITY );
|
||||
}
|
||||
|
||||
if ( ! audio_done && audioRingCount < AUDIO_RING_BUFFER_SIZE && pcmBufferCount < NUM_PCMBUFs ) {
|
||||
u32 samples;
|
||||
u32 length;
|
||||
void *buffer;
|
||||
s16 *sp, *dp;
|
||||
int i;
|
||||
if ( ++audioRingRead == AUDIO_RING_BUFFER_SIZE ) audioRingRead = 0;
|
||||
--audioRingCount;
|
||||
}
|
||||
osSetThreadPri( NULL, (OSPri)TIMEKEEPER_PRIORITY );
|
||||
}
|
||||
/*
|
||||
* Prepare the next PCM data
|
||||
*/
|
||||
if ( ! audio_done && audioRingCount < AUDIO_RING_BUFFER_SIZE && pcmBufferCount < NUM_PCMBUFs ) {
|
||||
u32 samples;
|
||||
u32 length;
|
||||
void *buffer;
|
||||
s16 *sp, *dp;
|
||||
int i;
|
||||
|
||||
samples = audioproc( &gAiBuffers[next_pcmbufno][pcm_mod_samples<<PCM_CHANNELS_SHIFT] );
|
||||
samples = audioproc( &gAiBuffers[next_pcmbufno][pcm_mod_samples<<PCM_CHANNELS_SHIFT] );
|
||||
|
||||
if ( samples > 0 ) {
|
||||
++pcmBufferCount;
|
||||
if ( samples > 0 ) {
|
||||
++pcmBufferCount;
|
||||
|
||||
sp = pcmModBuf;
|
||||
dp = (s16 *)((u8 *)gAiBuffers[next_pcmbufno]);
|
||||
i = pcm_mod_samples << PCM_CHANNELS_SHIFT;
|
||||
while ( i-- ) *dp++ = *sp++;
|
||||
samples += pcm_mod_samples;
|
||||
samples -= (pcm_mod_samples = samples & (PCM_ALIGN-1));
|
||||
length = samples << PCM_BYTES_PER_SAMPLE_SHIFT;
|
||||
buffer = gAiBuffers[next_pcmbufno];
|
||||
osWritebackDCache( buffer, length );
|
||||
audioRing[audioRingWrite].buf = buffer;
|
||||
audioRing[audioRingWrite].len = length;
|
||||
if ( ++audioRingWrite == AUDIO_RING_BUFFER_SIZE ) audioRingWrite = 0;
|
||||
++audioRingCount;
|
||||
sp = pcmModBuf;
|
||||
dp = (s16 *)((u8 *)gAiBuffers[next_pcmbufno]);
|
||||
i = pcm_mod_samples << PCM_CHANNELS_SHIFT;
|
||||
while ( i-- ) *dp++ = *sp++;
|
||||
samples += pcm_mod_samples;
|
||||
samples -= (pcm_mod_samples = samples & (PCM_ALIGN-1));
|
||||
length = samples << PCM_BYTES_PER_SAMPLE_SHIFT;
|
||||
buffer = gAiBuffers[next_pcmbufno];
|
||||
osWritebackDCache( buffer, length );
|
||||
audioRing[audioRingWrite].buf = buffer;
|
||||
audioRing[audioRingWrite].len = length;
|
||||
if ( ++audioRingWrite == AUDIO_RING_BUFFER_SIZE ) audioRingWrite = 0;
|
||||
++audioRingCount;
|
||||
|
||||
sp = (s16 *)((u8 *)(gAiBuffers[next_pcmbufno]) + length);
|
||||
dp = pcmModBuf;
|
||||
i = pcm_mod_samples << PCM_CHANNELS_SHIFT;
|
||||
while ( i-- ) *dp++ = *sp++;
|
||||
sp = (s16 *)((u8 *)(gAiBuffers[next_pcmbufno]) + length);
|
||||
dp = pcmModBuf;
|
||||
i = pcm_mod_samples << PCM_CHANNELS_SHIFT;
|
||||
while ( i-- ) *dp++ = *sp++;
|
||||
|
||||
if ( ++next_pcmbufno >= NUM_PCMBUFs ) next_pcmbufno = 0;
|
||||
}
|
||||
else audio_done = 1;
|
||||
}
|
||||
if ( ++next_pcmbufno >= NUM_PCMBUFs ) next_pcmbufno = 0;
|
||||
}
|
||||
else audio_done = 1;
|
||||
}
|
||||
|
||||
//! Push audio
|
||||
|
||||
//! Prepare audio
|
||||
|
||||
if (osRecvMesg(&tkCmdMesgQ, (OSMesg *)&cmd, OS_MESG_NOBLOCK) == 0) {
|
||||
video_done = 1;
|
||||
}
|
||||
if ( osRecvMesg( &tkCmdMesgQ, (OSMesg *)&cmd, OS_MESG_NOBLOCK ) == 0 )
|
||||
{
|
||||
/*
|
||||
* tkStop() or tkStart() has been executed
|
||||
*
|
||||
* Set 1 in video_done and end this playback loop
|
||||
* after playback of the current movie's video and
|
||||
* and audio has completely finished.
|
||||
*/
|
||||
video_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createTimekeeper(void) {
|
||||
/***********************************************************************
|
||||
*
|
||||
* void createTimekeeper(void)
|
||||
*
|
||||
* Explanation
|
||||
* Creates and starts the timekeeper thread
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
createTimekeeper(void)
|
||||
{
|
||||
osCreateMesgQueue( &tkCmdMesgQ, &tkCmdMesgBuf, 1 );
|
||||
osCreateMesgQueue( &tkResMesgQ, &tkResMesgBuf, 1 );
|
||||
osCreateThread( &tkThread, TIMEKEEPER_THREAD_ID, timekeeperProc,
|
||||
@@ -388,7 +432,27 @@ void createTimekeeper(void) {
|
||||
osStartThread( &tkThread );
|
||||
}
|
||||
|
||||
void tkStart( tkRewindProc rewind, u32 samples_per_sec ) {
|
||||
/***********************************************************************
|
||||
*
|
||||
* void tkStart(tkRewindProc rewind, u32 samples_per_sec)
|
||||
*
|
||||
* Argument
|
||||
* rewind Pointer to movie rewind callback function
|
||||
*
|
||||
* Explanation
|
||||
* Directs the timekeeper to play a new movie. Playback of the
|
||||
* movie starts after callback of "rewind" by the timekeeper. After
|
||||
* this, the HVQM2 video records are read and decoded and the
|
||||
* completed frame buffers are handed over to the timekeeper by
|
||||
* tkPushVideoframe() in succession to play the video part of the movie.
|
||||
* As for the audio, the timekeeper itself calls the callback
|
||||
* function (the value returned by rewind) that gets the PCM data as
|
||||
* needed to playback the audio.
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
tkStart( tkRewindProc rewind, u32 samples_per_sec )
|
||||
{
|
||||
TKCMD tkcmd;
|
||||
tkcmd.samples_per_sec = samples_per_sec;
|
||||
tkcmd.rewind = rewind;
|
||||
@@ -396,12 +460,53 @@ void tkStart( tkRewindProc rewind, u32 samples_per_sec ) {
|
||||
osRecvMesg( &tkResMesgQ, (OSMesg *)NULL, OS_MESG_BLOCK );
|
||||
}
|
||||
|
||||
void tkStop( void ) {
|
||||
/***********************************************************************
|
||||
*
|
||||
* void tkStop(void)
|
||||
*
|
||||
* Explanation
|
||||
* Stops the timekeeper. However, the timekeeper continues to
|
||||
* run until playback of the audio of the playing movie is complete.
|
||||
* To stop the stream in mid-stream, make 0 the value returned by
|
||||
* the callback function that reads audio and is called from the
|
||||
* timekeeper, and then execute tkStop().
|
||||
*
|
||||
* To immediately start the playback of a new movie, it is OK to
|
||||
* to execute tkStart() without executing tkStop().
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
tkStop( void )
|
||||
{
|
||||
osSendMesg( &tkCmdMesgQ, (OSMesg *)NULL, OS_MESG_BLOCK );
|
||||
osRecvMesg( &tkResMesgQ, (OSMesg *)NULL, OS_MESG_BLOCK );
|
||||
}
|
||||
|
||||
void tkPushVideoframe( void *vaddr, u32 *statP, u64 disptime ) {
|
||||
/***********************************************************************
|
||||
*
|
||||
* void tkPushVideoframe(void *vaddr, u32 *statP, u64 disptime)
|
||||
*
|
||||
* Argument
|
||||
* vaddr Frame buffer address
|
||||
* statP Pointer to state flag data regarding vaddr
|
||||
* disptime Display time
|
||||
*
|
||||
* Explanation
|
||||
* Entrusts the completed frame buffer vaddr to the timekeeper.
|
||||
* The timekeeper displays the frame buffer after waiting for the
|
||||
* "disptime" amount of time to pass from the start of the movie.
|
||||
*
|
||||
* To wait for the display of the vaddr frame buffer or to
|
||||
* indicate that something is being displayed, the CFB_SHOWING
|
||||
* flag is set in the u32 type data pointed to by the statP pointer.
|
||||
* At the time when display of vaddr is finished, (once its display
|
||||
* is over and display has switched to another frame buffer) this
|
||||
* flag is cleared by the timekeeper.
|
||||
*
|
||||
***********************************************************************/
|
||||
void
|
||||
tkPushVideoframe( void *vaddr, u32 *statP, u64 disptime )
|
||||
{
|
||||
*statP |= CFB_SHOWING;
|
||||
while ( videoRingCount >= VIDEO_RING_SIZE ) osYieldThread();
|
||||
videoRing[videoRingWrite].disptime = disptime;
|
||||
Reference in New Issue
Block a user