//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; }