// specialized gfx_decode_entry macros //#define GFXDECODE_RAM(region,offset,layout,start,colors) { region, offset, &layout, start, colors, GFXENTRY_RAM }, //#define GFXDECODE_DEVICE(region,offset,layout,start,colors) { region, offset, &layout, start, colors, GFXENTRY_DEVICE }, //#define GFXDECODE_DEVICE_RAM(region,offset,layout,start,colors) { region, offset, &layout, start, colors, GFXENTRY_DEVICE | GFXENTRY_RAM }, public static gfx_decode_entry GFXDECODE_SCALE(string region, u32 offset, gfx_layout layout, u16 start, u16 colors, u32 x, u32 y) { return(new gfx_decode_entry() { memory_region = region, start = offset, gfxlayout = layout, color_codes_start = start, total_color_codes = colors, flags = GFXENTRY_XSCALE(x) | GFXENTRY_YSCALE(y) }); }
// these macros are used for declaring gfx_decode_entry info arrays //#define GFXDECODE_START( name ) const gfx_decode_entry name[] = { //#define GFXDECODE_END { 0 } }; // use these to declare a gfx_decode_entry array as a member of a device class //#define DECLARE_GFXDECODE_MEMBER( name ) static const gfx_decode_entry name[] //#define GFXDECODE_MEMBER( name ) const gfx_decode_entry name[] = { // common gfx_decode_entry macros //#define GFXDECODE_ENTRYX(region,offset,layout,start,colors,flags) { region, offset, &layout, start, colors, flags }, public static gfx_decode_entry GFXDECODE_ENTRY(string region, u32 offset, gfx_layout layout, u16 start, u16 colors) { return(new gfx_decode_entry() { memory_region = region, start = offset, gfxlayout = layout, color_codes_start = start, total_color_codes = colors, flags = 0 }); }
public gfx_element(device_palette_interface palette, gfx_layout gl, ListBytesPointer srcdata, /*const u8 *srcdata,*/ u32 xormask, u32 total_colors, u32 color_base) { m_palette = palette; m_width = 0; m_height = 0; m_startx = 0; m_starty = 0; m_origwidth = 0; m_origheight = 0; m_total_elements = 0; m_color_base = color_base; m_color_depth = 0; m_color_granularity = 0; m_total_colors = total_colors; m_line_modulo = 0; m_char_modulo = 0; m_srcdata = null; m_dirtyseq = 1; m_gfxdata = null; m_layout_is_raw = false; m_layout_planes = 0; m_layout_xormask = xormask; m_layout_charincrement = 0; // set the layout set_layout(gl, srcdata); }
//void set_gfx(int index, gfx_element *element) { assert(index < MAX_GFX_ELEMENTS); m_gfx[index].reset(element); } // interface-level overrides //------------------------------------------------- // interface_validity_check - validate graphics // decoding configuration //------------------------------------------------- protected override void interface_validity_check(validity_checker valid) { if (!m_palette_is_disabled && m_paletteDevice == null) { KeyValuePair <device_t, string> target = m_paletteDevice.finder_target(); if (target.second() == finder_base.DUMMY_TAG) { osd_printf_error("No palette specified for device '{0}'\n", device().tag()); } else { osd_printf_error( "Device '{0}' specifies nonexistent device '{1}' relative to '{2}' as palette\n", device().tag(), target.second(), target.first().tag()); } } if (m_gfxdecodeinfo == null) { return; } // validate graphics decoding entries for (int gfxnum = 0; gfxnum < digfx_global.MAX_GFX_ELEMENTS && m_gfxdecodeinfo[gfxnum].gfxlayout != null; gfxnum++) { gfx_decode_entry gfx = m_gfxdecodeinfo[gfxnum]; gfx_layout layout = gfx.gfxlayout; // currently we are unable to validate RAM-based entries string region = gfx.memory_region; if (region != null && GFXENTRY_ISROM(gfx.flags)) { // resolve the region string gfxregion; if (GFXENTRY_ISDEVICE(gfx.flags)) { gfxregion = device().subtag(region); } else { gfxregion = device().owner().subtag(region); } UInt32 region_length = (UInt32)valid.region_length(gfxregion); if (region_length == 0) { osd_printf_error("gfx[{0}] references nonexistent region '{1}'\n", gfxnum, gfxregion); } // if we have a valid region, and we're not using auto-sizing, check the decode against the region length else if (!IS_FRAC(layout.total)) { // determine which plane is at the largest offset int start = 0; for (int plane = 0; plane < layout.planes; plane++) { if (layout.planeoffset[plane] > start) { start = (int)layout.planeoffset[plane]; } } start &= ~(int)(layout.charincrement - 1); // determine the total length based on this info int len = (int)(layout.total * layout.charincrement); // do we have enough space in the region to cover the whole decode? int avail = (int)(region_length - (gfx.start & ~(layout.charincrement / 8 - 1))); // if not, this is an error if ((start + len) / 8 > avail) { osd_printf_error("gfx[{0}] extends past allocated memory of region '{1}'\n", gfxnum, region); } } } int xscale = (int)GFXENTRY_GETXSCALE(gfx.flags); int yscale = (int)GFXENTRY_GETYSCALE(gfx.flags); // verify raw decode, which can only be full-region and have no scaling if (layout.planeoffset[0] == digfx_global.GFX_RAW) { if (layout.total != RGN_FRAC(1, 1)) { osd_printf_error("gfx[{0}] RAW layouts can only be RGN_FRAC(1,1)\n", gfxnum); } if (xscale != 1 || yscale != 1) { osd_printf_error("gfx[{0}] RAW layouts do not support xscale/yscale\n", gfxnum); } } // verify traditional decode doesn't have too many planes, // and has extended offset arrays if its width and/or height demand them else { throw new emu_unimplemented(); } } }
// decoding //------------------------------------------------- // decode_gfx - parse gfx decode info and // create gfx elements //------------------------------------------------- void decode_gfx(gfx_decode_entry [] gfxdecodeinfo) { // skip if nothing to do if (gfxdecodeinfo == null) { return; } // local variables to hold mutable copies of gfx layout data gfx_layout glcopy; std.vector <u32> extxoffs = new std.vector <u32>(0); std.vector <u32> extyoffs = new std.vector <u32>(0); // loop over all elements for (u8 curgfx = 0; curgfx < digfx_global.MAX_GFX_ELEMENTS && curgfx < gfxdecodeinfo.Length && gfxdecodeinfo[curgfx].gfxlayout != null; curgfx++) { gfx_decode_entry gfx = gfxdecodeinfo[curgfx]; // extract the scale factors and xormask u32 xscale = GFXENTRY_GETXSCALE(gfx.flags); u32 yscale = GFXENTRY_GETYSCALE(gfx.flags); u32 xormask = GFXENTRY_ISREVERSE(gfx.flags) ? 7U : 0U; // resolve the region u32 region_length; ListBytesPointer region_base; //const u8 *region_base; u8 region_width; endianness_t region_endianness; if (gfx.memory_region != null) { device_t basedevice = (GFXENTRY_ISDEVICE(gfx.flags)) ? device() : device().owner(); if (GFXENTRY_ISRAM(gfx.flags)) { memory_share share = basedevice.memshare(gfx.memory_region); //assert(share != NULL); region_length = (UInt32)(8 * share.bytes()); region_base = share.ptr(); //region_base = reinterpret_cast<u8 *>(share->ptr()); region_width = share.bytewidth(); region_endianness = share.endianness(); } else { memory_region region = basedevice.memregion(gfx.memory_region); //assert(region != NULL); region_length = 8 * region.bytes(); region_base = new ListBytesPointer(region.base_(), 0); //region_base = region->base(); region_width = region.bytewidth(); region_endianness = region.endianness(); } } else { region_length = 0; region_base = null; region_width = 1; region_endianness = ENDIANNESS_NATIVE; } if (region_endianness != ENDIANNESS_NATIVE) { switch (region_width) { case 2: xormask |= 0x08; break; case 4: xormask |= 0x18; break; case 8: xormask |= 0x38; break; } } // copy the layout into our temporary variable glcopy = new gfx_layout(gfx.gfxlayout); //memcpy(&glcopy, gfx.gfxlayout, sizeof(gfx_layout)); // if the character count is a region fraction, compute the effective total if (IS_FRAC(glcopy.total)) { //assert(region_length != 0); glcopy.total = region_length / glcopy.charincrement * FRAC_NUM(glcopy.total) / FRAC_DEN(glcopy.total); } // for non-raw graphics, decode the X and Y offsets if (glcopy.planeoffset[0] != digfx_global.GFX_RAW) { // copy the X and Y offsets into our temporary arrays extxoffs.resize((int)(glcopy.width * xscale)); extyoffs.resize((int)(glcopy.height * yscale)); //memcpy(&extxoffs[0], (glcopy.extxoffs != null) ? glcopy.extxoffs : glcopy.xoffset, glcopy.width * sizeof(UInt32)); //memcpy(&extyoffs[0], (glcopy.extyoffs != null) ? glcopy.extyoffs : glcopy.yoffset, glcopy.height * sizeof(UInt32)); for (int i = 0; i < glcopy.width; i++) { extxoffs[i] = glcopy.extxoffs != null ? glcopy.extxoffs[i] : glcopy.xoffset[i]; } for (int i = 0; i < glcopy.height; i++) { extyoffs[i] = glcopy.extyoffs != null ? glcopy.extyoffs[i] : glcopy.yoffset[i]; } // always use the extended offsets here glcopy.extxoffs = extxoffs; glcopy.extyoffs = extyoffs; // expand X and Y by the scale factors if (xscale > 1) { glcopy.width *= (UInt16)xscale; for (int j = glcopy.width - 1; j >= 0; j--) { extxoffs[j] = extxoffs[(int)(j / xscale)]; } } if (yscale > 1) { glcopy.height *= (UInt16)yscale; for (int j = glcopy.height - 1; j >= 0; j--) { extyoffs[j] = extyoffs[(int)(j / yscale)]; } } // loop over all the planes, converting fractions for (int j = 0; j < glcopy.planes; j++) { u32 value1 = glcopy.planeoffset[j]; if (IS_FRAC(value1)) { //assert(region_length != 0); glcopy.planeoffset[j] = FRAC_OFFSET(value1) + region_length * FRAC_NUM(value1) / FRAC_DEN(value1); } } // loop over all the X/Y offsets, converting fractions for (int j = 0; j < glcopy.width; j++) { u32 value2 = extxoffs[j]; if (digfx_global.IS_FRAC(value2)) { //assert(region_length != 0); extxoffs[j] = FRAC_OFFSET(value2) + region_length * FRAC_NUM(value2) / FRAC_DEN(value2); } } for (int j = 0; j < glcopy.height; j++) { u32 value3 = extyoffs[j]; if (IS_FRAC(value3)) { //assert(region_length != 0); extyoffs[j] = FRAC_OFFSET(value3) + region_length * FRAC_NUM(value3) / FRAC_DEN(value3); } } } // otherwise, just use the line modulo else { int base_ = (int)gfx.start; int end = (int)(region_length / 8); int linemod = (int)glcopy.yoffset[0]; while (glcopy.total > 0) { int elementbase = (int)(base_ + (glcopy.total - 1) * glcopy.charincrement / 8); int lastpixelbase = elementbase + glcopy.height * linemod / 8 - 1; if (lastpixelbase < end) { break; } glcopy.total--; } } // allocate the graphics //m_gfx[curgfx] = new gfx_element(m_palette, glcopy, region_base != null ? region_base + gfx.start : null, xormask, gfx.total_color_codes, gfx.color_codes_start); m_gfx[curgfx] = new gfx_element(m_paletteDevice.target.palette_interface, glcopy, region_base != null ? new ListBytesPointer(region_base, (int)gfx.start) : null, xormask, gfx.total_color_codes, gfx.color_codes_start); } m_decoded = true; }
public gfx_layout(gfx_layout rhs) : this(rhs.width, rhs.height, rhs.total, rhs.planes, rhs.planeoffset, rhs.xoffset, rhs.yoffset, rhs.charincrement, rhs.extxoffs, rhs.extyoffs) { }
// setters //------------------------------------------------- // set_layout - set the layout for a gfx_element //------------------------------------------------- void set_layout(gfx_layout gl, ListBytesPointer srcdata) //const u8 *srcdata) { m_srcdata = srcdata; // configure ourselves m_width = m_origwidth = gl.width; m_height = m_origheight = gl.height; m_startx = m_starty = 0; m_total_elements = gl.total; m_color_granularity = (UInt16)(1 << gl.planes); m_color_depth = m_color_granularity; // copy data from the layout m_layout_is_raw = gl.planeoffset[0] == digfx_global.GFX_RAW; m_layout_planes = (byte)gl.planes; m_layout_charincrement = gl.charincrement; // raw graphics case if (m_layout_is_raw) { // RAW layouts don't need these arrays m_layout_planeoffset.clear(); m_layout_xoffset.clear(); m_layout_yoffset.clear(); m_gfxdata_allocated.clear(); // modulos are determined for us by the layout m_line_modulo = gl.yoffs(0) / 8; m_char_modulo = gl.charincrement / 8; // RAW graphics must have a pointer up front //assert(srcdata != NULL); m_gfxdata = new ListBytesPointer(srcdata); //m_gfxdata = const_cast<u8 *>(srcdata); } // decoded graphics case else { // copy offsets m_layout_planeoffset.resize(m_layout_planes); m_layout_xoffset.resize(m_width); m_layout_yoffset.resize(m_height); for (int p = 0; p < m_layout_planes; p++) { m_layout_planeoffset[p] = gl.planeoffset[p]; } for (int y = 0; y < m_height; y++) { m_layout_yoffset[y] = gl.yoffs(y); } for (int x = 0; x < m_width; x++) { m_layout_xoffset[x] = gl.xoffs(x); } // we get to pick our own modulos m_line_modulo = m_origwidth; m_char_modulo = m_line_modulo * m_origheight; // allocate memory for the data m_gfxdata_allocated.resize((int)(m_total_elements * m_char_modulo)); m_gfxdata = new ListBytesPointer(m_gfxdata_allocated); //m_gfxdata = &m_gfxdata_allocated[0]; } // mark everything dirty m_dirty.resize((int)m_total_elements); memset(m_dirty, (u8)1, m_total_elements); // allocate a pen usage array for entries with 32 pens or less if (m_color_depth <= 32) { m_pen_usage.resize((int)m_total_elements); } else { m_pen_usage.clear(); } }