mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2025-02-17 07:10:19 +00:00
add unrestricted fast bilinear and nearest neighbor sw scaling to x11/qpainter blitter
git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@127 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
8a07c109f3
commit
bbe37130ba
@ -20,7 +20,6 @@
|
||||
#define QGLBLITTER_H
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
class QCheckBox;
|
||||
|
@ -17,27 +17,43 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "qpainterblitter.h"
|
||||
|
||||
#include "../scalebuffer.h"
|
||||
|
||||
#include "../swscale.h"
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <QPaintEvent>
|
||||
|
||||
#include <algorithm>
|
||||
#include <QVBoxLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QSettings>
|
||||
|
||||
QPainterBlitter::QPainterBlitter(PixelBufferSetter setPixelBuffer, QWidget *parent) :
|
||||
BlitterWidget(setPixelBuffer, "QPainter", true, parent),
|
||||
BlitterWidget(setPixelBuffer, "QPainter", false, parent),
|
||||
confWidget(new QWidget),
|
||||
bfBox(new QCheckBox(QString("Bilinear filtering"))),
|
||||
buffer(NULL),
|
||||
inWidth(160),
|
||||
inHeight(144),
|
||||
scale(0)
|
||||
bf(false)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("qpainterblitter");
|
||||
bf = settings.value("bf", false).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
confWidget->setLayout(new QVBoxLayout);
|
||||
confWidget->layout()->setMargin(0);
|
||||
confWidget->layout()->addWidget(bfBox);
|
||||
bfBox->setChecked(bf);
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
}
|
||||
|
||||
QPainterBlitter::~QPainterBlitter() {
|
||||
uninit();
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("qpainterblitter");
|
||||
settings.setValue("bf", bf);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void QPainterBlitter::blit() {
|
||||
@ -45,8 +61,12 @@ void QPainterBlitter::blit() {
|
||||
}
|
||||
|
||||
void QPainterBlitter::paintEvent(QPaintEvent *const event) {
|
||||
if (buffer)
|
||||
scaleBuffer(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, image->bytesPerLine() >> 2, scale);
|
||||
if (buffer) {
|
||||
if (bf)
|
||||
linearScale<quint32, 0xFF00FF, 0x00FF00, 8>(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, width(), height(), image->bytesPerLine() >> 2);
|
||||
else
|
||||
nearestNeighborScale(buffer, reinterpret_cast<quint32*>(image->bits()), inWidth, inHeight, width(), height(), image->bytesPerLine() >> 2);
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setClipRegion(event->region());
|
||||
@ -54,26 +74,18 @@ void QPainterBlitter::paintEvent(QPaintEvent *const event) {
|
||||
}
|
||||
|
||||
void QPainterBlitter::resizeEvent(QResizeEvent */*event*/) {
|
||||
const unsigned newScale = std::min(width() / inWidth, height() / inHeight);
|
||||
|
||||
if (newScale != scale) {
|
||||
scale = newScale;
|
||||
|
||||
if (image.get())
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
}
|
||||
if (image.get())
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
}
|
||||
|
||||
void QPainterBlitter::setBufferDimensions(const unsigned int w, const unsigned int h) {
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
scale = std::min(width() / w, height() / h);
|
||||
|
||||
uninit();
|
||||
image.reset(new QImage(w * scale, h * scale, QImage::Format_RGB32));
|
||||
image.reset(new QImage(width(), height(), QImage::Format_RGB32));
|
||||
|
||||
if (scale > 1) {
|
||||
if (width() != static_cast<int>(w) || height() != static_cast<int>(h)) {
|
||||
buffer = new quint32[w * h];
|
||||
setPixelBuffer(buffer, MediaSource::RGB32, w);
|
||||
} else
|
||||
@ -86,3 +98,11 @@ void QPainterBlitter::uninit() {
|
||||
delete []buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
void QPainterBlitter::acceptSettings() {
|
||||
bf = bfBox->isChecked();
|
||||
}
|
||||
|
||||
void QPainterBlitter::rejectSettings() {
|
||||
bfBox->setChecked(bf);
|
||||
}
|
||||
|
@ -20,17 +20,19 @@
|
||||
#define QPAINTERBLITTER_H
|
||||
|
||||
#include "../blitterwidget.h"
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
class QPainter;
|
||||
class QImage;
|
||||
class QCheckBox;
|
||||
|
||||
class QPainterBlitter : public BlitterWidget {
|
||||
const std::auto_ptr<QWidget> confWidget;
|
||||
std::auto_ptr<QImage> image;
|
||||
QCheckBox *const bfBox;
|
||||
quint32 *buffer;
|
||||
unsigned int inWidth, inHeight;
|
||||
unsigned int scale;
|
||||
bool bf;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
@ -42,6 +44,9 @@ public:
|
||||
void blit();
|
||||
void setBufferDimensions(unsigned int w, unsigned int h);
|
||||
void uninit();
|
||||
QWidget* settingsWidget() { return confWidget.get(); }
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -16,21 +16,18 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include <QPaintEvent>
|
||||
|
||||
#include "x11blitter.h"
|
||||
|
||||
#include "../scalebuffer.h"
|
||||
|
||||
#include "../swscale.h"
|
||||
#include <QPaintEvent>
|
||||
#include <QX11Info>
|
||||
#include <X11/Xlib.h>
|
||||
// #include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QSettings>
|
||||
#include <videoblitter.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class X11Blitter::SubBlitter {
|
||||
@ -150,17 +147,23 @@ unsigned X11Blitter::PlainBlitter::pitch() const {
|
||||
}
|
||||
|
||||
X11Blitter::X11Blitter(PixelBufferSetter setPixelBuffer, QWidget *parent) :
|
||||
BlitterWidget(setPixelBuffer, QString("X11"), true, parent),
|
||||
BlitterWidget(setPixelBuffer, QString("X11"), false, parent),
|
||||
confWidget(new QWidget),
|
||||
bfBox(new QCheckBox(QString("Bilinear filtering"))),
|
||||
buffer(NULL),
|
||||
inWidth(160),
|
||||
inHeight(144),
|
||||
scale(0)
|
||||
bf(false)
|
||||
{
|
||||
/*QPalette pal = palette();
|
||||
pal.setColor(QPalette::Window, QColor(0,0,0));
|
||||
setPalette(pal);
|
||||
setBackgroundRole(QPalette::Window);
|
||||
setAutoFillBackground(true);*/
|
||||
QSettings settings;
|
||||
settings.beginGroup("x11blitter");
|
||||
bf = settings.value("bf", false).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
confWidget->setLayout(new QVBoxLayout);
|
||||
confWidget->layout()->setMargin(0);
|
||||
confWidget->layout()->addWidget(bfBox);
|
||||
bfBox->setChecked(bf);
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
@ -187,6 +190,11 @@ void X11Blitter::uninit() {
|
||||
|
||||
X11Blitter::~X11Blitter() {
|
||||
uninit();
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("x11blitter");
|
||||
settings.setValue("bf", bf);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
int X11Blitter::sync(const bool turbo) {
|
||||
@ -220,12 +228,10 @@ void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h)
|
||||
inWidth = w;
|
||||
inHeight = h;
|
||||
|
||||
scale = std::min(width() / w, height() / h);
|
||||
|
||||
uninit();
|
||||
|
||||
if (shm) {
|
||||
subBlitter.reset(new ShmBlitter(w * scale, h * scale));
|
||||
subBlitter.reset(new ShmBlitter(width(), height()));
|
||||
|
||||
if (subBlitter->failed()) {
|
||||
shm = false;
|
||||
@ -234,9 +240,9 @@ void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h)
|
||||
}
|
||||
|
||||
if (!shm)
|
||||
subBlitter.reset(new PlainBlitter (w * scale, h * scale));
|
||||
subBlitter.reset(new PlainBlitter (width(), height()));
|
||||
|
||||
if (scale > 1) {
|
||||
if (width() != static_cast<int>(w) || height() != static_cast<int>(h)) {
|
||||
buffer = new char[w * h * (QX11Info::appDepth() == 16 ? 2 : 4)];
|
||||
setPixelBuffer(buffer, QX11Info::appDepth() == 16 ? MediaSource::RGB16 : MediaSource::RGB32, w);
|
||||
} else
|
||||
@ -246,9 +252,25 @@ void X11Blitter::setBufferDimensions(const unsigned int w, const unsigned int h)
|
||||
void X11Blitter::blit() {
|
||||
if (buffer) {
|
||||
if (QX11Info::appDepth() == 16) {
|
||||
scaleBuffer(reinterpret_cast<quint16*>(buffer), reinterpret_cast<quint16*>(subBlitter->pixels()), inWidth, inHeight, subBlitter->pitch(), scale);
|
||||
if (bf) {
|
||||
linearScale<quint16, 0xF81F, 0x07E0, 6>(reinterpret_cast<quint16*>(buffer),
|
||||
static_cast<quint16*>(subBlitter->pixels()),
|
||||
inWidth, inHeight, width(), height(), subBlitter->pitch());
|
||||
} else {
|
||||
nearestNeighborScale(reinterpret_cast<quint16*>(buffer),
|
||||
static_cast<quint16*>(subBlitter->pixels()),
|
||||
inWidth, inHeight, width(), height(), subBlitter->pitch());
|
||||
}
|
||||
} else {
|
||||
scaleBuffer(reinterpret_cast<quint32*>(buffer), reinterpret_cast<quint32*>(subBlitter->pixels()), inWidth, inHeight, subBlitter->pitch(), scale);
|
||||
if (bf) {
|
||||
linearScale<quint32, 0xFF00FF, 0x00FF00, 8>(reinterpret_cast<quint32*>(buffer),
|
||||
static_cast<quint32*>(subBlitter->pixels()),
|
||||
inWidth, inHeight, width(), height(), subBlitter->pitch());
|
||||
} else {
|
||||
nearestNeighborScale(reinterpret_cast<quint32*>(buffer),
|
||||
static_cast<quint32*>(subBlitter->pixels()),
|
||||
inWidth, inHeight, width(), height(), subBlitter->pitch());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,12 +279,14 @@ void X11Blitter::blit() {
|
||||
}
|
||||
|
||||
void X11Blitter::resizeEvent(QResizeEvent */*event*/) {
|
||||
const unsigned newScale = std::min(width() / inWidth, height() / inHeight);
|
||||
|
||||
if (newScale != scale) {
|
||||
scale = newScale;
|
||||
|
||||
if (subBlitter.get())
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
}
|
||||
if (subBlitter.get())
|
||||
setBufferDimensions(inWidth, inHeight);
|
||||
}
|
||||
|
||||
void X11Blitter::acceptSettings() {
|
||||
bf = bfBox->isChecked();
|
||||
}
|
||||
|
||||
void X11Blitter::rejectSettings() {
|
||||
bfBox->setChecked(bf);
|
||||
}
|
||||
|
@ -23,16 +23,21 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
class X11Blitter : public BlitterWidget {
|
||||
class SubBlitter;
|
||||
class ShmBlitter;
|
||||
class PlainBlitter;
|
||||
|
||||
const std::auto_ptr<QWidget> confWidget;
|
||||
std::auto_ptr<SubBlitter> subBlitter;
|
||||
QCheckBox *const bfBox;
|
||||
char *buffer;
|
||||
unsigned int inWidth, inHeight;
|
||||
unsigned int scale;
|
||||
// unsigned int scale;
|
||||
bool shm;
|
||||
bool bf;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
@ -47,6 +52,9 @@ public:
|
||||
int sync(bool turbo);
|
||||
void setBufferDimensions(const unsigned width, const unsigned height);
|
||||
void blit();
|
||||
QWidget* settingsWidget() { return confWidget.get(); }
|
||||
void acceptSettings();
|
||||
void rejectSettings();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -46,7 +46,8 @@ SDL_Joystick/src/SDL_sysjoystick.h \
|
||||
gambattesource.h \
|
||||
pixelbuffersetter.h \
|
||||
gambattemenuhandler.h \
|
||||
mainwindow.h
|
||||
mainwindow.h \
|
||||
swscale.h
|
||||
|
||||
TEMPLATE = app
|
||||
CONFIG += warn_on \
|
||||
|
142
gambatte_qt/src/swscale.h
Normal file
142
gambatte_qt/src/swscale.h
Normal file
@ -0,0 +1,142 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SWSCALE_H
|
||||
#define SWSCALE_H
|
||||
|
||||
#include <cstring>
|
||||
|
||||
template<typename T>
|
||||
static void nearestNeighborScale(const T *src, T *dst, const unsigned inWidth, const unsigned inHeight, const unsigned outWidth, const unsigned outHeight, const unsigned dstPitch) {
|
||||
unsigned long vppos = 0;
|
||||
unsigned h = inHeight;
|
||||
|
||||
do {
|
||||
unsigned long hppos = 0;
|
||||
unsigned w = inWidth;
|
||||
|
||||
do {
|
||||
do {
|
||||
*dst++ = *src;
|
||||
hppos += inWidth;
|
||||
} while (hppos < outWidth);
|
||||
|
||||
hppos -= outWidth;
|
||||
++src;
|
||||
} while (--w);
|
||||
|
||||
dst += dstPitch - outWidth;
|
||||
vppos += inHeight;
|
||||
|
||||
while (vppos < outHeight) {
|
||||
std::memcpy(dst, dst - dstPitch, outWidth * sizeof(T));
|
||||
dst += dstPitch;
|
||||
vppos += inHeight;
|
||||
}
|
||||
|
||||
vppos -= outHeight;
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
template<typename T, const T c13mask, const T c2mask, const unsigned c13distance>
|
||||
static void linearScale(const T *src, T *dst, const unsigned inWidth, const unsigned inHeight, const unsigned outWidth, const unsigned outHeight, const unsigned dstPitch) {
|
||||
struct Colorsum {
|
||||
unsigned long c13,c2;
|
||||
};
|
||||
|
||||
Colorsum *const sums = new Colorsum[inWidth + 1];
|
||||
unsigned char *const hcoeffs = new unsigned char[outWidth];
|
||||
|
||||
{
|
||||
unsigned long hppos = 0;
|
||||
unsigned w = inWidth;
|
||||
unsigned char *coeff = hcoeffs;
|
||||
|
||||
do {
|
||||
do {
|
||||
*coeff++ = (hppos << c13distance) / outWidth;
|
||||
hppos += inWidth;
|
||||
} while (hppos < outWidth);
|
||||
|
||||
hppos -= outWidth;
|
||||
} while (--w);
|
||||
}
|
||||
|
||||
unsigned srcPitch = inWidth;
|
||||
unsigned long vppos = 0;
|
||||
unsigned h = inHeight;
|
||||
|
||||
do {
|
||||
do {
|
||||
{
|
||||
const unsigned coeff = (vppos << c13distance) / outHeight;
|
||||
const T *s = src;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = inWidth;
|
||||
|
||||
do {
|
||||
const T p1c13 = *s & c13mask;
|
||||
const T p1c2 = *s & c2mask;
|
||||
const T p2c13 = *(s+srcPitch) & c13mask;
|
||||
const T p2c2 = *(s+srcPitch) & c2mask;
|
||||
|
||||
sum->c13 = p1c13 + ((p2c13 - p1c13) * coeff >> c13distance) & c13mask;
|
||||
sum->c2 = (p1c2 << c13distance) + (p2c2 - p1c2) * coeff;
|
||||
|
||||
++sum;
|
||||
++s;
|
||||
} while (--n);
|
||||
|
||||
*sum = *(sum-1);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned long hppos = 0;
|
||||
const Colorsum *sum = sums;
|
||||
const unsigned char *coeff = hcoeffs;
|
||||
unsigned w = inWidth;
|
||||
|
||||
do {
|
||||
do {
|
||||
*dst++ = sum->c13 + (((sum+1)->c13 - sum->c13) * *coeff >> c13distance) & c13mask |
|
||||
(sum->c2 << c13distance) + ((sum+1)->c2 - sum->c2) * *coeff >> c13distance * 2 & c2mask;
|
||||
hppos += inWidth;
|
||||
++coeff;
|
||||
} while (hppos < outWidth);
|
||||
|
||||
hppos -= outWidth;
|
||||
++sum;
|
||||
} while (--w);
|
||||
}
|
||||
|
||||
dst += dstPitch - outWidth;
|
||||
vppos += inHeight;
|
||||
} while (vppos < outHeight);
|
||||
|
||||
vppos -= outHeight;
|
||||
src += srcPitch;
|
||||
|
||||
if (h == 2)
|
||||
srcPitch = 0;
|
||||
} while (--h);
|
||||
|
||||
delete []sums;
|
||||
delete []hcoeffs;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user