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:
sinamas 2008-03-03 12:01:59 +00:00
parent 8a07c109f3
commit bbe37130ba
7 changed files with 255 additions and 56 deletions

View File

@ -20,7 +20,6 @@
#define QGLBLITTER_H
#include "../blitterwidget.h"
#include <stdint.h>
#include <memory>
class QCheckBox;

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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
View 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