diff options
author | 2016-02-15 17:57:16 +0100 | |
---|---|---|
committer | 2016-02-15 17:57:28 +0100 | |
commit | b0a7bcd3468fa309d3761742be7f69c671d7a1fc (patch) | |
tree | bb75aac1faac0b980ddcf9d0de2599478cc504e4 | |
parent | a95323026cceddedb09eac64eedf8daef1dfd580 (diff) |
Significant speed improvements to the BGFX renderer. [MooglyGuy]
-rw-r--r-- | scripts/src/osd/modules.lua | 1 | ||||
-rw-r--r-- | src/emu/render.cpp | 21 | ||||
-rw-r--r-- | src/emu/render.h | 10 | ||||
-rw-r--r-- | src/emu/ui/menu.cpp | 36 | ||||
-rw-r--r-- | src/osd/modules/render/binpacker.cpp | 195 | ||||
-rw-r--r-- | src/osd/modules/render/binpacker.h | 183 | ||||
-rw-r--r-- | src/osd/modules/render/d3d/d3dhlsl.cpp | 11 | ||||
-rw-r--r-- | src/osd/modules/render/drawbgfx.cpp | 871 | ||||
-rw-r--r-- | src/osd/modules/render/drawbgfx.h | 115 |
9 files changed, 1025 insertions, 418 deletions
diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index 87e684a50f6..14d344fee09 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -104,6 +104,7 @@ function osdmodulesbuild() if USE_BGFX == 1 then files { MAME_DIR .. "src/osd/modules/render/drawbgfx.cpp", + MAME_DIR .. "src/osd/modules/render/binpacker.cpp", } defines { "USE_BGFX" diff --git a/src/emu/render.cpp b/src/emu/render.cpp index e25f62a8e13..cbcfd6b16b3 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -442,8 +442,10 @@ void render_texture::hq_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const // get_scaled - get a scaled bitmap (if we can) //------------------------------------------------- -void render_texture::get_scaled(UINT32 dwidth, UINT32 dheight, render_texinfo &texinfo, render_primitive_list &primlist) +void render_texture::get_scaled(UINT32 dwidth, UINT32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, bool packable) { + texinfo.hash = 0; + // source width/height come from the source bounds int swidth = m_sbounds.width(); int sheight = m_sbounds.height(); @@ -520,6 +522,17 @@ void render_texture::get_scaled(UINT32 dwidth, UINT32 dheight, render_texinfo &t // palette will be set later texinfo.seqid = scaled->seqid; } + + UINT32 hash = 0; + if (packable) + { + //printf("Packable, %d, %d\n", texinfo.width, texinfo.height); + } + if (packable && texinfo.width <= 128 && texinfo.height <= 128) + { + hash = reinterpret_cast<UINT64>(texinfo.base) & 0xffffffff; + } + texinfo.hash = hash; } @@ -677,7 +690,7 @@ void render_container::add_char(float x0, float y0, float height, float aspect, // add it like a quad item &newitem = add_generic(CONTAINER_ITEM_QUAD, bounds.x0, bounds.y0, bounds.x1, bounds.y1, argb); newitem.m_texture = texture; - newitem.m_flags = PRIMFLAG_TEXORIENT(ROT0) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); + newitem.m_flags = PRIMFLAG_TEXORIENT(ROT0) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE; newitem.m_internal = INTERNAL_FLAG_CHAR; } @@ -1751,7 +1764,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const width = MIN(width, m_maxtexwidth); height = MIN(height, m_maxtexheight); - curitem->texture()->get_scaled(width, height, prim->texture, list); + curitem->texture()->get_scaled(width, height, prim->texture, list, (curitem->flags() & PRIMFLAG_PACKABLE) ? true : false); // set the palette prim->texture.palette = curitem->texture()->get_adjusted_palette(container); @@ -1854,7 +1867,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob // get the scaled texture and append it - texture->get_scaled(width, height, prim->texture, list); + texture->get_scaled(width, height, prim->texture, list, (prim->flags & PRIMFLAG_PACKABLE) ? true : false); // compute the clip rect render_bounds cliprect; diff --git a/src/emu/render.h b/src/emu/render.h index e40c86b1c3c..0fda591381a 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -62,7 +62,9 @@ enum BLENDMODE_NONE = 0, // no blending BLENDMODE_ALPHA, // standard alpha blend BLENDMODE_RGB_MULTIPLY, // apply source alpha to source pix, then multiply RGB values - BLENDMODE_ADD // apply source alpha to source pix, then add to destination + BLENDMODE_ADD, // apply source alpha to source pix, then add to destination + + BLENDMODE_COUNT }; @@ -105,6 +107,9 @@ const UINT32 PRIMFLAG_TYPE_MASK = 3 << PRIMFLAG_TYPE_SHIFT; const UINT32 PRIMFLAG_TYPE_LINE = 0 << PRIMFLAG_TYPE_SHIFT; const UINT32 PRIMFLAG_TYPE_QUAD = 1 << PRIMFLAG_TYPE_SHIFT; +const int PRIMFLAG_PACKABLE_SHIFT = 1; +const UINT32 PRIMFLAG_PACKABLE = 1 << PRIMFLAG_PACKABLE_SHIFT; + //************************************************************************** // MACROS //************************************************************************** @@ -206,6 +211,7 @@ struct render_texinfo UINT32 height; // height of the image UINT32 seqid; // sequence ID UINT64 osddata; // aux data to pass to osd + UINT32 hash; // hash (where applicable) const rgb_t * palette; // palette for PALETTE16 textures, bcg lookup table for RGB32/YUY16 }; @@ -430,7 +436,7 @@ public: private: // internal helpers - void get_scaled(UINT32 dwidth, UINT32 dheight, render_texinfo &texinfo, render_primitive_list &primlist); + void get_scaled(UINT32 dwidth, UINT32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, bool packable = false); const rgb_t *get_adjusted_palette(render_container &container); static const int MAX_TEXTURE_SCALES = 16; diff --git a/src/emu/ui/menu.cpp b/src/emu/ui/menu.cpp index a06fb5e62ca..fbe7d46e541 100644 --- a/src/emu/ui/menu.cpp +++ b/src/emu/ui/menu.cpp @@ -59,12 +59,12 @@ static const ui_arts_info arts_info[] = { nullptr } }; -static const char *hover_msg[] = { - "Add or remove favorites", - "Export displayed list to file", - "Show DATs view", - "Setup directories", - "Configure options" +static const char *hover_msg[] = { + "Add or remove favorites", + "Export displayed list to file", + "Show DATs view", + "Setup directories", + "Configure options" }; /*************************************************************************** @@ -1258,7 +1258,7 @@ void ui_menu::render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source, const void ui_menu::highlight(render_container *container, float x0, float y0, float x1, float y1, rgb_t bgcolor) { - container->add_quad(x0, y0, x1, y1, bgcolor, hilight_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + container->add_quad(x0, y0, x1, y1, bgcolor, hilight_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE) | PRIMFLAG_PACKABLE); } @@ -1268,7 +1268,7 @@ void ui_menu::highlight(render_container *container, float x0, float y0, float x void ui_menu::draw_arrow(render_container *container, float x0, float y0, float x1, float y1, rgb_t fgcolor, UINT32 orientation) { - container->add_quad(x0, y0, x1, y1, fgcolor, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(orientation)); + container->add_quad(x0, y0, x1, y1, fgcolor, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(orientation) | PRIMFLAG_PACKABLE); } //------------------------------------------------- @@ -1350,7 +1350,7 @@ void ui_menu::init_ui(running_machine &machine) toolbar_texture[x]->set_bitmap(*toolbar_bitmap[x], toolbar_bitmap[x]->cliprect(), TEXFORMAT_ARGB32); else toolbar_bitmap[x]->reset(); - + if (x == 0 || x == 2) { dst = &sw_toolbar_bitmap[x]->pix32(0); @@ -1487,7 +1487,7 @@ void ui_menu::draw_select_game(bool noinput) // if we have some background hilighting to do, add a quad behind everything else if (bgcolor != UI_TEXT_BG_COLOR) - mui.draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(255, 43, 43, 43), + mui.draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); // if we're on the top line, display the up arrow @@ -1531,7 +1531,7 @@ void ui_menu::draw_select_game(bool noinput) space = mui.get_line_height() * container->manager().ui_aspect() * 1.5f; } - mui.draw_text_full(container, itemtext, effective_left + space, line_y, effective_width - space, JUSTIFY_LEFT, WRAP_TRUNCATE, + mui.draw_text_full(container, itemtext, effective_left + space, line_y, effective_width - space, JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); } else @@ -1591,7 +1591,7 @@ void ui_menu::draw_select_game(bool noinput) container->add_line(visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); else - mui.draw_text_full(container, itemtext, effective_left, line, effective_width, JUSTIFY_CENTER, WRAP_TRUNCATE, + mui.draw_text_full(container, itemtext, effective_left, line, effective_width, JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr); line += line_height; } @@ -2116,7 +2116,7 @@ void ui_menu::draw_star(float x0, float y0) { float y1 = y0 + machine().ui().get_line_height(); float x1 = x0 + machine().ui().get_line_height() * container->manager().ui_aspect(); - container->add_quad(x0, y0, x1, y1, ARGB_WHITE, star_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + container->add_quad(x0, y0, x1, y1, ARGB_WHITE, star_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE); } //------------------------------------------------- @@ -2298,13 +2298,13 @@ void ui_menu::draw_common_arrow(float origx1, float origy1, float origx2, float // apply arrow if (current == dmin) - container->add_quad(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90)); + container->add_quad(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90) | PRIMFLAG_PACKABLE); else if (current == dmax) - container->add_quad(al_x0, al_y0, al_x1, al_y1, fgcolor_left, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X)); + container->add_quad(al_x0, al_y0, al_x1, al_y1, fgcolor_left, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X) | PRIMFLAG_PACKABLE); else { - container->add_quad(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90)); - container->add_quad(al_x0, al_y0, al_x1, al_y1, fgcolor_left, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X)); + container->add_quad(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90) | PRIMFLAG_PACKABLE); + container->add_quad(al_x0, al_y0, al_x1, al_y1, fgcolor_left, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X) | PRIMFLAG_PACKABLE); } } @@ -2409,7 +2409,7 @@ void ui_menu::draw_icon(int linenum, void *selectedref, float x0, float y0) } if (icons_bitmap[linenum]->valid()) - container->add_quad(x0, y0, x1, y1, ARGB_WHITE, icons_texture[linenum], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + container->add_quad(x0, y0, x1, y1, ARGB_WHITE, icons_texture[linenum], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE); } //------------------------------------------------- diff --git a/src/osd/modules/render/binpacker.cpp b/src/osd/modules/render/binpacker.cpp new file mode 100644 index 00000000000..2054dfa54cf --- /dev/null +++ b/src/osd/modules/render/binpacker.cpp @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +//============================================================ +// +// binpacker.cpp - Simple texture packer for dynamic atlasing +// +//============================================================ + +#include "binpacker.h" +#include <algorithm> + +bool rectangle_packer::pack(const std::vector<packable_rectangle>& rects, std::vector<std::vector<packed_rectangle>>& packs, int pack_size) +{ + clear(); + + m_pack_size = pack_size; + + // Add rects to member array, and check to make sure none is too big + for (size_t rect = 0; rect < rects.size(); rect++) + { + m_rects.push_back(rectangle(0, 0, rects[rect].width(), rects[rect].height(), rects[rect].hash(), rects[rect].format(), rects[rect].rowpixels(), rects[rect].palette(), rects[rect].base())); + } + + // Sort from greatest to least area + std::sort(m_rects.rbegin(), m_rects.rend()); + + // Pack + while (m_num_packed < (int)m_rects.size()) + { + int i = m_packs.size(); + m_packs.push_back(rectangle(m_pack_size)); + m_roots.push_back(i); + if (!fill(i)) + { + return false; + } + } + + // Write out + packs.resize(m_roots.size()); + for (size_t i = 0; i < m_roots.size(); ++i) + { + packs[i].clear(); + add_pack_to_array(m_roots[i], packs[i]); + } + + return true; +} + +void rectangle_packer::clear() +{ + m_pack_size = 0; + m_num_packed = 0; + m_rects.clear(); + m_packs.clear(); + m_roots.clear(); +} + +bool rectangle_packer::fill(int pack) +{ + // For each rect + for (size_t rect = 0; rect < m_rects.size(); ++rect) + { + // If it's not already packed + if (!m_rects[rect].packed) + { + // If it fits in the current working area + if (fits(m_rects[rect], m_packs[pack])) + { + // Store in lower-left of working area, split, and recurse + m_num_packed++; + split(pack, rect); + fill(m_packs[pack].children[0]); + fill(m_packs[pack].children[1]); + return true; + } + } + } + return false; +} + +void rectangle_packer::split(int pack, int rect) +{ + // Split the working area either horizontally or vertically with respect + // to the rect we're storing, such that we get the largest possible child + // area. + + rectangle left = m_packs[pack]; + rectangle right = m_packs[pack]; + rectangle bottom = m_packs[pack]; + rectangle top = m_packs[pack]; + + left.y += m_rects[rect].h; + left.w = m_rects[rect].w; + left.h -= m_rects[rect].h; + + right.x += m_rects[rect].w; + right.w -= m_rects[rect].w; + + bottom.x += m_rects[rect].w; + bottom.h = m_rects[rect].h; + bottom.w -= m_rects[rect].w; + + top.y += m_rects[rect].h; + top.h -= m_rects[rect].h; + + int max_lr_area = left.get_area(); + if (right.get_area() > max_lr_area) + { + max_lr_area = right.get_area(); + } + + int max_bt_area = bottom.get_area(); + if (top.get_area() > max_bt_area) + { + max_bt_area = top.get_area(); + } + + if (max_lr_area > max_bt_area) + { + if (left.get_area() > right.get_area()) + { + m_packs.push_back(left); + m_packs.push_back(right); + } + else + { + m_packs.push_back(right); + m_packs.push_back(left); + } + } + else + { + if (bottom.get_area() > top.get_area()) + { + m_packs.push_back(bottom); + m_packs.push_back(top); + } + else + { + m_packs.push_back(top); + m_packs.push_back(bottom); + } + } + + // This pack area now represents the rect we've just stored, so save the + // relevant info to it, and assign children. + m_packs[pack].w = m_rects[rect].w; + m_packs[pack].h = m_rects[rect].h; + m_packs[pack].hash = m_rects[rect].hash; + m_packs[pack].format = m_rects[rect].format; + m_packs[pack].rowpixels = m_rects[rect].rowpixels; + m_packs[pack].palette = m_rects[rect].palette; + m_packs[pack].base = m_rects[rect].base; + m_packs[pack].children[0] = m_packs.size() - 2; + m_packs[pack].children[1] = m_packs.size() - 1; + + // Done with the rect + m_rects[rect].packed = true; + +} + +bool rectangle_packer::fits(rectangle& rect1, const rectangle& rect2) +{ + // Check to see if rect1 fits in rect2 + + if (rect1.w <= rect2.w && rect1.h <= rect2.h) + { + return true; + } + else + { + return false; + } +} + +void rectangle_packer::add_pack_to_array(int pack, std::vector<packed_rectangle>& array) const +{ + if (m_packs[pack].hash != 0) + { + array.push_back(packed_rectangle(m_packs[pack].hash, m_packs[pack].format, + m_packs[pack].w, m_packs[pack].h, m_packs[pack].x, m_packs[pack].y, + m_packs[pack].rowpixels, m_packs[pack].palette, m_packs[pack].base)); + + if (m_packs[pack].children[0] != -1) + { + add_pack_to_array(m_packs[pack].children[0], array); + } + + if (m_packs[pack].children[1] != -1) + { + add_pack_to_array(m_packs[pack].children[1], array); + } + } +} diff --git a/src/osd/modules/render/binpacker.h b/src/osd/modules/render/binpacker.h new file mode 100644 index 00000000000..677083b5c09 --- /dev/null +++ b/src/osd/modules/render/binpacker.h @@ -0,0 +1,183 @@ +#pragma once + +#ifndef __RECTPACKER_H__ +#define __RECTPACKER_H__ + +#include "emu.h" + +#include <vector> + +class rectangle_packer +{ +public: + // The input and output are in terms of vectors of ints to avoid + // dependencies (although I suppose a public member struct could have been + // used). The parameters are: + + // packs : After packing, the outer array contains the packs (therefore + // the number of packs is packs.size()). Each inner array contains a + // sequence of sets of 3 ints. Each set represents a rectangle in the + // pack. The elements in the set are 1) the rect ID, 2) the x position + // of the rect with respect to the pack, and 3) the y position of the rect + // with respect to the pack. The widths and heights of the rects are not + // included, as it's assumed they are stored on the caller's side (they + // were after all the input to the function). + + class packable_rectangle + { + public: + packable_rectangle() : m_hash(0), m_width(-1), m_height(-1) { } + packable_rectangle(UINT32 hash, UINT32 format, int width, int height, int rowpixels, const rgb_t *palette, void *base) + : m_hash(hash) + , m_format(format) + , m_width(width) + , m_height(height) + , m_rowpixels(rowpixels) + , m_palette(palette) + , m_base(base) + { + } + + UINT32 hash() const { return m_hash; } + UINT32 format() const { return m_format; } + int width() const { return m_width; } + int height() const { return m_height; } + int rowpixels() const { return m_rowpixels; } + const rgb_t* palette() const { return m_palette; } + void* base() const { return m_base; } + + private: + UINT32 m_hash; + UINT32 m_format; + int m_width; + int m_height; + int m_rowpixels; + const rgb_t* m_palette; + void* m_base; + }; + + class packed_rectangle + { + public: + packed_rectangle() : m_hash(0), m_format(0), m_width(-1), m_height(-1), m_x(-1), m_y(-1), m_rowpixels(0), m_palette(nullptr), m_base(nullptr) { } + packed_rectangle(const packed_rectangle& rect) + : m_hash(rect.m_hash) + , m_format(rect.m_format) + , m_width(rect.m_width) + , m_height(rect.m_height) + , m_x(rect.m_x) + , m_y(rect.m_y) + , m_rowpixels(rect.m_rowpixels) + , m_palette(rect.m_palette) + , m_base(rect.m_base) + { + } + packed_rectangle(UINT32 hash, UINT32 format, int width, int height, int x, int y, int rowpixels, const rgb_t *palette, void *base) + : m_hash(hash) + , m_format(format) + , m_width(width) + , m_height(height) + , m_x(x) + , m_y(y) + , m_rowpixels(rowpixels) + , m_palette(palette) + , m_base(base) + { + } + + UINT32 hash() const { return m_hash; } + UINT32 format() const { return m_format; } + int width() const { return m_width; } + int height() const { return m_height; } + int x() const { return m_x; } + int y() const { return m_y; } + int rowpixels() const { return m_rowpixels; } + const rgb_t* palette() const { return m_palette; } + void* base() const { return m_base; } + + private: + UINT32 m_hash; + UINT32 m_format; + int m_width; + int m_height; + int m_x; + int m_y; + int m_rowpixels; + const rgb_t* m_palette; + void* m_base; + }; + + bool pack(const std::vector<packable_rectangle>& rects, std::vector<std::vector<packed_rectangle>>& packs, int pack_size); + +private: + struct rectangle + { + rectangle(int size) + : x(0) + , y(0) + , w(size) + , h(size) + , hash(-1) + , format(0) + , rowpixels(0) + , palette(nullptr) + , base(nullptr) + , packed(false) + { + children[0] = -1; + children[1] = -1; + } + + rectangle(int x, int y, int w, int h, int hash, UINT32 format, int rowpixels, const rgb_t *palette, void *base) + : x(x) + , y(y) + , w(w) + , h(h) + , hash(hash) + , format(format) + , rowpixels(rowpixels) + , palette(palette) + , base(base) + , packed(false) + { + children[0] = -1; + children[1] = -1; + } + + int get_area() const + { + return w * h; + } + + bool operator<(const rectangle& rect) const + { + return get_area() < rect.get_area(); + } + + int x; + int y; + int w; + int h; + int hash; + UINT32 format; + int rowpixels; + const rgb_t* palette; + void* base; + int children[2]; + bool packed; + }; + + void clear(); + bool fill(int pack); + void split(int pack, int rect); + bool fits(rectangle& rect1, const rectangle& rect2); + void add_pack_to_array(int pack, std::vector<packed_rectangle>& array) const; + + int m_pack_size; + int m_num_packed; + std::vector<rectangle> m_rects; + std::vector<rectangle> m_packs; + std::vector<int> m_roots; +}; + +#endif // __RECTPACKER_H__
\ No newline at end of file diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp index 43d6ec9bc48..4cc53f2e41d 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.cpp +++ b/src/osd/modules/render/d3d/d3dhlsl.cpp @@ -1416,14 +1416,9 @@ int shaders::post_pass(render_target *rt, int source_index, poly_info *poly, int float screen_scale[2] = { xscale, yscale }; float screen_offset[2] = { xoffset, yoffset }; - rgb_t back_color_rgb = !machine->first_screen()->has_palette() - ? rgb_t(0, 0, 0) - : machine->first_screen()->palette().palette()->entry_color(0); + rgb_t back_color_rgb = !machine->first_screen()->has_palette() ? rgb_t(0, 0, 0) : machine->first_screen()->palette().palette()->entry_color(0); back_color_rgb = apply_color_convolution(back_color_rgb); - float back_color[3] = { - static_cast<float>(back_color_rgb.r()) / 255.0f, - static_cast<float>(back_color_rgb.g()) / 255.0f, - static_cast<float>(back_color_rgb.b()) / 255.0f }; + float back_color[3] = { static_cast<float>(back_color_rgb.r()) / 255.0f, static_cast<float>(back_color_rgb.g()) / 255.0f, static_cast<float>(back_color_rgb.b()) / 255.0f }; curr_effect = post_effect; curr_effect->update_uniforms(); @@ -1463,9 +1458,9 @@ int shaders::downsample_pass(render_target *rt, int source_index, poly_info *pol curr_effect->set_bool("PrepareVector", prepare_vector); int bloom_index = 0; - float bloom_size = (d3d->get_width() < d3d->get_height()) ? d3d->get_width() : d3d->get_height(); float bloom_width = prepare_vector ? rt->target_width : rt->target_width / hlsl_prescale_x; float bloom_height = prepare_vector ? rt->target_height : rt->target_height / hlsl_prescale_y; + float bloom_size = (bloom_width < bloom_height) ? bloom_width : bloom_height; for (; bloom_size >= 2.0f && bloom_index < 11; bloom_size *= 0.5f) { bloom_dims[bloom_index][0] = (float)(int)bloom_width; diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp index 35a50609cf4..707360053aa 100644 --- a/src/osd/modules/render/drawbgfx.cpp +++ b/src/osd/modules/render/drawbgfx.cpp @@ -1,8 +1,8 @@ // license:BSD-3-Clause -// copyright-holders:Miodrag Milanovic,Dario Manesku,Branimir Karadzic,Aaron Giles +// copyright-holders:Miodrag Milanovic,Ryan Holtz,Dario Manesku,Branimir Karadzic,Aaron Giles //============================================================ // -// drawbgfx.c - BGFX drawer +// drawbgfx.cpp - BGFX renderer // //============================================================ #define __STDC_LIMIT_MACROS @@ -32,6 +32,9 @@ #include <bgfx/bgfx.h> #include <bx/fpumath.h> #include <bx/readerwriter.h> +#include <algorithm> + +#include "drawbgfx.h" //============================================================ // DEBUGGING @@ -55,42 +58,6 @@ //============================================================ -/* sdl_info is the information about SDL for the current screen */ -class renderer_bgfx : public osd_renderer -{ -public: - renderer_bgfx(osd_window *w) - : osd_renderer(w, FLAG_NONE), - m_dimensions(0,0) - {} - - virtual int create() override; - virtual int draw(const int update) override; -#ifdef OSD_SDL - virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override; -#else - virtual void save() override { } - virtual void record() override { } - virtual void toggle_fsfx() override { } -#endif - virtual void destroy() override; - virtual render_primitive_list *get_primitives() override - { - osd_dim wdim = window().get_size(); - window().target()->set_bounds(wdim.width(), wdim.height(), window().aspect()); - return &window().target()->get_primitives(); - } - - bgfx::ProgramHandle m_progQuad; - bgfx::ProgramHandle m_progQuadTexture; - bgfx::ProgramHandle m_progLine; - bgfx::UniformHandle m_s_texColor; - bgfx::FrameBufferHandle fbh; - // Original display_mode - osd_dim m_dimensions; -}; - - //============================================================ // PROTOTYPES //============================================================ @@ -144,7 +111,7 @@ static void* sdlNativeWindowHandle(SDL_Window* _window) SDL_VERSION(&wmi.version); if (!SDL_GetWindowWMInfo(_window, &wmi)) { - return NULL; + return nullptr; } # if BX_PLATFORM_LINUX || BX_PLATFORM_BSD @@ -175,7 +142,8 @@ int renderer_bgfx::create() bgfx::setDebug(BGFX_DEBUG_TEXT); //BGFX_DEBUG_STATS m_dimensions = osd_dim(wdim.width(), wdim.height()); } - else { + else + { #ifdef OSD_WINDOWS fbh = bgfx::createFrameBuffer(window().m_hwnd, wdim.width(), wdim.height()); #else @@ -183,12 +151,18 @@ int renderer_bgfx::create() #endif bgfx::touch(window().m_index); } + + PosColorTexCoord0Vertex::init(); + PosColorVertex::init(); + // Create program from shaders. m_progQuad = loadProgram("vs_quad", "fs_quad"); m_progQuadTexture = loadProgram("vs_quad_texture", "fs_quad_texture"); - m_progLine = loadProgram("vs_line", "fs_line"); m_s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1); + uint32_t flags = BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_MIN_ANISOTROPIC | BGFX_TEXTURE_MAG_ANISOTROPIC; + m_texture_cache = bgfx::createTexture2D(CACHE_SIZE, CACHE_SIZE, 1, bgfx::TextureFormat::BGRA8, flags); + return 0; } @@ -198,7 +172,7 @@ int renderer_bgfx::create() void renderer_bgfx::destroy() { - if (window().m_index > 0) + if (window().m_index > 0) { bgfx::destroyFrameBuffer(fbh); } @@ -206,7 +180,6 @@ void renderer_bgfx::destroy() // Cleanup. bgfx::destroyProgram(m_progQuad); bgfx::destroyProgram(m_progQuadTexture); - bgfx::destroyProgram(m_progLine); } @@ -239,7 +212,7 @@ static const bgfx::Memory* loadMem(bx::FileReaderI* _reader, const char* _filePa return mem; } - return NULL; + return nullptr; } static bgfx::ShaderHandle loadShader(bx::FileReaderI* _reader, const char* _name) { @@ -277,11 +250,11 @@ static bgfx::ShaderHandle loadShader(bx::FileReaderI* _reader, const char* _name return bgfx::createShader(loadMem(_reader, filePath)); } -bgfx::ProgramHandle loadProgram(bx::FileReaderI* _reader, const char* _vsName, const char* _fsName) +bgfx::ProgramHandle renderer_bgfx::loadProgram(bx::FileReaderI* _reader, const char* _vsName, const char* _fsName) { bgfx::ShaderHandle vsh = loadShader(_reader, _vsName); bgfx::ShaderHandle fsh = BGFX_INVALID_HANDLE; - if (NULL != _fsName) + if (nullptr != _fsName) { fsh = loadShader(_reader, _fsName); } @@ -290,44 +263,70 @@ bgfx::ProgramHandle loadProgram(bx::FileReaderI* _reader, const char* _vsName, c } static auto s_fileReader = new bx::CrtFileReader; -bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName) +bgfx::ProgramHandle renderer_bgfx::loadProgram(const char* _vsName, const char* _fsName) { - return loadProgram(s_fileReader, _vsName, _fsName); } + //============================================================ // drawbgfx_window_draw //============================================================ -struct PosColorTexCoord0Vertex +bgfx::VertexDecl renderer_bgfx::PosColorTexCoord0Vertex::ms_decl; + +void renderer_bgfx::put_packed_quad(render_primitive *prim, UINT32 hash, PosColorTexCoord0Vertex* vertex) { - float m_x; - float m_y; - float m_z; - uint32_t m_rgba; - float m_u; - float m_v; - - static void init() - { - ms_decl.begin() - .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) - .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) - .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) - .end(); - } - - static bgfx::VertexDecl ms_decl; -}; -bgfx::VertexDecl PosColorTexCoord0Vertex::ms_decl; - -void screenQuad(float _x1 - , float _y1 - , float _x2 - , float _y2 - , uint32_t _abgr - , render_quad_texuv uv - ) + rectangle_packer::packed_rectangle& rect = m_hash_to_entry[hash]; + float u0 = float(rect.x()) / float(CACHE_SIZE); + float v0 = float(rect.y()) / float(CACHE_SIZE); + float u1 = u0 + float(rect.width()) / float(CACHE_SIZE); + float v1 = v0 + float(rect.height()) / float(CACHE_SIZE); + UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); + + vertex[0].m_x = prim->bounds.x0; + vertex[0].m_y = prim->bounds.y0; + vertex[0].m_z = 0; + vertex[0].m_rgba = rgba; + vertex[0].m_u = u0; + vertex[0].m_v = v0; + + vertex[1].m_x = prim->bounds.x1; + vertex[1].m_y = prim->bounds.y0; + vertex[1].m_z = 0; + vertex[1].m_rgba = rgba; + vertex[1].m_u = u1; + vertex[1].m_v = v0; + + vertex[2].m_x = prim->bounds.x1; + vertex[2].m_y = prim->bounds.y1; + vertex[2].m_z = 0; + vertex[2].m_rgba = rgba; + vertex[2].m_u = u1; + vertex[2].m_v = v1; + + vertex[3].m_x = prim->bounds.x1; + vertex[3].m_y = prim->bounds.y1; + vertex[3].m_z = 0; + vertex[3].m_rgba = rgba; + vertex[3].m_u = u1; + vertex[3].m_v = v1; + + vertex[4].m_x = prim->bounds.x0; + vertex[4].m_y = prim->bounds.y1; + vertex[4].m_z = 0; + vertex[4].m_rgba = rgba; + vertex[4].m_u = u0; + vertex[4].m_v = v1; + + vertex[5].m_x = prim->bounds.x0; + vertex[5].m_y = prim->bounds.y0; + vertex[5].m_z = 0; + vertex[5].m_rgba = rgba; + vertex[5].m_u = u0; + vertex[5].m_v = v0; +} + +void renderer_bgfx::render_textured_quad(int view, render_primitive* prim) { if (bgfx::checkAvailTransientVertexBuffer(6, PosColorTexCoord0Vertex::ms_decl)) { @@ -335,90 +334,86 @@ void screenQuad(float _x1 bgfx::allocTransientVertexBuffer(&vb, 6, PosColorTexCoord0Vertex::ms_decl); PosColorTexCoord0Vertex* vertex = (PosColorTexCoord0Vertex*)vb.data; - const float minx = _x1; - const float miny = _y1; - const float maxx = _x2; - const float maxy = _y2; - const float zz = 0.0f; - - vertex[0].m_x = minx; - vertex[0].m_y = miny; - vertex[0].m_z = zz; - vertex[0].m_rgba = _abgr; - vertex[0].m_u = uv.tl.u; - vertex[0].m_v = uv.tl.v; - - vertex[1].m_x = maxx; - vertex[1].m_y = miny; - vertex[1].m_z = zz; - vertex[1].m_rgba = _abgr; - vertex[1].m_u = uv.tr.u; - vertex[1].m_v = uv.tr.v; - - vertex[2].m_x = maxx; - vertex[2].m_y = maxy; - vertex[2].m_z = zz; - vertex[2].m_rgba = _abgr; - vertex[2].m_u = uv.br.u; - vertex[2].m_v = uv.br.v; - - vertex[3].m_x = maxx; - vertex[3].m_y = maxy; - vertex[3].m_z = zz; - vertex[3].m_rgba = _abgr; - vertex[3].m_u = uv.br.u; - vertex[3].m_v = uv.br.v; - - vertex[4].m_x = minx; - vertex[4].m_y = maxy; - vertex[4].m_z = zz; - vertex[4].m_rgba = _abgr; - vertex[4].m_u = uv.bl.u; - vertex[4].m_v = uv.bl.v; - - vertex[5].m_x = minx; - vertex[5].m_y = miny; - vertex[5].m_z = zz; - vertex[5].m_rgba = _abgr; - vertex[5].m_u = uv.tl.u; - vertex[5].m_v = uv.tl.v; + UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); + + vertex[0].m_x = prim->bounds.x0; + vertex[0].m_y = prim->bounds.y0; + vertex[0].m_z = 0; + vertex[0].m_rgba = rgba; + vertex[0].m_u = prim->texcoords.tl.u; + vertex[0].m_v = prim->texcoords.tl.v; + + vertex[1].m_x = prim->bounds.x1; + vertex[1].m_y = prim->bounds.y0; + vertex[1].m_z = 0; + vertex[1].m_rgba = rgba; + vertex[1].m_u = prim->texcoords.tr.u; + vertex[1].m_v = prim->texcoords.tr.v; + + vertex[2].m_x = prim->bounds.x1; + vertex[2].m_y = prim->bounds.y1; + vertex[2].m_z = 0; + vertex[2].m_rgba = rgba; + vertex[2].m_u = prim->texcoords.br.u; + vertex[2].m_v = prim->texcoords.br.v; + + vertex[3].m_x = prim->bounds.x1; + vertex[3].m_y = prim->bounds.y1; + vertex[3].m_z = 0; + vertex[3].m_rgba = rgba; + vertex[3].m_u = prim->texcoords.br.u; + vertex[3].m_v = prim->texcoords.br.v; + + vertex[4].m_x = prim->bounds.x0; + vertex[4].m_y = prim->bounds.y1; + vertex[4].m_z = 0; + vertex[4].m_rgba = rgba; + vertex[4].m_u = prim->texcoords.bl.u; + vertex[4].m_v = prim->texcoords.bl.v; + + vertex[5].m_x = prim->bounds.x0; + vertex[5].m_y = prim->bounds.y0; + vertex[5].m_z = 0; + vertex[5].m_rgba = rgba; + vertex[5].m_u = prim->texcoords.tl.u; + vertex[5].m_v = prim->texcoords.tl.v; bgfx::setVertexBuffer(&vb); - } -} + uint32_t texture_flags = BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP; + if (video_config.filter == 0) + { + texture_flags |= BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT; + } + + const bgfx::Memory* mem = mame_texture_data_to_bgfx_texture_data(prim->flags & PRIMFLAG_TEXFORMAT_MASK, + prim->texture.width, prim->texture.height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base); -struct PosColorVertex -{ - float m_x; - float m_y; - uint32_t m_abgr; + bgfx::TextureHandle texture = bgfx::createTexture2D((uint16_t)prim->texture.width, (uint16_t)prim->texture.height, 1, bgfx::TextureFormat::BGRA8, texture_flags, mem); - static void init() - { - ms_decl - .begin() - .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float) - .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) - .end(); + bgfx::setTexture(0, m_s_texColor, texture); + + set_bgfx_state(PRIMFLAG_GET_BLENDMODE(prim->flags)); + bgfx::submit(view, m_progQuadTexture); + + bgfx::destroyTexture(texture); } +} - static bgfx::VertexDecl ms_decl; -}; -bgfx::VertexDecl PosColorVertex::ms_decl; +bgfx::VertexDecl renderer_bgfx::PosColorVertex::ms_decl; #define MAX_TEMP_COORDS 100 -void drawPolygon(const float* _coords, uint32_t _numCoords, float _r, uint32_t _abgr) +void renderer_bgfx::put_polygon(const float* coords, UINT32 num_coords, float r, UINT32 rgba, PosColorVertex* vertex) { - float tempCoords[MAX_TEMP_COORDS * 2]; + float tempCoords[MAX_TEMP_COORDS * 3]; float tempNormals[MAX_TEMP_COORDS * 2]; - _numCoords = _numCoords < MAX_TEMP_COORDS ? _numCoords : MAX_TEMP_COORDS; + num_coords = num_coords < MAX_TEMP_COORDS ? num_coords : MAX_TEMP_COORDS; - for (uint32_t ii = 0, jj = _numCoords - 1; ii < _numCoords; jj = ii++) + for (uint32_t ii = 0, jj = num_coords - 1; ii < num_coords; jj = ii++) { - const float* v0 = &_coords[jj * 2]; - const float* v1 = &_coords[ii * 2]; + const float* v0 = &coords[jj * 3]; + const float* v1 = &coords[ii * 3]; float dx = v1[0] - v0[0]; float dy = v1[1] - v0[1]; float d = sqrtf(dx * dx + dy * dy); @@ -433,7 +428,7 @@ void drawPolygon(const float* _coords, uint32_t _numCoords, float _r, uint32_t _ tempNormals[jj * 2 + 1] = -dx; } - for (uint32_t ii = 0, jj = _numCoords - 1; ii < _numCoords; jj = ii++) + for (uint32_t ii = 0, jj = num_coords - 1; ii < num_coords; jj = ii++) { float dlx0 = tempNormals[jj * 2 + 0]; float dly0 = tempNormals[jj * 2 + 1]; @@ -454,77 +449,78 @@ void drawPolygon(const float* _coords, uint32_t _numCoords, float _r, uint32_t _ dmy *= scale; } - tempCoords[ii * 2 + 0] = _coords[ii * 2 + 0] + dmx * _r; - tempCoords[ii * 2 + 1] = _coords[ii * 2 + 1] + dmy * _r; + tempCoords[ii * 3 + 0] = coords[ii * 3 + 0] + dmx * r; + tempCoords[ii * 3 + 1] = coords[ii * 3 + 1] + dmy * r; + tempCoords[ii * 3 + 2] = coords[ii * 3 + 2]; } - uint32_t numVertices = _numCoords * 6 + (_numCoords - 2) * 3; - if (bgfx::checkAvailTransientVertexBuffer(numVertices, PosColorVertex::ms_decl)) + int vertIndex = 0; + UINT32 trans = rgba & 0x00ffffff; + for (uint32_t ii = 0, jj = num_coords - 1; ii < num_coords; jj = ii++) { - bgfx::TransientVertexBuffer tvb; - bgfx::allocTransientVertexBuffer(&tvb, numVertices, PosColorVertex::ms_decl); - uint32_t trans = _abgr & 0xffffff; - - PosColorVertex* vertex = (PosColorVertex*)tvb.data; - for (uint32_t ii = 0, jj = _numCoords - 1; ii < _numCoords; jj = ii++) - { - vertex->m_x = _coords[ii * 2 + 0]; - vertex->m_y = _coords[ii * 2 + 1]; - vertex->m_abgr = _abgr; - ++vertex; - - vertex->m_x = _coords[jj * 2 + 0]; - vertex->m_y = _coords[jj * 2 + 1]; - vertex->m_abgr = _abgr; - ++vertex; - - vertex->m_x = tempCoords[jj * 2 + 0]; - vertex->m_y = tempCoords[jj * 2 + 1]; - vertex->m_abgr = trans; - ++vertex; - - vertex->m_x = tempCoords[jj * 2 + 0]; - vertex->m_y = tempCoords[jj * 2 + 1]; - vertex->m_abgr = trans; - ++vertex; - - vertex->m_x = tempCoords[ii * 2 + 0]; - vertex->m_y = tempCoords[ii * 2 + 1]; - vertex->m_abgr = trans; - ++vertex; - - vertex->m_x = _coords[ii * 2 + 0]; - vertex->m_y = _coords[ii * 2 + 1]; - vertex->m_abgr = _abgr; - ++vertex; - } - - for (uint32_t ii = 2; ii < _numCoords; ++ii) - { - vertex->m_x = _coords[0]; - vertex->m_y = _coords[1]; - vertex->m_abgr = _abgr; - ++vertex; - - vertex->m_x = _coords[(ii - 1) * 2 + 0]; - vertex->m_y = _coords[(ii - 1) * 2 + 1]; - vertex->m_abgr = _abgr; - ++vertex; - - vertex->m_x = _coords[ii * 2 + 0]; - vertex->m_y = _coords[ii * 2 + 1]; - vertex->m_abgr = _abgr; - ++vertex; - } + vertex[vertIndex].m_x = coords[ii * 3 + 0]; + vertex[vertIndex].m_y = coords[ii * 3 + 1]; + vertex[vertIndex].m_z = coords[ii * 3 + 2]; + vertex[vertIndex].m_rgba = rgba; + vertIndex++; + + vertex[vertIndex].m_x = coords[jj * 3 + 0]; + vertex[vertIndex].m_y = coords[jj * 3 + 1]; + vertex[vertIndex].m_z = coords[jj * 3 + 2]; + vertex[vertIndex].m_rgba = rgba; + vertIndex++; + + vertex[vertIndex].m_x = tempCoords[jj * 3 + 0]; + vertex[vertIndex].m_y = tempCoords[jj * 3 + 1]; + vertex[vertIndex].m_z = tempCoords[jj * 3 + 2]; + vertex[vertIndex].m_rgba = trans; + vertIndex++; + + vertex[vertIndex].m_x = tempCoords[jj * 3 + 0]; + vertex[vertIndex].m_y = tempCoords[jj * 3 + 1]; + vertex[vertIndex].m_z = tempCoords[jj * 3 + 2]; + vertex[vertIndex].m_rgba = trans; + vertIndex++; + + vertex[vertIndex].m_x = tempCoords[ii * 3 + 0]; + vertex[vertIndex].m_y = tempCoords[ii * 3 + 1]; + vertex[vertIndex].m_z = tempCoords[ii * 3 + 2]; + vertex[vertIndex].m_rgba = trans; + vertIndex++; + + vertex[vertIndex].m_x = coords[ii * 3 + 0]; + vertex[vertIndex].m_y = coords[ii * 3 + 1]; + vertex[vertIndex].m_z = coords[ii * 3 + 2]; + vertex[vertIndex].m_rgba = rgba; + vertIndex++; + } - bgfx::setVertexBuffer(&tvb); + for (uint32_t ii = 2; ii < num_coords; ++ii) + { + vertex[vertIndex].m_x = coords[0]; + vertex[vertIndex].m_y = coords[1]; + vertex[vertIndex].m_z = coords[2]; + vertex[vertIndex].m_rgba = rgba; + vertIndex++; + + vertex[vertIndex].m_x = coords[(ii - 1) * 3 + 0]; + vertex[vertIndex].m_y = coords[(ii - 1) * 3 + 1]; + vertex[vertIndex].m_z = coords[(ii - 1) * 3 + 2]; + vertex[vertIndex].m_rgba = rgba; + vertIndex++; + + vertex[vertIndex].m_x = coords[ii * 3 + 0]; + vertex[vertIndex].m_y = coords[ii * 3 + 1]; + vertex[vertIndex].m_z = coords[ii * 3 + 2]; + vertex[vertIndex].m_rgba = rgba; + vertIndex++; } } -void drawLine(float _x0, float _y0, float _x1, float _y1, float _r, uint32_t _abgr, float _fth = 1.0f) +void renderer_bgfx::put_line(float x0, float y0, float x1, float y1, float r, UINT32 rgba, PosColorVertex* vertex, float fth) { - float dx = _x1 - _x0; - float dy = _y1 - _y0; + float dx = x1 - x0; + float dy = y1 - y0; float d = sqrtf(dx * dx + dy * dy); if (d > 0.0001f) { @@ -535,49 +531,41 @@ void drawLine(float _x0, float _y0, float _x1, float _y1, float _r, uint32_t _ab float nx = dy; float ny = -dx; - float verts[4 * 2]; - _r -= _fth; - _r *= 0.5f; - if (_r < 0.01f) + float verts[4 * 3]; + r -= fth; + r *= 0.5f; + if (r < 0.01f) { - _r = 0.01f; + r = 0.01f; } - dx *= _r; - dy *= _r; - nx *= _r; - ny *= _r; + dx *= r; + dy *= r; + nx *= r; + ny *= r; - verts[0] = _x0 - dx - nx; - verts[1] = _y0 - dy - ny; + verts[0] = x0 - dx - nx; + verts[1] = y0 - dy - ny; + verts[2] = 0; - verts[2] = _x0 - dx + nx; - verts[3] = _y0 - dy + ny; + verts[3] = x0 - dx + nx; + verts[4] = y0 - dy + ny; + verts[5] = 0; - verts[4] = _x1 + dx + nx; - verts[5] = _y1 + dy + ny; + verts[6] = x1 + dx + nx; + verts[7] = y1 + dy + ny; + verts[8] = 0; - verts[6] = _x1 + dx - nx; - verts[7] = _y1 + dy - ny; + verts[9] = x1 + dx - nx; + verts[10] = y1 + dy - ny; + verts[11] = 0; - drawPolygon(verts, 4, _fth, _abgr); + put_polygon(verts, 4, fth, rgba, vertex); } -void initVertexDecls() +uint32_t renderer_bgfx::u32Color(uint32_t r, uint32_t g, uint32_t b, uint32_t a = 255) { - PosColorTexCoord0Vertex::init(); - PosColorVertex::init(); -} - -static inline -uint32_t u32Color(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a = 255) -{ - return 0 - | (uint32_t(_r) << 0) - | (uint32_t(_g) << 8) - | (uint32_t(_b) << 16) - | (uint32_t(_a) << 24) - ; + return (a << 24) | (b << 16) | (g << 8) | r; } //============================================================ @@ -609,9 +597,9 @@ static inline void copyline_palettea16(UINT32 *dst, const UINT16 *src, int width static inline void copyline_rgb32(UINT32 *dst, const UINT32 *src, int width, const rgb_t *palette) { int x; - + // palette (really RGB map) case - if (palette != NULL) + if (palette != nullptr) { for (x = 0; x < width; x++) { @@ -637,7 +625,7 @@ static inline void copyline_argb32(UINT32 *dst, const UINT32 *src, int width, co { int x; // palette (really RGB map) case - if (palette != NULL) + if (palette != nullptr) { for (x = 0; x < width; x++) { @@ -706,7 +694,7 @@ static inline void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int wi assert(width % 2 == 0); // palette (really RGB map) case - if (palette != NULL) + if (palette != nullptr) { for (x = 0; x < width / 2; x++) { @@ -737,9 +725,38 @@ static inline void copyline_yuy16_to_argb(UINT32 *dst, const UINT16 *src, int wi } } } + +const bgfx::Memory* renderer_bgfx::mame_texture_data_to_bgfx_texture_data(UINT32 format, int width, int height, int rowpixels, const rgb_t *palette, void *base) +{ + const bgfx::Memory* mem = bgfx::alloc(width * height * 4); + for (int y = 0; y < height; y++) + { + switch (format) + { + case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16): + copyline_palette16((UINT32*)mem->data + y * width, (UINT16*)base + y * rowpixels, width, palette); + break; + case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTEA16): + copyline_palettea16((UINT32*)mem->data + y * width, (UINT16*)base + y * rowpixels, width, palette); + break; + case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16): + copyline_yuy16_to_argb((UINT32*)mem->data + y * width, (UINT16*)base + y * rowpixels, width, palette, 1); + break; + case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32): + copyline_argb32((UINT32*)mem->data + y * width, (UINT32*)base + y * rowpixels, width, palette); + break; + case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32): + copyline_rgb32((UINT32*)mem->data + y * width, (UINT32*)base + y * rowpixels, width, palette); + break; + default: + break; + } + } + return mem; +} + int renderer_bgfx::draw(int update) { - initVertexDecls(); int index = window().m_index; // Set view 0 default viewport. osd_dim wdim = window().get_size(); @@ -806,154 +823,48 @@ int renderer_bgfx::draw(int update) bgfx::touch(index); window().m_primlist->acquire_lock(); - // Draw quad. - // now draw - uint32_t texture_flags = BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP; - if (video_config.filter==0) texture_flags |= BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT; - - for (render_primitive *prim = window().m_primlist->first(); prim != NULL; prim = prim->next()) - { - uint64_t flags = BGFX_STATE_RGB_WRITE; - switch (prim->flags & PRIMFLAG_BLENDMODE_MASK) - { - case PRIMFLAG_BLENDMODE(BLENDMODE_NONE): - break; - case PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA): - flags |= BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA); - break; - case PRIMFLAG_BLENDMODE(BLENDMODE_RGB_MULTIPLY): - flags |= BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_ZERO); - break; - case PRIMFLAG_BLENDMODE(BLENDMODE_ADD): - flags |= BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_ONE); - } - bool alpha = false; + + bgfx::TransientVertexBuffer flat_buffer[4]; + bgfx::TransientVertexBuffer textured_buffer[4]; + + allocate_buffers(flat_buffer, textured_buffer); + + int flat_vertices[4] = { 0, 0, 0, 0 }; + int textured_vertices[4] = { 0, 0, 0, 0 }; + + // Mark our texture atlas as dirty if we need to do so + bool atlas_valid = update_atlas(); + + memset(flat_vertices, 0, sizeof(int) * 4); + memset(textured_vertices, 0, sizeof(int) * 4); + + for (render_primitive *prim = window().m_primlist->first(); prim != nullptr; prim = prim->next()) + { + UINT32 blend = PRIMFLAG_GET_BLENDMODE(prim->flags); + switch (prim->type) { - /** - * Try to stay in one Begin/End block as long as possible, - * since entering and leaving one is most expensive.. - */ case render_primitive::LINE: - - drawLine(prim->bounds.x0, prim->bounds.y0, prim->bounds.x1, prim->bounds.y1, - 1.0f, - u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255), - 1.0f); - bgfx::setState(flags); - bgfx::submit(index, m_progLine); + put_line(prim->bounds.x0, prim->bounds.y0, prim->bounds.x1, prim->bounds.y1, 1.0f, u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255), (PosColorVertex*)flat_buffer[blend].data + flat_vertices[blend], 1.0f); + flat_vertices[blend] += 30; break; case render_primitive::QUAD: - if (prim->texture.base == nullptr) { - render_quad_texuv uv; - uv.tl.u = uv.tl.v = uv.tr.u = uv.tr.v = 0; - uv.bl.u = uv.bl.v = uv.br.u = uv.br.v = 0; - screenQuad(prim->bounds.x0, prim->bounds.y0, prim->bounds.x1, prim->bounds.y1, - u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255), uv); - bgfx::setState(flags); - bgfx::submit(index, m_progQuad); + if (prim->texture.base == nullptr) + { + render_flat_quad(index, prim); } - else { - screenQuad(prim->bounds.x0, prim->bounds.y0, prim->bounds.x1, prim->bounds.y1, - u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255), prim->texcoords); - bgfx::TextureHandle m_texture; - // render based on the texture coordinates - switch (prim->flags & PRIMFLAG_TEXFORMAT_MASK) + else + { + if (atlas_valid && (prim->flags & PRIMFLAG_PACKABLE) && prim->texture.hash != 0 && m_hash_to_entry[prim->texture.hash].hash()) { - case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTEA16): - alpha = true; - case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16): - { - auto mem = bgfx::alloc(prim->texture.width*prim->texture.height * 4); - if (alpha) - { - for (int y = 0; y < prim->texture.height; y++) - { - copyline_palettea16((UINT32*)mem->data + y*prim->texture.width, (UINT16*)prim->texture.base + y*prim->texture.rowpixels, prim->texture.width, prim->texture.palette); - } - } - else - { - for (int y = 0; y < prim->texture.height; y++) - { - copyline_palette16((UINT32*)mem->data + y*prim->texture.width, (UINT16*)prim->texture.base + y*prim->texture.rowpixels, prim->texture.width, prim->texture.palette); - } - } - - m_texture = bgfx::createTexture2D((uint16_t)prim->texture.width - , (uint16_t)prim->texture.height - , 1 - , bgfx::TextureFormat::BGRA8 - , texture_flags - , mem - ); - } - break; - case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16): - { - auto mem = bgfx::alloc(prim->texture.width*prim->texture.height * 4); - for (int y = 0; y < prim->texture.height; y++) - { - copyline_yuy16_to_argb((UINT32*)mem->data + y*prim->texture.width, (UINT16*)prim->texture.base + y*prim->texture.rowpixels, prim->texture.width, prim->texture.palette, 1); - } - m_texture = bgfx::createTexture2D((uint16_t)prim->texture.width - , (uint16_t)prim->texture.height - , 1 - , bgfx::TextureFormat::BGRA8 - , texture_flags - , mem - ); - } - break; - case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32): - alpha = true; - case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32): - { - if (prim->texture.rowpixels!=prim->texture.width) - { - auto mem = bgfx::alloc(prim->texture.width*prim->texture.height * 4); - if (alpha) - { - for (int y = 0; y < prim->texture.height; y++) - { - copyline_argb32((UINT32*)mem->data + y*prim->texture.width, (UINT32*)prim->texture.base + y*prim->texture.rowpixels, prim->texture.width, prim->texture.palette); - } - } - else - { - for (int y = 0; y < prim->texture.height; y++) - { - copyline_rgb32((UINT32*)mem->data + y*prim->texture.width, (UINT32*)prim->texture.base + y*prim->texture.rowpixels, prim->texture.width, prim->texture.palette); - } - } - - m_texture = bgfx::createTexture2D((uint16_t)prim->texture.width - , (uint16_t)prim->texture.height - , 1 - , bgfx::TextureFormat::BGRA8 - , texture_flags - , mem - ); - } else { - m_texture = bgfx::createTexture2D((uint16_t)prim->texture.width - , (uint16_t)prim->texture.height - , 1 - , bgfx::TextureFormat::BGRA8 - , texture_flags - , bgfx::copy(prim->texture.base, prim->texture.width*prim->texture.height*4) - ); - } - } - break; - - default: - break; + put_packed_quad(prim, prim->texture.hash, (PosColorTexCoord0Vertex*)textured_buffer[blend].data + textured_vertices[blend]); + textured_vertices[blend] += 6; + } + else + { + render_textured_quad(index, prim); } - bgfx::setTexture(0, m_s_texColor, m_texture); - bgfx::setState(flags); - bgfx::submit(index, m_progQuadTexture); - bgfx::destroyTexture(m_texture); } break; @@ -962,6 +873,27 @@ int renderer_bgfx::draw(int update) } } + for (UINT32 blend_mode = 0; blend_mode < BLENDMODE_COUNT; blend_mode++) + { + if (flat_vertices[blend_mode] > 0) + { + set_bgfx_state(blend_mode); + bgfx::setVertexBuffer(&flat_buffer[blend_mode]); + bgfx::submit(index, m_progQuad); + } + } + + for (UINT32 blend_mode = 0; blend_mode < BLENDMODE_COUNT; blend_mode++) + { + if (textured_vertices[blend_mode] > 0) + { + set_bgfx_state(blend_mode); + bgfx::setVertexBuffer(&textured_buffer[blend_mode]); + bgfx::setTexture(0, m_s_texColor, m_texture_cache); + bgfx::submit(index, m_progQuadTexture); + } + } + window().m_primlist->release_lock(); // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. @@ -969,3 +901,170 @@ int renderer_bgfx::draw(int update) return 0; } + +void renderer_bgfx::set_bgfx_state(UINT32 blend) +{ + uint64_t flags = BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_DEPTH_TEST_ALWAYS; + + switch (blend) + { + case BLENDMODE_NONE: + bgfx::setState(flags); + break; + case BLENDMODE_ALPHA: + bgfx::setState(flags | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)); + break; + case BLENDMODE_RGB_MULTIPLY: + bgfx::setState(flags | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_ZERO)); + break; + case BLENDMODE_ADD: + bgfx::setState(flags | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_ONE)); + break; + } +} + +void renderer_bgfx::render_flat_quad(int view, render_primitive *prim) +{ + if (bgfx::checkAvailTransientVertexBuffer(6, PosColorVertex::ms_decl)) + { + bgfx::TransientVertexBuffer vb; + bgfx::allocTransientVertexBuffer(&vb, 6, PosColorVertex::ms_decl); + PosColorVertex* vertex = (PosColorVertex*)vb.data; + + UINT32 rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); + + vertex[0].m_x = prim->bounds.x0; + vertex[0].m_y = prim->bounds.y0; + vertex[0].m_z = 0; + vertex[0].m_rgba = rgba; + + vertex[1].m_x = prim->bounds.x1; + vertex[1].m_y = prim->bounds.y0; + vertex[1].m_z = 0; + vertex[1].m_rgba = rgba; + + vertex[2].m_x = prim->bounds.x1; + vertex[2].m_y = prim->bounds.y1; + vertex[2].m_z = 0; + vertex[2].m_rgba = rgba; + + vertex[3].m_x = prim->bounds.x1; + vertex[3].m_y = prim->bounds.y1; + vertex[3].m_z = 0; + vertex[3].m_rgba = rgba; + + vertex[4].m_x = prim->bounds.x0; + vertex[4].m_y = prim->bounds.y1; + vertex[4].m_z = 0; + vertex[4].m_rgba = rgba; + + vertex[5].m_x = prim->bounds.x0; + vertex[5].m_y = prim->bounds.y0; + vertex[5].m_z = 0; + vertex[5].m_rgba = rgba; + bgfx::setVertexBuffer(&vb); + + set_bgfx_state(PRIMFLAG_GET_BLENDMODE(prim->flags)); + bgfx::submit(view, m_progQuad); + } +} + +bool renderer_bgfx::update_atlas() +{ + bool atlas_dirty = check_for_dirty_atlas(); + + if (atlas_dirty) + { + m_hash_to_entry.clear(); + + std::vector<std::vector<rectangle_packer::packed_rectangle>> packed; + if (m_packer.pack(m_texinfo, packed, 1024)) + { + for (std::vector<rectangle_packer::packed_rectangle> pack : packed) + { + for (rectangle_packer::packed_rectangle rect : pack) + { + if (rect.hash() == 0xffffffff) + { + continue; + } + m_hash_to_entry[rect.hash()] = rect; + const bgfx::Memory* mem = mame_texture_data_to_bgfx_texture_data(rect.format(), rect.width(), rect.height(), rect.rowpixels(), rect.palette(), rect.base()); + bgfx::updateTexture2D(m_texture_cache, 0, rect.x(), rect.y(), rect.width(), rect.height(), mem); + } + } + } + else + { + m_texinfo.clear(); + return false; + } + } + return true; +} + +bool renderer_bgfx::check_for_dirty_atlas() +{ + bool atlas_dirty = false; + + std::map<UINT32, rectangle_packer::packable_rectangle> acquired_infos; + for (render_primitive *prim = window().m_primlist->first(); prim != nullptr; prim = prim->next()) + { + bool pack = prim->flags & PRIMFLAG_PACKABLE; + if (prim->type == render_primitive::QUAD && prim->texture.base != nullptr && pack) + { + const UINT32 hash = prim->texture.hash; + + // If this texture is packable and not currently in the atlas, prepare the texture for putting in the atlas + if (hash != 0 && m_hash_to_entry[hash].hash() == 0 && acquired_infos[hash].hash() == 0) + { // Create create the texture and mark the atlas dirty + atlas_dirty = true; + + m_texinfo.push_back(rectangle_packer::packable_rectangle(hash, prim->flags & PRIMFLAG_TEXFORMAT_MASK, + prim->texture.width, prim->texture.height, + prim->texture.rowpixels, prim->texture.palette, prim->texture.base)); + acquired_infos[hash] = m_texinfo[m_texinfo.size() - 1]; + } + } + } + + return atlas_dirty; +} + +void renderer_bgfx::allocate_buffers(bgfx::TransientVertexBuffer *flat_buffer, bgfx::TransientVertexBuffer *textured_buffer) +{ + int flat_vertices[4] = { 0, 0, 0, 0 }; + int textured_vertices[4] = { 0, 0, 0, 0 }; + + for (render_primitive *prim = window().m_primlist->first(); prim != nullptr; prim = prim->next()) + { + switch (prim->type) + { + case render_primitive::LINE: + flat_vertices[PRIMFLAG_GET_BLENDMODE(prim->flags)] += 30; + break; + + case render_primitive::QUAD: + if (prim->flags & PRIMFLAG_PACKABLE && prim->texture.base != nullptr && prim->texture.hash != 0) + { + textured_vertices[PRIMFLAG_GET_BLENDMODE(prim->flags)] += 6; + } + break; + default: + // Do nothing + break; + } + } + + for (int blend_mode = 0; blend_mode < 4; blend_mode++) + { + if (flat_vertices[blend_mode] > 0 && bgfx::checkAvailTransientVertexBuffer(flat_vertices[blend_mode], PosColorVertex::ms_decl)) + { + bgfx::allocTransientVertexBuffer(&flat_buffer[blend_mode], flat_vertices[blend_mode], PosColorVertex::ms_decl); + } + if (textured_vertices[blend_mode] > 0 && bgfx::checkAvailTransientVertexBuffer(textured_vertices[blend_mode], PosColorTexCoord0Vertex::ms_decl)) + { + bgfx::allocTransientVertexBuffer(&textured_buffer[blend_mode], textured_vertices[blend_mode], PosColorTexCoord0Vertex::ms_decl); + } + } +} diff --git a/src/osd/modules/render/drawbgfx.h b/src/osd/modules/render/drawbgfx.h new file mode 100644 index 00000000000..b0cab8c8193 --- /dev/null +++ b/src/osd/modules/render/drawbgfx.h @@ -0,0 +1,115 @@ +#pragma once + +#ifndef __RENDER_BGFX__ +#define __RENDER_BGFX__ + +#include <map> +#include <vector> + +#include "binpacker.h" + +/* sdl_info is the information about SDL for the current screen */ +class renderer_bgfx : public osd_renderer +{ +public: + renderer_bgfx(osd_window *w) + : osd_renderer(w, FLAG_NONE) + , m_dimensions(0, 0) + { + } + + virtual int create() override; + virtual int draw(const int update) override; +#ifdef OSD_SDL + virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override; +#else + virtual void save() override { } + virtual void record() override { } + virtual void toggle_fsfx() override { } +#endif + virtual void destroy() override; + virtual render_primitive_list *get_primitives() override + { + osd_dim wdim = window().get_size(); + window().target()->set_bounds(wdim.width(), wdim.height(), window().aspect()); + return &window().target()->get_primitives(); + } + +private: + struct PosColorTexCoord0Vertex + { + float m_x; + float m_y; + float m_z; + UINT32 m_rgba; + float m_u; + float m_v; + + static void init() + { + ms_decl.begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) + .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) + .end(); + } + + static bgfx::VertexDecl ms_decl; + }; + + struct PosColorVertex + { + float m_x; + float m_y; + float m_z; + UINT32 m_rgba; + + static void init() + { + ms_decl + .begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) + .end(); + } + + static bgfx::VertexDecl ms_decl; + }; + + void allocate_buffers(bgfx::TransientVertexBuffer *flat_buffer, bgfx::TransientVertexBuffer *textured_buffer); + + void render_textured_quad(int view, render_primitive* prim); + void render_flat_quad(int view, render_primitive *prim); + + void put_packed_quad(render_primitive *prim, UINT32 hash, PosColorTexCoord0Vertex* vertex); + void put_polygon(const float* coords, UINT32 num_coords, float r, UINT32 rgba, PosColorVertex* vertex); + void put_line(float x0, float y0, float x1, float y1, float r, UINT32 rgba, PosColorVertex* vertex, float fth = 1.0f); + + void set_bgfx_state(UINT32 blend); + + uint32_t u32Color(uint32_t r, uint32_t g, uint32_t b, uint32_t a); + + bool check_for_dirty_atlas(); + bool update_atlas(); + const bgfx::Memory* mame_texture_data_to_bgfx_texture_data(UINT32 format, int width, int height, int rowpixels, const rgb_t *palette, void *base); + + bgfx::ProgramHandle loadProgram(bx::FileReaderI* _reader, const char* _vsName, const char* _fsName); + bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName); + + bgfx::ProgramHandle m_progQuad; + bgfx::ProgramHandle m_progQuadTexture; + bgfx::UniformHandle m_s_texColor; + bgfx::FrameBufferHandle fbh; + bgfx::TextureHandle m_texture_cache; + + // Original display_mode + osd_dim m_dimensions; + + std::map<UINT32, rectangle_packer::packed_rectangle> m_hash_to_entry; + std::vector<rectangle_packer::packable_rectangle> m_texinfo; + rectangle_packer m_packer; + + static const uint16_t CACHE_SIZE = 1024; +}; + +#endif
\ No newline at end of file |