void Line( int x1, int y1, int x2, int y2, int col ) { if ( x1 > x2 ) _iswap( &x1, &x2 ); if ( y1 > y2 ) _iswap( &y1, &y2 ); if ( y1 == y2 ) SCANLINE( x1, x2, y1, col ); else _LINE( x1, y1, x2, y2, col ); }
void Solid_Box( int x1, int y1, int x2, int y2, int col ) { int i; if ( x1 > x2 ) _iswap( &x1, &x2 ); if ( y1 > y2 ) _iswap( &y1, &y2 ); for ( i = y1; i <= y2; i++ ) { SCANLINE( x1, x2, i, col ); } }
/* Generate code for a section of the mask. first is the index we start * at, we set last to the index of the last one we use before we run * out of intermediates / constants / parameters / sources or mask * coefficients. * * 0 for success, -1 on error. */ static int vips_reducev_compile_section( VipsReducev *reducev, Pass *pass, gboolean first ) { VipsVector *v; int i; #ifdef DEBUG_COMPILE printf( "starting pass %d\n", pass->first ); #endif /*DEBUG_COMPILE*/ pass->vector = v = vips_vector_new( "reducev", 1 ); /* We have two destinations: the final output image (8-bit) and the * intermediate buffer if this is not the final pass (16-bit). */ pass->d2 = vips_vector_destination( v, "d2", 2 ); /* "r" is the array of sums from the previous pass (if any). */ pass->r = vips_vector_source_name( v, "r", 2 ); /* The value we fetch from the image, the accumulated sum. */ TEMP( "value", 2 ); TEMP( "sum", 2 ); /* Init the sum. If this is the first pass, it's a constant. If this * is a later pass, we have to init the sum from the result * of the previous pass. */ if( first ) { char c0[256]; CONST( c0, 0, 2 ); ASM2( "loadpw", "sum", c0 ); } else ASM2( "loadw", "sum", "r" ); for( i = pass->first; i < reducev->n_point; i++ ) { char source[256]; char coeff[256]; SCANLINE( source, i, 1 ); /* This mask coefficient. */ vips_snprintf( coeff, 256, "p%d", i ); pass->p[pass->n_param] = PARAM( coeff, 2 ); pass->n_param += 1; if( pass->n_param >= MAX_PARAM ) return( -1 ); /* Mask coefficients are 2.6 bits fixed point. We need to hold * about -0.5 to 1.0, so -2 to +1.999 is as close as we can * get. * * We need a signed multiply, so the image pixel needs to * become a signed 16-bit value. We know only the bottom 8 bits * of the image and coefficient are interesting, so we can take * the bottom bits of a 16x16->32 multiply. * * We accumulate the signed 16-bit result in sum. */ ASM2( "convubw", "value", source ); ASM3( "mullw", "value", "value", coeff ); ASM3( "addssw", "sum", "sum", "value" ); /* We've used this coeff. */ pass->last = i; if( vips_vector_full( v ) ) break; /* orc 0.4.24 and earlier hate more than about five lines at * once :( */ if( i - pass->first > 3 ) break; } /* If this is the end of the mask, we write the 8-bit result to the * image, otherwise write the 16-bit intermediate to our temp buffer. */ if( pass->last >= reducev->n_point - 1 ) { char c32[256]; char c6[256]; char c0[256]; char c255[256]; CONST( c32, 32, 2 ); ASM3( "addw", "sum", "sum", c32 ); CONST( c6, 6, 2 ); ASM3( "shrsw", "sum", "sum", c6 ); /* You'd think "convsuswb", convert signed 16-bit to unsigned * 8-bit with saturation, would be quicker, but it's a lot * slower. */ CONST( c0, 0, 2 ); ASM3( "maxsw", "sum", c0, "sum" ); CONST( c255, 255, 2 ); ASM3( "minsw", "sum", c255, "sum" ); ASM2( "convwb", "d1", "sum" ); } else ASM2( "copyw", "d2", "sum" ); if( !vips_vector_compile( v ) ) return( -1 ); #ifdef DEBUG_COMPILE printf( "done coeffs %d to %d\n", pass->first, pass->last ); vips_vector_print( v ); #endif /*DEBUG_COMPILE*/ return( 0 ); }
/* Generate code for a section of the mask. first is the index we start * at, we set last to the index of the last one we use before we run * out of intermediates / constants / parameters / sources or mask * coefficients. * * 0 for success, -1 on error. */ static int pass_compile_section( Pass *pass, Morph *morph, gboolean first_pass ) { INTMASK *mask = morph->mask; const int n_mask = mask->xsize * mask->ysize; VipsVector *v; char offset[256]; char source[256]; char zero[256]; char one[256]; int i; pass->vector = v = vips_vector_new( "morph", 1 ); /* The value we fetch from the image, the accumulated sum. */ TEMP( "value", 1 ); TEMP( "sum", 1 ); CONST( zero, 0, 1 ); CONST( one, 255, 1 ); /* Init the sum. If this is the first pass, it's a constant. If this * is a later pass, we have to init the sum from the result * of the previous pass. */ if( first_pass ) { if( morph->op == DILATE ) ASM2( "copyb", "sum", zero ); else ASM2( "copyb", "sum", one ); } else { /* "r" is the result of the previous pass. */ pass->r = vips_vector_source_name( v, "r", 1 ); ASM2( "loadb", "sum", "r" ); } for( i = pass->first; i < n_mask; i++ ) { int x = i % mask->xsize; int y = i / mask->xsize; /* Exclude don't-care elements. */ if( mask->coeff[i] == 128 ) continue; /* The source. sl0 is the first scanline in the mask. */ SCANLINE( source, y, 1 ); /* The offset, only for non-first-columns though. */ if( x > 0 ) { CONST( offset, morph->in->Bands * x, 1 ); ASM3( "loadoffb", "value", source, offset ); } else ASM2( "loadb", "value", source ); /* Join to our sum. If the mask element is zero, we have to * add an extra negate. */ if( morph->op == DILATE ) { if( !mask->coeff[i] ) ASM3( "xorb", "value", "value", one ); ASM3( "orb", "sum", "sum", "value" ); } else { if( !mask->coeff[i] ) ASM3( "andnb", "sum", "sum", "value" ); else ASM3( "andb", "sum", "sum", "value" ); } if( vips_vector_full( v ) ) break; } pass->last = i; ASM2( "copyb", "d1", "sum" ); if( !vips_vector_compile( v ) ) return( -1 ); #ifdef DEBUG printf( "done matrix coeffs %d to %d\n", pass->first, pass->last ); vips_vector_print( v ); #endif /*DEBUG*/ return( 0 ); }
static void do_hs_fall(void) { /* Finish rendering previous scanline */ #ifdef HAVE_GP32 /* GP32 renders 4 scanlines at once */ if (frame == 0 && scanline >= VDG_ACTIVE_AREA_START && scanline < VDG_ACTIVE_AREA_END && (scanline & 3) == ((VDG_ACTIVE_AREA_START+3)&3) ) { video_module->render_scanline(); } #elif defined (HAVE_NDS) if (scanline >= VDG_ACTIVE_AREA_START && scanline < VDG_ACTIVE_AREA_END) { render_scanline(); sam_vdg_hsync(); } #elif !defined(HAVE_NDS) /* NDS video module does its own thing */ /* Normal code */ if (frame == 0 && scanline >= (VDG_TOP_BORDER_START + 1)) { if (scanline < VDG_ACTIVE_AREA_START) { video_module->render_border(); } else if (scanline < VDG_ACTIVE_AREA_END) { render_scanline(); sam_vdg_hsync(); video_module->hsync(); } else if (scanline < (VDG_BOTTOM_BORDER_END - 2)) { video_module->render_border(); } } #endif /* Next scanline */ scanline = (scanline + 1) % VDG_FRAME_DURATION; scanline_start = hs_fall_event.at_cycle; SET_BEAM_POS(0); PIA_RESET_Cx1(PIA0.a); #ifdef FAST_VDG /* Faster, less accurate timing for GP32/NDS */ PIA_SET_Cx1(PIA0.a); #else /* Everything else schedule HS rise for later */ hs_rise_event.at_cycle = scanline_start + VDG_HS_RISING_EDGE; event_queue(&MACHINE_EVENT_LIST, &hs_rise_event); #endif hs_fall_event.at_cycle = scanline_start + VDG_LINE_DURATION; /* Frame sync */ if (scanline == SCANLINE(VDG_VBLANK_START)) { sam_vdg_fsync(); #ifndef HAVE_NDS frame--; if (frame < 0) frame = xroar_frameskip; if (frame == 0) video_module->vdg_vsync(); #else scanline_data_ptr = scanline_data; #endif } #ifndef FAST_VDG /* Enable mode changes at beginning of active area */ if (scanline == SCANLINE(VDG_ACTIVE_AREA_START)) { inhibit_mode_change = 0; vdg_set_mode(); } #endif /* FS falling edge at end of this scanline */ if (scanline == SCANLINE(VDG_ACTIVE_AREA_END - 1)) { #ifdef HAVE_NDS nds_update_screen = 1; #endif fs_fall_event.at_cycle = scanline_start + VDG_LINE_DURATION; event_queue(&MACHINE_EVENT_LIST, &fs_fall_event); } #ifndef FAST_VDG /* Disable mode changes after end of active area */ if (scanline == SCANLINE(VDG_ACTIVE_AREA_END)) { inhibit_mode_change = 1; } #endif /* PAL delay 24 lines after FS falling edge */ if (IS_PAL && (scanline == SCANLINE(VDG_ACTIVE_AREA_END + 23))) { hs_fall_event.at_cycle += 25 * VDG_PAL_PADDING_LINE; } /* FS rising edge at end of this scanline */ if (scanline == SCANLINE(VDG_ACTIVE_AREA_END + 31)) { /* Fig. 8, VDG data sheet: tWFS = 32 * (227.5 * 1/f) */ fs_rise_event.at_cycle = scanline_start + VDG_LINE_DURATION; event_queue(&MACHINE_EVENT_LIST, &fs_rise_event); /* PAL delay after FS rising edge */ if (IS_PAL) { hs_fall_event.at_cycle += 25 * VDG_PAL_PADDING_LINE; } } event_queue(&MACHINE_EVENT_LIST, &hs_fall_event); }
static void do_hs_fall(void *data) { struct MC6847_private *vdg = data; // Finish rendering previous scanline if (vdg->frame == 0) { if (vdg->scanline < VDG_ACTIVE_AREA_START) { if (vdg->scanline == 0) { memset(vdg->pixel_data + VDG_LEFT_BORDER_START, vdg->border_colour, VDG_tAVB); } video_module->render_scanline(vdg->pixel_data); } else if (vdg->scanline >= VDG_ACTIVE_AREA_START && vdg->scanline < VDG_ACTIVE_AREA_END) { render_scanline(vdg); vdg->row++; if (vdg->row > 11) vdg->row = 0; video_module->render_scanline(vdg->pixel_data); vdg->pixel = vdg->pixel_data + VDG_LEFT_BORDER_START; } else if (vdg->scanline >= VDG_ACTIVE_AREA_END) { if (vdg->scanline == VDG_ACTIVE_AREA_END) { memset(vdg->pixel_data + VDG_LEFT_BORDER_START, vdg->border_colour, VDG_tAVB); } video_module->render_scanline(vdg->pixel_data); } } // HS falling edge. DELEGATE_CALL1(vdg->public.signal_hs, 0); vdg->scanline_start = vdg->hs_fall_event.at_tick; // Next HS rise and fall vdg->hs_rise_event.at_tick = vdg->scanline_start + VDG_CYCLES(VDG_HS_RISING_EDGE); vdg->hs_fall_event.at_tick = vdg->scanline_start + VDG_CYCLES(VDG_LINE_DURATION); /* On PAL machines, the clock to the VDG is interrupted at two points * in every frame to fake up some extra scanlines, padding the signal * from 262 lines to 312 lines. Dragons do not generate an HS-related * interrupt signal during this time, CoCos do. The positioning and * duration of each interruption differs also. */ if (IS_PAL && IS_COCO) { if (vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 25)) { vdg->pal_padding = 26; vdg->hs_fall_event.delegate.func = do_hs_fall_pal_coco; } else if (vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 47)) { vdg->pal_padding = 24; vdg->hs_fall_event.delegate.func = do_hs_fall_pal_coco; } } else if (IS_PAL && IS_DRAGON) { if (vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 24) || vdg->scanline == SCANLINE(VDG_ACTIVE_AREA_END + 32)) { vdg->hs_rise_event.at_tick += 25 * VDG_CYCLES(VDG_PAL_PADDING_LINE); vdg->hs_fall_event.at_tick += 25 * VDG_CYCLES(VDG_PAL_PADDING_LINE); } } event_queue(&MACHINE_EVENT_LIST, &vdg->hs_rise_event); event_queue(&MACHINE_EVENT_LIST, &vdg->hs_fall_event); // Next scanline vdg->scanline = SCANLINE(vdg->scanline + 1); vdg->beam_pos = 0; vdg->vram_nbytes = 0; vdg->vram_ptr = vdg->vram; vdg->vram_bit = 0; vdg->lborder_remaining = VDG_tLB; vdg->vram_remaining = vdg->is_32byte ? 32 : 16; vdg->rborder_remaining = VDG_tRB; if (vdg->scanline == VDG_ACTIVE_AREA_START) { vdg->row = 0; } if (vdg->scanline == VDG_ACTIVE_AREA_END) { // FS falling edge DELEGATE_CALL1(vdg->public.signal_fs, 0); }