mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
patchupdate.py: Various speed optimizations and improvements, removed several patches (accepted upstream).
This commit is contained in:
parent
e6d0cbe554
commit
db0fd400e4
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,4 @@
|
||||
debian/tools/wine
|
||||
.depcache
|
||||
.srccache
|
||||
.patchupdate.cache
|
||||
*.ok
|
||||
*.pyc
|
||||
|
@ -39,13 +39,12 @@ Wine. All those differences are also documented on the
|
||||
Included bug fixes and improvements
|
||||
===================================
|
||||
|
||||
**Bugfixes and features included in the next upcoming release [6]:**
|
||||
**Bugfixes and features included in the next upcoming release [5]:**
|
||||
|
||||
* Avoid race-conditions of async WSARecv() operations with write watches.
|
||||
* Black & White needs DXTn software decoding support ([Wine Bug #14939](https://bugs.winehq.org/show_bug.cgi?id=14939))
|
||||
* Fix issues with dragging layers between images in Adobe Photoshop 7.0 ([Wine Bug #12007](https://bugs.winehq.org/show_bug.cgi?id=12007))
|
||||
* Implement exclusive mode in PulseAudio backend ([Wine Bug #37042](https://bugs.winehq.org/show_bug.cgi?id=37042))
|
||||
* Take abs() of vertex z coordinate as FFP fog coordinate
|
||||
* Wintrust doesn't reset data->pWintrustData->u.pFile->hFile after closing handle ([Wine Bug #36257](https://bugs.winehq.org/show_bug.cgi?id=36257))
|
||||
|
||||
|
||||
|
3
debian/changelog
vendored
3
debian/changelog
vendored
@ -1,4 +1,5 @@
|
||||
wine-compholio (1.7.32) UNRELEASED; urgency=low
|
||||
* Various optimizations of patchupdate.py.
|
||||
* Update patch for SO_CONNECT_TIME and adding better tests.
|
||||
* Update patch for FD Cache and use faster method on x86_64.
|
||||
* Added patch to ensure dbghelp always checks for debug symbols in BINDIR.
|
||||
@ -19,6 +20,8 @@ wine-compholio (1.7.32) UNRELEASED; urgency=low
|
||||
* Removed patches to avoid sending messages in FindWindowExW (accepted upstream).
|
||||
* Removed patch to fix implementation ofCoWaitForMultipleHandles (accepted upstream).
|
||||
* Removed patch to avoid interthread no-op messages in ShowWindow (accepted upstream).
|
||||
* Removed patches to take abs() of vertex z coordinate as FFP fog coordinate (fixed upstream).
|
||||
* Removed patch to fix detection of gnutls on Ubuntu 14.10.
|
||||
-- Sebastian Lackner <sebastian@fds-team.de> Sat, 15 Nov 2014 20:21:53 +0100
|
||||
|
||||
wine-compholio (1.7.31) unstable; urgency=low
|
||||
|
273
debian/tools/patchupdate.py
vendored
273
debian/tools/patchupdate.py
vendored
@ -19,24 +19,31 @@
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
|
||||
import binascii
|
||||
import cPickle as pickle
|
||||
import hashlib
|
||||
import itertools
|
||||
import math
|
||||
import multiprocessing.pool
|
||||
import operator
|
||||
import os
|
||||
import patchutils
|
||||
import pickle
|
||||
import progressbar
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import textwrap
|
||||
|
||||
_devnull = open(os.devnull, 'wb')
|
||||
|
||||
# Cached information to speed up patch dependency checks
|
||||
latest_wine_commit = None
|
||||
cached_patch_result = {}
|
||||
cached_original_src = {}
|
||||
|
||||
class config(object):
|
||||
path_depcache = ".depcache"
|
||||
path_srccache = ".srccache"
|
||||
path_depcache = ".patchupdate.cache"
|
||||
|
||||
path_patches = "patches"
|
||||
path_changelog = "debian/changelog"
|
||||
@ -82,6 +89,22 @@ def _unique(iterable, key=None):
|
||||
# _unique('ABBCcAD', str.lower) --> A B C A D
|
||||
return itertools.imap(next, itertools.imap(operator.itemgetter(1), itertools.groupby(iterable, key)))
|
||||
|
||||
def _split_seq(iterable, size):
|
||||
"""Split an iterator into chunks of a given size."""
|
||||
it = iter(iterable)
|
||||
items = list(itertools.islice(it, size))
|
||||
while items:
|
||||
yield items
|
||||
items = list(itertools.islice(it, size))
|
||||
|
||||
def _merge_seq(iterable, callback=None):
|
||||
"""Merge lists/iterators into a new one. Call callback after each chunk"""
|
||||
for i, items in enumerate(iterable):
|
||||
if callback is not None:
|
||||
callback(i)
|
||||
for obj in items:
|
||||
yield obj
|
||||
|
||||
def _escape(s):
|
||||
"""Escape string inside of '...' quotes."""
|
||||
return s.replace("\\", "\\\\\\\\").replace("\"", "\\\"").replace("'", "'\\''")
|
||||
@ -99,7 +122,17 @@ def _save_dict(filename, value):
|
||||
with open(filename, "wb") as fp:
|
||||
pickle.dump(value, fp, pickle.HIGHEST_PROTOCOL)
|
||||
|
||||
def parse_int(val, default=0):
|
||||
def _sha256(fp):
|
||||
"""Calculate sha256sum from a file descriptor."""
|
||||
m = hashlib.sha256()
|
||||
fp.seek(0)
|
||||
while True:
|
||||
buf = fp.read(16384)
|
||||
if buf == "": break
|
||||
m.update(buf)
|
||||
return m.digest()
|
||||
|
||||
def _parse_int(val, default=0):
|
||||
"""Parse an integer or boolean value."""
|
||||
r = re.match("^[0-9]+$", val)
|
||||
if r:
|
||||
@ -109,21 +142,21 @@ def parse_int(val, default=0):
|
||||
except AttributeError:
|
||||
return default
|
||||
|
||||
# Read information from changelog
|
||||
def _read_changelog():
|
||||
"""Read information from changelog."""
|
||||
with open(config.path_changelog) as fp:
|
||||
for line in fp:
|
||||
r = re.match("^([a-zA-Z0-9][^(]*)\((.*)\) ([^;]*)", line)
|
||||
if r: yield (r.group(1).strip(), r.group(2).strip(), r.group(3).strip())
|
||||
|
||||
# Get version number of the latest stable release
|
||||
def _stable_compholio_version():
|
||||
"""Get version number of the latest stable release."""
|
||||
for package, version, distro in _read_changelog():
|
||||
if distro.lower() != "unreleased":
|
||||
return version
|
||||
|
||||
# Get latest wine commit
|
||||
def _latest_wine_commit():
|
||||
"""Get latest wine commit."""
|
||||
if not os.path.isdir(config.path_wine):
|
||||
raise PatchUpdaterError("Please create a symlink to the wine repository in %s" % config.path_wine)
|
||||
commit = subprocess.check_output(["git", "rev-parse", "origin/master"], cwd=config.path_wine).strip()
|
||||
@ -149,8 +182,7 @@ def enum_directories(revision, path):
|
||||
else:
|
||||
filename = "%s:%s" % (revision, path)
|
||||
try:
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
content = subprocess.check_output(["git", "show", filename], stderr=devnull)
|
||||
content = subprocess.check_output(["git", "show", filename], stderr=_devnull)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.returncode != 128: raise
|
||||
return [] # ignore error
|
||||
@ -166,7 +198,6 @@ def enum_directories(revision, path):
|
||||
|
||||
def read_definition(revision, filename, name_to_id):
|
||||
"""Read a definition file and return information as tuple (depends, fixes)."""
|
||||
|
||||
filename = os.path.join(filename, "definition")
|
||||
if revision is None:
|
||||
with open(filename) as fp:
|
||||
@ -174,8 +205,7 @@ def read_definition(revision, filename, name_to_id):
|
||||
else:
|
||||
filename = "%s:%s" % (revision, filename)
|
||||
try:
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
content = subprocess.check_output(["git", "show", filename], stderr=devnull)
|
||||
content = subprocess.check_output(["git", "show", filename], stderr=_devnull)
|
||||
except subprocess.CalledProcessError:
|
||||
raise IOError("Failed to load %s" % filename)
|
||||
|
||||
@ -186,18 +216,15 @@ def read_definition(revision, filename, name_to_id):
|
||||
for line in content.split("\n"):
|
||||
if line.startswith("#"):
|
||||
continue
|
||||
|
||||
tmp = line.split(":", 1)
|
||||
if len(tmp) != 2:
|
||||
continue
|
||||
|
||||
key, val = tmp[0].lower(), tmp[1].strip()
|
||||
if key == "depends":
|
||||
if name_to_id is not None:
|
||||
if not name_to_id.has_key(val):
|
||||
raise PatchUpdaterError("Definition file %s references unknown dependency %s" % (filename, val))
|
||||
depends.add(name_to_id[val])
|
||||
|
||||
elif key == "fixes":
|
||||
r = re.match("^[0-9]+$", val)
|
||||
if r:
|
||||
@ -208,10 +235,8 @@ def read_definition(revision, filename, name_to_id):
|
||||
fixes.append((int(r.group(1)), r.group(2).strip()))
|
||||
continue
|
||||
fixes.append((None, val))
|
||||
|
||||
elif key == "disabled":
|
||||
disabled = parse_int(val)
|
||||
|
||||
disabled = _parse_int(val)
|
||||
elif revision is None:
|
||||
print "WARNING: Ignoring unknown command in definition file %s: %s" % (filename, line)
|
||||
|
||||
@ -219,7 +244,6 @@ def read_definition(revision, filename, name_to_id):
|
||||
|
||||
def read_patchset(revision = None):
|
||||
"""Read information about all patchsets for a specific revision."""
|
||||
|
||||
unique_id = itertools.count()
|
||||
all_patches = {}
|
||||
name_to_id = {}
|
||||
@ -285,15 +309,12 @@ def causal_time_relation_any(all_patches, indices):
|
||||
return False
|
||||
return True
|
||||
|
||||
def causal_time_permutations(all_patches, indices, filename):
|
||||
def causal_time_permutations(all_patches, indices):
|
||||
"""Iterate over all possible permutations of patches affecting
|
||||
a specific file, which are compatible with dependencies."""
|
||||
for permutation in itertools.permutations(indices):
|
||||
if causal_time_relation(all_patches, permutation):
|
||||
selected_patches = []
|
||||
for i in permutation:
|
||||
selected_patches += [patch for patch in all_patches[i].patches if patch.modified_file == filename]
|
||||
yield selected_patches
|
||||
yield permutation
|
||||
|
||||
def contains_binary_patch(all_patches, indices, filename):
|
||||
"""Checks if any patch with given indices affecting filename is a binary patch."""
|
||||
@ -303,30 +324,43 @@ def contains_binary_patch(all_patches, indices, filename):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_wine_file(filename, force=False):
|
||||
def get_wine_file(filename):
|
||||
"""Return the hash and optionally the content of a file."""
|
||||
|
||||
# If we're not forced, we try to save time and only lookup the cached checksum
|
||||
entry = "%s:%s" % (latest_wine_commit, filename)
|
||||
if not force and cached_original_src.has_key(entry):
|
||||
return (cached_original_src[entry], None)
|
||||
|
||||
# Grab original file from the wine git repository
|
||||
entry = "%s:%s" % (latest_wine_commit, filename)
|
||||
result = tempfile.NamedTemporaryFile()
|
||||
try:
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
content = subprocess.check_output(["git", "show", entry], cwd=config.path_wine, stderr=devnull)
|
||||
content = subprocess.check_call(["git", "show", entry], cwd=config.path_wine, \
|
||||
stdout=result, stderr=_devnull)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.returncode != 128: raise
|
||||
content = ""
|
||||
result.flush() # shouldn't be necessary because the subprocess writes directly to the fd
|
||||
return result
|
||||
|
||||
content_hash = hashlib.sha256(content).digest()
|
||||
cached_original_src[entry] = content_hash
|
||||
return (content_hash, content)
|
||||
def select_patches(all_patches, indices, filename):
|
||||
"""Create a temporary patch file for each patchset and calculate the checksum."""
|
||||
selected_patches = {}
|
||||
|
||||
def verify_patch_order(all_patches, indices, filename):
|
||||
for i in indices:
|
||||
p = tempfile.NamedTemporaryFile()
|
||||
m = hashlib.sha256()
|
||||
|
||||
for patch in all_patches[i].patches:
|
||||
if patch.modified_file != filename:
|
||||
continue
|
||||
for chunk in patch.read_chunks():
|
||||
p.write(chunk)
|
||||
m.update(chunk)
|
||||
p.write("\n")
|
||||
m.update("\n")
|
||||
|
||||
p.flush()
|
||||
selected_patches[i] = (m.digest(), p)
|
||||
|
||||
return selected_patches
|
||||
|
||||
def verify_patch_order(all_patches, indices, filename, pool):
|
||||
"""Checks if the dependencies are defined correctly by applying
|
||||
the patches on a (temporary) copy from the git tree."""
|
||||
global cached_patch_result
|
||||
|
||||
# If one of patches is a binary patch, then we cannot / won't verify it - require dependencies in this case
|
||||
if contains_binary_patch(all_patches, indices, filename):
|
||||
@ -335,55 +369,99 @@ def verify_patch_order(all_patches, indices, filename):
|
||||
(filename, ", ".join([all_patches[i].name for i in indices])))
|
||||
return
|
||||
|
||||
# Get at least the checksum of the original file
|
||||
original_content_hash, original_content = get_wine_file(filename)
|
||||
original_content = get_wine_file(filename)
|
||||
original_content_hash = _sha256(original_content)
|
||||
selected_patches = select_patches(all_patches, indices, filename)
|
||||
try:
|
||||
|
||||
# Check for possible ways to apply the patch
|
||||
failed_to_apply = False
|
||||
last_result_hash = None
|
||||
for patches in causal_time_permutations(all_patches, indices, filename):
|
||||
|
||||
# Calculate unique hash based on the original content and the order in which the patches are applied
|
||||
m = hashlib.sha256()
|
||||
m.update(original_content_hash)
|
||||
for patch in patches:
|
||||
m.update(patch.hash())
|
||||
unique_hash = m.digest()
|
||||
|
||||
# Fast path -> we know that it applies properly
|
||||
if cached_patch_result.has_key(unique_hash):
|
||||
result_hash = cached_patch_result[unique_hash]
|
||||
assert result_hash is not None
|
||||
|
||||
else:
|
||||
# Now really get the file, if we don't have it yet
|
||||
if original_content is None:
|
||||
original_content_hash, original_content = get_wine_file(filename, force=True)
|
||||
|
||||
# Apply the patches (without fuzz)
|
||||
def _test_apply(permutations):
|
||||
"""Tests if specific permutations of patches apply on the wine source tree."""
|
||||
patch_stack_indices = []
|
||||
patch_stack_patches = []
|
||||
try:
|
||||
content = patchutils.apply_patch(original_content, patches, fuzz=0)
|
||||
except patchutils.PatchApplyError:
|
||||
# Remember that we failed to apply the patches, but continue, if there is still a chance
|
||||
# that it applies in a different order (to give a better error message).
|
||||
failed_to_apply = True
|
||||
if last_result_hash is None:
|
||||
continue
|
||||
break
|
||||
|
||||
# Get hash of resulting file and add to cache
|
||||
result_hash = hashlib.sha256(content).digest()
|
||||
cached_patch_result[unique_hash] = result_hash
|
||||
for permutation in permutations:
|
||||
|
||||
# No known hash yet, remember the result. If we failed applying before, we can stop now.
|
||||
if last_result_hash is None:
|
||||
last_result_hash = result_hash
|
||||
if failed_to_apply: break
|
||||
# Calculate hash
|
||||
m = hashlib.sha256()
|
||||
m.update(original_content_hash)
|
||||
for i in permutation:
|
||||
m.update(selected_patches[i][0])
|
||||
input_hash = m.digest()
|
||||
|
||||
# Applied successful, but result has a different hash - also treat as failure.
|
||||
elif last_result_hash != result_hash:
|
||||
failed_to_apply = True
|
||||
break
|
||||
# Fast path -> we know that it applies properly
|
||||
try:
|
||||
yield cached_patch_result[input_hash]
|
||||
continue
|
||||
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Remove unneeded patches from patch stack
|
||||
while list(permutation[:len(patch_stack_indices)]) != patch_stack_indices:
|
||||
patch_stack_indices.pop()
|
||||
patch_stack_patches.pop().close()
|
||||
|
||||
# Apply the patches (without fuzz)
|
||||
try:
|
||||
while len(patch_stack_indices) < len(permutation):
|
||||
i = permutation[len(patch_stack_indices)]
|
||||
original = patch_stack_patches[-1] if len(patch_stack_indices) else original_content
|
||||
patchfile = selected_patches[i][1]
|
||||
patch_stack_patches.append(patchutils.apply_patch(original, patchfile, fuzz=0))
|
||||
patch_stack_indices.append(i)
|
||||
output_hash = _sha256(patch_stack_patches[-1])
|
||||
|
||||
except patchutils.PatchApplyError:
|
||||
output_hash = None
|
||||
|
||||
cached_patch_result[input_hash] = output_hash
|
||||
yield output_hash
|
||||
|
||||
finally:
|
||||
# Ensure temporary files are cleaned up properly
|
||||
while len(patch_stack_patches):
|
||||
patch_stack_patches.pop().close()
|
||||
|
||||
# Show a progress bar while applying the patches - this task might take some time
|
||||
chunk_size = 20
|
||||
total_tasks = (math.factorial(len(indices)) + chunk_size - 1) / chunk_size
|
||||
with progressbar.ProgressBar(desc=filename, total=total_tasks) as progress:
|
||||
|
||||
failed_to_apply = False
|
||||
last_result_hash = None
|
||||
|
||||
# Check for possible ways to apply the patch
|
||||
it = _split_seq(causal_time_permutations(all_patches, indices), chunk_size)
|
||||
for output_hash in _merge_seq(pool.imap_unordered(lambda seq: list(_test_apply(seq)), it), \
|
||||
callback=progress.update):
|
||||
|
||||
# Failed to apply patch, continue checking the rest.
|
||||
if output_hash is None:
|
||||
failed_to_apply = True
|
||||
if last_result_hash is None:
|
||||
continue
|
||||
break
|
||||
|
||||
# No known hash yet, remember the result. If we failed applying before, we can stop now.
|
||||
elif last_result_hash is None:
|
||||
last_result_hash = output_hash
|
||||
if failed_to_apply: break
|
||||
|
||||
# Applied successful, but result has a different hash - also treat as failure.
|
||||
elif last_result_hash != output_hash:
|
||||
failed_to_apply = True
|
||||
break
|
||||
|
||||
if failed_to_apply:
|
||||
progress.finish("<failed to apply>")
|
||||
elif verbose:
|
||||
progress.finish(binascii.hexlify(last_result_hash))
|
||||
|
||||
finally:
|
||||
original_content.close()
|
||||
for _, (_, p) in selected_patches.iteritems():
|
||||
p.close()
|
||||
|
||||
# If something failed, then show the appropriate error message.
|
||||
if failed_to_apply and last_result_hash is None:
|
||||
@ -403,14 +481,11 @@ def verify_dependencies(all_patches):
|
||||
def _load_patch_cache():
|
||||
"""Load dictionary for cached patch dependency tests."""
|
||||
global cached_patch_result
|
||||
global cached_original_src
|
||||
cached_patch_result = _load_dict(config.path_depcache)
|
||||
cached_original_src = _load_dict(config.path_srccache)
|
||||
|
||||
def _save_patch_cache():
|
||||
"""Save dictionary for cached patch dependency tests."""
|
||||
_save_dict(config.path_depcache, cached_patch_result)
|
||||
_save_dict(config.path_srccache, cached_original_src)
|
||||
_save_dict(config.path_depcache, cached_patch_result.copy())
|
||||
|
||||
enabled_patches = dict([(i, patch) for i, patch in all_patches.iteritems() if not patch.disabled])
|
||||
max_patches = max(enabled_patches.keys()) + 1
|
||||
@ -450,11 +525,13 @@ def verify_dependencies(all_patches):
|
||||
|
||||
# Check if patches always apply correctly
|
||||
_load_patch_cache()
|
||||
pool = multiprocessing.pool.ThreadPool(processes=8)
|
||||
try:
|
||||
for f, indices in modified_files.iteritems():
|
||||
verify_patch_order(enabled_patches, indices, f)
|
||||
verify_patch_order(enabled_patches, indices, f, pool)
|
||||
finally:
|
||||
_save_patch_cache()
|
||||
pool.close()
|
||||
|
||||
def generate_makefile(all_patches):
|
||||
"""Generate Makefile for a specific set of patches."""
|
||||
@ -464,9 +541,9 @@ def generate_makefile(all_patches):
|
||||
|
||||
with open(config.path_Makefile, "w") as fp:
|
||||
fp.write(template.format(patchlist="\t" + " \\\n\t".join(
|
||||
["%s.ok" % patch.name for i, patch in all_patches.iteritems() if not patch.disabled])))
|
||||
["%s.ok" % patch.name for _, patch in all_patches.iteritems() if not patch.disabled])))
|
||||
|
||||
for i, patch in all_patches.iteritems():
|
||||
for _, patch in all_patches.iteritems():
|
||||
fp.write("# Patchset %s\n" % patch.name)
|
||||
fp.write("# |\n")
|
||||
|
||||
@ -513,13 +590,13 @@ def generate_markdown(all_patches, stable_patches, stable_compholio_version):
|
||||
all_fixes = {}
|
||||
|
||||
# Get fixes for current version
|
||||
for i, patch in all_patches.iteritems():
|
||||
for _, patch in all_patches.iteritems():
|
||||
for bugid, bugname in patch.fixes:
|
||||
key = bugid if bugid is not None else bugname
|
||||
all_fixes[key] = [1, bugid, bugname]
|
||||
|
||||
# Compare with fixes for latest stable version
|
||||
for i, patch in stable_patches.iteritems():
|
||||
for _, patch in stable_patches.iteritems():
|
||||
for bugid, bugname in patch.fixes:
|
||||
key = bugid if bugid is not None else bugname
|
||||
if all_fixes.has_key(key):
|
||||
@ -565,6 +642,14 @@ def generate_markdown(all_patches, stable_patches, stable_compholio_version):
|
||||
fp.write(template.format(version=stable_compholio_version))
|
||||
|
||||
if __name__ == "__main__":
|
||||
verbose = "-v" in sys.argv[1:]
|
||||
|
||||
# Hack to avoid KeyboardInterrupts on worker threads
|
||||
def _sig_int(signum=None, frame=None):
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
raise RuntimeError("CTRL+C pressed")
|
||||
signal.signal(signal.SIGINT, _sig_int)
|
||||
|
||||
try:
|
||||
|
||||
# Get information about Wine and Compholio version
|
||||
|
157
debian/tools/patchutils.py
vendored
157
debian/tools/patchutils.py
vendored
@ -19,16 +19,19 @@
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
|
||||
import email.header
|
||||
import collections
|
||||
import difflib
|
||||
import email.header
|
||||
import hashlib
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
_devnull = open(os.devnull, 'wb')
|
||||
|
||||
class PatchParserError(RuntimeError):
|
||||
"""Unable to parse patch file - either an unimplemented feature, or corrupted patch."""
|
||||
pass
|
||||
@ -44,7 +47,7 @@ class PatchObject(object):
|
||||
self.patch_subject = header['subject']
|
||||
self.patch_revision = header['revision'] if header.has_key('revision') else 1
|
||||
|
||||
self.extracted_patch = None
|
||||
# self.extracted_patch = None
|
||||
self.unique_hash = None
|
||||
|
||||
self.filename = filename
|
||||
@ -70,76 +73,58 @@ class PatchObject(object):
|
||||
fp.seek(self.offset_begin)
|
||||
i = self.offset_end - self.offset_begin
|
||||
while i > 0:
|
||||
buf = fp.read(4096 if i > 4096 else i)
|
||||
buf = fp.read(16384 if i > 16384 else i)
|
||||
if buf == "": raise IOError("Unable to extract patch.")
|
||||
yield buf
|
||||
i -= len(buf)
|
||||
|
||||
def extract(self):
|
||||
"""Create a temporary file containing the extracted patch."""
|
||||
if not self.extracted_patch:
|
||||
self.extracted_patch = tempfile.NamedTemporaryFile()
|
||||
for chunk in self.read_chunks():
|
||||
self.extracted_patch.write(chunk)
|
||||
self.extracted_patch.flush()
|
||||
return self.extracted_patch
|
||||
class _FileReader(object):
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.fp = open(self.filename)
|
||||
self.peeked = None
|
||||
|
||||
def hash(self):
|
||||
"""Hash the content of the patch."""
|
||||
if not self.unique_hash:
|
||||
m = hashlib.sha256()
|
||||
for chunk in self.read_chunks():
|
||||
m.update(chunk)
|
||||
self.unique_hash = m.digest()
|
||||
return self.unique_hash
|
||||
def close(self):
|
||||
self.fp.close()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
def seek(self, pos):
|
||||
"""Change the file cursor position."""
|
||||
self.fp.seek(pos)
|
||||
self.peeked = None
|
||||
|
||||
def tell(self):
|
||||
"""Return the current file cursor position."""
|
||||
if self.peeked is None:
|
||||
return self.fp.tell()
|
||||
return self.peeked[0]
|
||||
|
||||
def peek(self):
|
||||
"""Read one line without changing the file cursor."""
|
||||
if self.peeked is None:
|
||||
pos = self.fp.tell()
|
||||
tmp = self.fp.readline()
|
||||
if len(tmp) == 0: return None
|
||||
self.peeked = (pos, tmp)
|
||||
return self.peeked[1]
|
||||
|
||||
def read(self):
|
||||
"""Read one line from the file, and move the file cursor to the next line."""
|
||||
if self.peeked is None:
|
||||
tmp = self.fp.readline()
|
||||
if len(tmp) == 0: return None
|
||||
return tmp
|
||||
tmp, self.peeked = self.peeked, None
|
||||
return tmp[1]
|
||||
|
||||
def read_patch(filename):
|
||||
"""Iterates over all patches contained in a file, and returns PatchObject objects."""
|
||||
|
||||
class _FileReader(object):
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.fp = open(self.filename)
|
||||
self.peeked = None
|
||||
|
||||
def close(self):
|
||||
self.fp.close()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
def seek(self, pos):
|
||||
"""Change the file cursor position."""
|
||||
self.fp.seek(pos)
|
||||
self.peeked = None
|
||||
|
||||
def tell(self):
|
||||
"""Return the current file cursor position."""
|
||||
if self.peeked is None:
|
||||
return self.fp.tell()
|
||||
return self.peeked[0]
|
||||
|
||||
def peek(self):
|
||||
"""Read one line without changing the file cursor."""
|
||||
if self.peeked is None:
|
||||
pos = self.fp.tell()
|
||||
tmp = self.fp.readline()
|
||||
if len(tmp) == 0: return None
|
||||
self.peeked = (pos, tmp)
|
||||
return self.peeked[1]
|
||||
|
||||
def read(self):
|
||||
"""Read one line from the file, and move the file cursor to the next line."""
|
||||
if self.peeked is None:
|
||||
tmp = self.fp.readline()
|
||||
if len(tmp) == 0: return None
|
||||
return tmp
|
||||
tmp, self.peeked = self.peeked, None
|
||||
return tmp[1]
|
||||
|
||||
def _read_single_patch(fp, header, oldname=None, newname=None):
|
||||
"""Internal function to read a single patch from a file."""
|
||||
|
||||
@ -351,35 +336,29 @@ def read_patch(filename):
|
||||
else:
|
||||
assert fp.read() == line
|
||||
|
||||
def apply_patch(content, patches, reverse=False, fuzz=2):
|
||||
def apply_patch(original, patchfile, reverse=False, fuzz=2):
|
||||
"""Apply a patch with optional fuzz - uses the commandline 'patch' utility."""
|
||||
|
||||
if not isinstance(patches, collections.Sequence):
|
||||
patches = [patches]
|
||||
|
||||
contentfile = tempfile.NamedTemporaryFile(delete=False)
|
||||
result = tempfile.NamedTemporaryFile(delete=False)
|
||||
try:
|
||||
contentfile.write(content)
|
||||
contentfile.close()
|
||||
# We open the file again to avoid race-conditions with multithreaded reads
|
||||
with open(original.name) as fp:
|
||||
shutil.copyfileobj(fp, result)
|
||||
result.close()
|
||||
|
||||
for patch in patches:
|
||||
cmdline = ["patch", "--no-backup-if-mismatch", "--force", "--silent", "-r", "-"]
|
||||
if reverse: cmdline.append("--reverse")
|
||||
if fuzz != 2: cmdline.append("--fuzz=%d" % fuzz)
|
||||
cmdline += [result.name, patchfile.name]
|
||||
|
||||
patchfile = patch.extract()
|
||||
cmdline = ["patch", "--no-backup-if-mismatch", "--force", "--silent", "-r", "-"]
|
||||
if reverse: cmdline.append("--reverse")
|
||||
if fuzz != 2: cmdline.append("--fuzz=%d" % fuzz)
|
||||
cmdline += [contentfile.name, patchfile.name]
|
||||
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
exitcode = subprocess.call(cmdline, stdout=devnull, stderr=devnull)
|
||||
if exitcode != 0:
|
||||
raise PatchApplyError("Failed to apply patch (exitcode %d)." % exitcode)
|
||||
|
||||
with open(contentfile.name) as fp:
|
||||
content = fp.read()
|
||||
|
||||
finally:
|
||||
os.unlink(contentfile.name)
|
||||
|
||||
return content
|
||||
exitcode = subprocess.call(cmdline, stdout=_devnull, stderr=_devnull)
|
||||
if exitcode != 0:
|
||||
raise PatchApplyError("Failed to apply patch (exitcode %d)." % exitcode)
|
||||
|
||||
# Hack - we can't keep the file open while patching ('patch' might rename/replace
|
||||
# the file), so create a new _TemporaryFileWrapper object for the existing path.
|
||||
return tempfile._TemporaryFileWrapper(file=open(result.name, 'r+b'), \
|
||||
name=result.name, delete=True)
|
||||
except:
|
||||
os.unlink(result.name)
|
||||
raise
|
||||
|
106
debian/tools/progressbar.py
vendored
Normal file
106
debian/tools/progressbar.py
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
#!/usr/bin/python2
|
||||
#
|
||||
# Python progressbar functions.
|
||||
#
|
||||
# Copyright (C) 2014 Sebastian Lackner
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
|
||||
import fcntl
|
||||
import os
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
import termios
|
||||
|
||||
def _sig_winch(signum=None, frame=None):
|
||||
"""Signal handler for SIGWINCH."""
|
||||
global _term_width
|
||||
h, w, hp, wp = struct.unpack('HHHH', fcntl.ioctl(sys.stdout.fileno(),
|
||||
termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))
|
||||
_term_width = w
|
||||
|
||||
try:
|
||||
_sig_winch()
|
||||
signal.signal(signal.SIGWINCH, _sig_winch)
|
||||
except IOError:
|
||||
_term_width = int(os.environ.get('COLUMNS', 80)) - 1
|
||||
|
||||
class ProgressBar(object):
|
||||
def __init__(self, desc="", msg=None, current=0, total=100):
|
||||
"""Initialize a new progress bar with given properties."""
|
||||
self.desc = desc
|
||||
self.msg = msg
|
||||
self.current = current
|
||||
self.total = total
|
||||
|
||||
def __enter__(self):
|
||||
self.update()
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if type is not None:
|
||||
sys.stdout.write("\r")
|
||||
msg = "<interrupted>"
|
||||
else:
|
||||
msg = None
|
||||
self.finish(msg)
|
||||
if self.msg is not None:
|
||||
sys.stdout.write("\n")
|
||||
|
||||
def update(self, value = None):
|
||||
"""Redraw the progressbar and optionally update the value."""
|
||||
if value is not None:
|
||||
self.current = value
|
||||
|
||||
if self.current == 0 or (self.current >= self.total and self.msg is None):
|
||||
sys.stdout.write("%s\r" % (' ' * _term_width))
|
||||
sys.stdout.flush()
|
||||
return
|
||||
|
||||
width = _term_width / 2
|
||||
s1 = self.desc.ljust(width - 1, ' ')[:width - 1]
|
||||
|
||||
width = _term_width - width
|
||||
if self.current >= self.total:
|
||||
s2 = self.msg.ljust(width, ' ')[:width]
|
||||
elif width > 2:
|
||||
numbars = min(self.current * (width - 2) / self.total, width - 2)
|
||||
s2 = "[%s%s]" % ('#' * numbars, '-' * (width - 2 - numbars))
|
||||
percent = " %d%% " % min(self.current * 100 / self.total, 100)
|
||||
i = (len(s2)-len(percent))/2
|
||||
s2 = "%s%s%s" % (s2[:i], percent, s2[i+len(percent):])
|
||||
|
||||
sys.stdout.write("%s %s\r" % (s1, s2))
|
||||
sys.stdout.flush()
|
||||
|
||||
def finish(self, msg = None):
|
||||
"""Finalize the progressbar."""
|
||||
if msg is not None:
|
||||
self.msg = msg
|
||||
|
||||
self.current = self.total
|
||||
self.update()
|
||||
sys.stdout.flush()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import time
|
||||
|
||||
print ""
|
||||
with ProgressBar(desc="description") as x:
|
||||
for i in xrange(100):
|
||||
x.update(i)
|
||||
time.sleep(1)
|
@ -27,7 +27,6 @@ PATCHLIST := \
|
||||
atl-IOCS_Property.ok \
|
||||
comctl32-LoadIconMetric.ok \
|
||||
configure-Absolute_RPATH.ok \
|
||||
configure-Detect_Gnutls.ok \
|
||||
d3d9-Surface_Refcount.ok \
|
||||
d3dx9_36-DXTn.ok \
|
||||
d3dx9_36-Filter_Warnings.ok \
|
||||
@ -109,7 +108,6 @@ PATCHLIST := \
|
||||
wineboot-HKEY_DYN_DATA.ok \
|
||||
winebuild-LinkerVersion.ok \
|
||||
wined3d-DXTn.ok \
|
||||
wined3d-FFP_Fog.ok \
|
||||
wined3d-Revert_PixelFormat.ok \
|
||||
winedevice-Fix_Relocation.ok \
|
||||
winemenubuilder-Desktop_Icon_Path.ok \
|
||||
@ -332,18 +330,6 @@ configure-Absolute_RPATH.ok:
|
||||
echo '+ { "Sebastian Lackner", "configure: Also add the absolute RPATH when linking against libwine.", 1 },'; \
|
||||
) > configure-Absolute_RPATH.ok
|
||||
|
||||
# Patchset configure-Detect_Gnutls
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * configure.ac
|
||||
# |
|
||||
.INTERMEDIATE: configure-Detect_Gnutls.ok
|
||||
configure-Detect_Gnutls.ok:
|
||||
$(call APPLY_FILE,configure-Detect_Gnutls/0001-configure-Fix-detection-of-gnutls-on-Ubuntu-14.10.patch)
|
||||
@( \
|
||||
echo '+ { "Sebastian Lackner", "configure: Fix detection of gnutls on Ubuntu 14.10.", 3 },'; \
|
||||
) > configure-Detect_Gnutls.ok
|
||||
|
||||
# Patchset d3d9-Surface_Refcount
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
@ -1693,21 +1679,6 @@ wined3d-DXTn.ok:
|
||||
echo '+ { "Michael Müller", "wined3d: add DXT1 to B4G4R4A4, DXT1 to B5G5R5A1 and DXT3 to B4G4R4A4 conversion.", 1 },'; \
|
||||
) > wined3d-DXTn.ok
|
||||
|
||||
# Patchset wined3d-FFP_Fog
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/d3d8/tests/visual.c, dlls/d3d9/tests/visual.c, dlls/ddraw/tests/ddraw7.c, dlls/wined3d/directx.c,
|
||||
# | dlls/wined3d/glsl_shader.c
|
||||
# |
|
||||
.INTERMEDIATE: wined3d-FFP_Fog.ok
|
||||
wined3d-FFP_Fog.ok:
|
||||
$(call APPLY_FILE,wined3d-FFP_Fog/0001-wined3d-Set-D3DPMISCCAPS_FOGVERTEXCLAMPED-flag-in-ge.patch)
|
||||
$(call APPLY_FILE,wined3d-FFP_Fog/0002-wined3d-Take-abs-of-vertex-z-coordinate-as-FFP-fog-c.patch)
|
||||
@( \
|
||||
echo '+ { "Joachim Priesner", "wined3d: Set D3DPMISCCAPS_FOGVERTEXCLAMPED flag in get_device_caps (resend).", 1 },'; \
|
||||
echo '+ { "Joachim Priesner", "wined3d: Take abs() of vertex z coordinate as FFP fog coordinate.", 7 },'; \
|
||||
) > wined3d-FFP_Fog.ok
|
||||
|
||||
# Patchset wined3d-Revert_PixelFormat
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
@ -1,25 +0,0 @@
|
||||
From 3ec0224addff16f803d8d49feb0a4a232c48ebcd Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Sun, 7 Sep 2014 08:09:54 +0200
|
||||
Subject: configure: Fix detection of gnutls on Ubuntu 14.10. (try 3)
|
||||
|
||||
---
|
||||
configure.ac | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 2bc0008..c22b119 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -1360,7 +1360,7 @@ then
|
||||
[AC_CHECK_HEADER(gnutls/gnutls.h,
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>]], [[static typeof(gnutls_mac_get_key_size) *func; if (func) return 0;]])],
|
||||
- [WINE_CHECK_SONAME(gnutls,gnutls_global_init,,[GNUTLS_CFLAGS=""],[$GNUTLS_LIBS])])],
|
||||
+ [WINE_CHECK_SONAME(gnutls,gnutls_global_init,,[GNUTLS_CFLAGS=""],[$GNUTLS_LIBS],[[libgnutls\\(-deb0\\)\\{0,1\\}]])])],
|
||||
[GNUTLS_CFLAGS=""])])
|
||||
fi
|
||||
WINE_WARNING_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"],
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,34 +0,0 @@
|
||||
From 77f3334105cbefa51452f8d7ad68c7ba5b797837 Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Priesner <joachim.priesner@web.de>
|
||||
Date: Fri, 14 Nov 2014 22:39:58 +0100
|
||||
Subject: wined3d: Set D3DPMISCCAPS_FOGVERTEXCLAMPED flag in get_device_caps
|
||||
(resend)
|
||||
|
||||
Wine clamps the oFog output of vertex shaders. Tests for the flag follow
|
||||
in the second part of this patch.
|
||||
---
|
||||
dlls/wined3d/directx.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
|
||||
index 794496b..d31202a 100644
|
||||
--- a/dlls/wined3d/directx.c
|
||||
+++ b/dlls/wined3d/directx.c
|
||||
@@ -4165,12 +4165,12 @@ HRESULT CDECL wined3d_get_device_caps(const struct wined3d *wined3d, UINT adapte
|
||||
WINED3DPMISCCAPS_CLIPPLANESCALEDPOINTS |
|
||||
WINED3DPMISCCAPS_MASKZ |
|
||||
WINED3DPMISCCAPS_BLENDOP |
|
||||
+ WINED3DPMISCCAPS_FOGVERTEXCLAMPED |
|
||||
WINED3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING;
|
||||
/* TODO:
|
||||
WINED3DPMISCCAPS_NULLREFERENCE
|
||||
WINED3DPMISCCAPS_FOGANDSPECULARALPHA
|
||||
- WINED3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
|
||||
- WINED3DPMISCCAPS_FOGVERTEXCLAMPED */
|
||||
+ WINED3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS */
|
||||
|
||||
if (gl_info->supported[EXT_BLEND_EQUATION_SEPARATE] && gl_info->supported[EXT_BLEND_FUNC_SEPARATE])
|
||||
caps->PrimitiveMiscCaps |= WINED3DPMISCCAPS_SEPARATEALPHABLEND;
|
||||
--
|
||||
2.1.3
|
||||
|
@ -1,996 +0,0 @@
|
||||
From 5180456ab36112ce0f12b0fd9eddc29b860430be Mon Sep 17 00:00:00 2001
|
||||
From: Joachim Priesner <joachim.priesner@web.de>
|
||||
Date: Fri, 14 Nov 2014 22:40:11 +0100
|
||||
Subject: wined3d: Take abs() of vertex z coordinate as FFP fog coordinate (try
|
||||
7)
|
||||
|
||||
Take the absolute value of vertex.z as fog coordinate instead of just
|
||||
the z coordinate. This fixes e.g. fog for applications that use
|
||||
right-handed projection matrices.
|
||||
|
||||
Also test the clamp behavior of the oFog vertex shader output.
|
||||
|
||||
Tested on openSuse 13.1 and Windows 8.1 (VMware Player).
|
||||
|
||||
Try 7: Also test fogstart=-1, fogend=0.
|
||||
---
|
||||
dlls/d3d8/tests/visual.c | 331 +++++++++++++++++++++++++++++++++++++
|
||||
dlls/d3d9/tests/visual.c | 399 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/ddraw/tests/ddraw7.c | 174 ++++++++++++++++++++
|
||||
dlls/wined3d/glsl_shader.c | 2 +-
|
||||
4 files changed, 905 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c
|
||||
index cbede9d..af4a16d 100644
|
||||
--- a/dlls/d3d8/tests/visual.c
|
||||
+++ b/dlls/d3d8/tests/visual.c
|
||||
@@ -696,6 +696,336 @@ done:
|
||||
DestroyWindow(window);
|
||||
}
|
||||
|
||||
+/* This test tests fog in combination with negative vertex z coordinates. */
|
||||
+static void fog_negative_z_test(void)
|
||||
+{
|
||||
+ enum
|
||||
+ {
|
||||
+ C_ALPHA_0x00 = 0x00000000,
|
||||
+ C_CLEAR = 0xffff00ff,
|
||||
+ C_FOGGED = 0x0000ff00,
|
||||
+ C_HALF_FOGGED = 0x00808000,
|
||||
+ C_UNFOGGED = 0x00ff0000,
|
||||
+ C_CLAMPED_FOG = 0xdeadbeef /* triggers special codepath when used as middle_color */
|
||||
+ };
|
||||
+
|
||||
+ /* Fill the null-shader entry with the FVF (SetVertexShader is "overloaded" on d3d8). */
|
||||
+ DWORD vertex_shader[3] = {D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR, 0, 0};
|
||||
+ DWORD pixel_shader[2] = {0, 0};
|
||||
+ IDirect3D8 *d3d;
|
||||
+ IDirect3DDevice8 *device;
|
||||
+ BOOL has_vs_support, has_ps_support, has_table_fog_support;
|
||||
+ unsigned int i, ps, y;
|
||||
+ D3DCOLOR color, expected_middle_color;
|
||||
+ ULONG refcount;
|
||||
+ D3DCAPS8 caps;
|
||||
+ HWND window;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ static const DWORD vertex_decl[] =
|
||||
+ {
|
||||
+ D3DVSD_STREAM(0),
|
||||
+ D3DVSD_REG(0, D3DVSDT_FLOAT3), /* position, v0 */
|
||||
+ D3DVSD_REG(1, D3DVSDT_D3DCOLOR), /* diffuse color, v1 */
|
||||
+ D3DVSD_REG(2, D3DVSDT_D3DCOLOR), /* specular color, v2 */
|
||||
+ D3DVSD_CONST(0, 1), 0x3f000000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 0.5, 0, 0, 0 */
|
||||
+ D3DVSD_END()
|
||||
+ };
|
||||
+
|
||||
+ /* Basic vertex shader without fog computation ("non foggy") */
|
||||
+ static const DWORD vertex_shader_code1[] =
|
||||
+ {
|
||||
+ 0xfffe0100, /* vs_1_0 */
|
||||
+ /* output.Pos.z = input.Pos.z * 0.5 + 0.5 */
|
||||
+ 0x00000005, 0x80010000, 0x90aa0000, 0xa0000000, /* mul r0.x, v0.z, c0.x */
|
||||
+ 0x00000002, 0xc0040000, 0x80000000, 0xa0000000, /* add oPos.z, r0.x c0.x */
|
||||
+ /* output.Pos.xyw = input.Pos.xyw */
|
||||
+ 0x00000001, 0xc00b0000, 0x90e40000, /* mov oPos.xyw, v0 */
|
||||
+ /* output.Color = input.Color */
|
||||
+ 0x00000001, 0xd00f0000, 0x90e40001, /* mov oD0, v1 */
|
||||
+ 0x0000ffff, /* END */
|
||||
+ };
|
||||
+
|
||||
+ /* Basic vertex shader with fog computation ("foggy"). Outputs the z coordinate of the vertex
|
||||
+ * as its fog intensity value. */
|
||||
+ static const DWORD vertex_shader_code2[] =
|
||||
+ {
|
||||
+ 0xfffe0100, /* vs_1_0 */
|
||||
+ /* output.Pos.z = input.Pos.z * 0.5 + 0.5 */
|
||||
+ 0x00000005, 0x80010000, 0x90aa0000, 0xa0000000, /* mul r0.x, v0.z, c0.x */
|
||||
+ 0x00000002, 0xc0040000, 0x80000000, 0xa0000000, /* add oPos.z, r0.x c0.x */
|
||||
+ /* output.Pos.xyw = input.Pos.xyw */
|
||||
+ 0x00000001, 0xc00b0000, 0x90e40000, /* mov oPos.xyw, v0 */
|
||||
+ /* output.Color = input.Color */
|
||||
+ 0x00000001, 0xd00f0000, 0x90e40001, /* mov oD0, v1 */
|
||||
+ /* output.Fog = input.Pos.z */
|
||||
+ 0x00000001, 0xc00f0001, 0x90aa0000, /* mov oFog, v0.z */
|
||||
+ 0x0000ffff, /* END */
|
||||
+ };
|
||||
+
|
||||
+ /* Basic pixel shader */
|
||||
+ static const DWORD pixel_shader_code[] =
|
||||
+ {
|
||||
+ 0xffff0101, /* ps_1_1 */
|
||||
+ 0x00000001, 0x800f0000, 0x90e40000, /* mov r0, v0 */
|
||||
+ 0x0000ffff
|
||||
+ };
|
||||
+
|
||||
+ static const struct
|
||||
+ {
|
||||
+ struct vec3 position;
|
||||
+ DWORD diffuse;
|
||||
+ DWORD specular;
|
||||
+ }
|
||||
+ top_quad[] =
|
||||
+ {
|
||||
+ {{-1.0f, -1.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{-1.0f, 0.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, -1.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 0.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ },
|
||||
+ bottom_quad_1[] =
|
||||
+ {
|
||||
+ {{-1.0f, 0.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{-1.0f, 1.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 0.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 1.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ },
|
||||
+ bottom_quad_2[] =
|
||||
+ {
|
||||
+ {{ 0.0f, 0.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 1.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 0.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 1.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ };
|
||||
+ static const struct
|
||||
+ {
|
||||
+ int vshader;
|
||||
+ float fog_start;
|
||||
+ float fog_end;
|
||||
+ D3DFOGMODE vfog;
|
||||
+ D3DFOGMODE tfog;
|
||||
+ DWORD color_left;
|
||||
+ DWORD color_middle_top;
|
||||
+ DWORD color_middle_bottom;
|
||||
+ DWORD color_right;
|
||||
+ }
|
||||
+ test_data[] =
|
||||
+ {
|
||||
+ /* fogstart = 0, fogend = 1:
|
||||
+ * Using z-based fog, the bottom quad should have a gradient UNFOGGED->FOGGED
|
||||
+ * for table fog, and be completely fogged for vertex fog.
|
||||
+ * When the fog coordinate returned by the vertex shader is used instead,
|
||||
+ * the result is a gradient FOGGED->UNFOGGED.
|
||||
+ *
|
||||
+ * fogstart = -1, fogend = 0:
|
||||
+ * Both quads are completely fogged, except in the cases where the foggy vertex shader
|
||||
+ * with vertex fog or neither vertex nor table fog are used. Those are independent of
|
||||
+ * fogstart/fogend, the result should therefore equal that of the
|
||||
+ * corresponding (fogstart, fogend) == (0, 1) case. */
|
||||
+
|
||||
+ /* No vertex shader */
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_UNFOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ /* Vertex shader without vertex fog computation */
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ /* Vertex shader with vertex fog computation.
|
||||
+ * As drivers inconsistently clamp or don't clamp the oFog output of vertex shaders,
|
||||
+ * the special value C_CLAMPED_FOG allows both C_HALF_FOGGED (clamped) and C_FOGGED. */
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ };
|
||||
+ /* Affine projection matrix for z-near = -1, z-far = 1.
|
||||
+ * Note that for the tests with vertex shaders, this matrix is hard-coded in the shaders. */
|
||||
+ static const D3DMATRIX proj_mat =
|
||||
+ {{{
|
||||
+ 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
+ 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
+ 0.0f, 0.0f, 0.5f, 0.0f,
|
||||
+ 0.0f, 0.0f, 0.5f, 1.0f
|
||||
+ }}};
|
||||
+
|
||||
+ window = CreateWindowA("static", "d3d8_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
+ 0, 0, 640, 480, NULL, NULL, NULL, NULL);
|
||||
+ d3d = Direct3DCreate8(D3D_SDK_VERSION);
|
||||
+ ok(!!d3d, "Failed to create a D3D object\n");
|
||||
+ if (!(device = create_device(d3d, window, window, TRUE)))
|
||||
+ {
|
||||
+ skip("Failed to create a D3D device, skipping tests\n");
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ hr = IDirect3DDevice8_GetDeviceCaps(device, &caps);
|
||||
+ ok(SUCCEEDED(hr), "Failed to get device caps (%#x)\n", hr);
|
||||
+
|
||||
+ has_table_fog_support = caps.RasterCaps & D3DPRASTERCAPS_FOGTABLE;
|
||||
+ if (!has_table_fog_support)
|
||||
+ skip("No table fog support, skipping some fog tests\n");
|
||||
+
|
||||
+ has_ps_support = caps.PixelShaderVersion >= D3DPS_VERSION(1, 1);
|
||||
+ if (has_ps_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice8_CreatePixelShader(device, pixel_shader_code, &pixel_shader[1]);
|
||||
+ ok(SUCCEEDED(hr), "CreatePixelShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ skip("No ps_1_1 support, skipping some fog tests\n");
|
||||
+ }
|
||||
+
|
||||
+ has_vs_support = caps.VertexShaderVersion >= D3DVS_VERSION(1, 0);
|
||||
+ if (has_vs_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice8_CreateVertexShader(device, vertex_decl, vertex_shader_code1, &vertex_shader[1], 0);
|
||||
+ ok(SUCCEEDED(hr), "CreateVertexShader failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_CreateVertexShader(device, vertex_decl, vertex_shader_code2, &vertex_shader[2], 0);
|
||||
+ ok(SUCCEEDED(hr), "CreateVertexShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ skip("No vs_1_0 support, skipping some fog tests\n");
|
||||
+ }
|
||||
+
|
||||
+ /* Setup initial states: No depth test, no lighting, fog on, fog color */
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
|
||||
+ ok(SUCCEEDED(hr), "Turning off depth test failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_LIGHTING, FALSE);
|
||||
+ ok(SUCCEEDED(hr), "Turning off lighting failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGENABLE, TRUE);
|
||||
+ ok(SUCCEEDED(hr), "Turning on fog calculations failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGCOLOR, C_FOGGED);
|
||||
+ ok(SUCCEEDED(hr), "Setting fog color failed (%#x)\n", hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice8_SetTransform(device, D3DTS_PROJECTION, &proj_mat);
|
||||
+ ok(SUCCEEDED(hr), "Failed to set projection transform (%#x)\n", hr);
|
||||
+
|
||||
+ for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); i++)
|
||||
+ {
|
||||
+ if (test_data[i].vshader != 0 && !vertex_shader[test_data[i].vshader])
|
||||
+ continue;
|
||||
+ if (test_data[i].tfog != D3DFOG_NONE && !has_table_fog_support)
|
||||
+ continue;
|
||||
+
|
||||
+ hr = IDirect3DDevice8_SetVertexShader(device, vertex_shader[test_data[i].vshader]);
|
||||
+ ok(SUCCEEDED(hr), "SetVertexShader failed (%#x)\n", hr);
|
||||
+
|
||||
+ for (ps = 0; ps < sizeof(pixel_shader)/sizeof(pixel_shader[0]); ps++)
|
||||
+ {
|
||||
+ if (ps != 0 && !pixel_shader[ps])
|
||||
+ continue;
|
||||
+
|
||||
+ if (has_ps_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice8_SetPixelShader(device, pixel_shader[ps]);
|
||||
+ ok(SUCCEEDED(hr), "SetPixelShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGVERTEXMODE, test_data[i].vfog);
|
||||
+ ok(SUCCEEDED(hr), "Setting fog vertex mode to %d failed (%#x)\n", test_data[i].vfog, hr);
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGTABLEMODE, test_data[i].tfog);
|
||||
+ ok(SUCCEEDED(hr), "Setting fog table mode to %d failed (%#x)\n", test_data[i].tfog, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGSTART,
|
||||
+ *(DWORD*)(&test_data[i].fog_start));
|
||||
+ ok(SUCCEEDED(hr), "Setting fog start to %.1f failed (%#x)\n", test_data[i].fog_start, hr);
|
||||
+ hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGEND,
|
||||
+ *(DWORD*)(&test_data[i].fog_end));
|
||||
+ ok(SUCCEEDED(hr), "Setting fog end to %.1f failed (%#x)\n", test_data[i].fog_end, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET, C_CLEAR, 1.0f, 0);
|
||||
+ ok(SUCCEEDED(hr), "Clear failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_BeginScene(device);
|
||||
+ ok(SUCCEEDED(hr), "BeginScene failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_DrawPrimitiveUP(
|
||||
+ device, D3DPT_TRIANGLESTRIP, 2, &top_quad[0], sizeof(top_quad[0]));
|
||||
+ ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_DrawPrimitiveUP(
|
||||
+ device, D3DPT_TRIANGLESTRIP, 2, &bottom_quad_1[0], sizeof(bottom_quad_1[0]));
|
||||
+ ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_DrawPrimitiveUP(
|
||||
+ device, D3DPT_TRIANGLESTRIP, 2, &bottom_quad_2[0], sizeof(bottom_quad_2[0]));
|
||||
+ ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice8_EndScene(device);
|
||||
+ ok(SUCCEEDED(hr), "EndScene failed (%#x)\n", hr);
|
||||
+
|
||||
+ /* Use 5% tolerance on the colors since there may be a gradient
|
||||
+ * between left and right vertices. */
|
||||
+ for (y = 120; y <= 360; y += 240)
|
||||
+ {
|
||||
+ color = getPixelColor(device, 2, y);
|
||||
+ ok(color_match(color, test_data[i].color_left, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got left color %08x, expected %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, test_data[i].color_left);
|
||||
+ color = getPixelColor(device, 320, y);
|
||||
+ expected_middle_color =
|
||||
+ y == 120 ? test_data[i].color_middle_top : test_data[i].color_middle_bottom;
|
||||
+ if (expected_middle_color == C_CLAMPED_FOG)
|
||||
+ {
|
||||
+ ok(color_match(color, C_HALF_FOGGED, 13) || color_match(color, C_FOGGED, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got middle color %08x, expected %08x+-5%% or %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, C_HALF_FOGGED, C_FOGGED);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ok(color_match(color, expected_middle_color, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got middle color %08x, expected %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, expected_middle_color);
|
||||
+ }
|
||||
+ color = getPixelColor(device, 638, y);
|
||||
+ ok(color_match(color, test_data[i].color_right, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got right color %08x, expected %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, test_data[i].color_right);
|
||||
+ }
|
||||
+
|
||||
+ hr = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
|
||||
+ ok(SUCCEEDED(hr), "Present failed (%#x)\n", hr);
|
||||
+ }
|
||||
+ }
|
||||
+ for (i = 0; i < sizeof(vertex_shader)/sizeof(vertex_shader[0]); i++)
|
||||
+ if (vertex_shader[i])
|
||||
+ IDirect3DDevice8_DeleteVertexShader(device, vertex_shader[i]);
|
||||
+ for (i = 0; i < sizeof(pixel_shader)/sizeof(pixel_shader[0]); i++)
|
||||
+ if (pixel_shader[i])
|
||||
+ IDirect3DDevice8_DeletePixelShader(device, pixel_shader[i]);
|
||||
+ refcount = IDirect3DDevice8_Release(device);
|
||||
+ ok(!refcount, "Device has %u references left\n", refcount);
|
||||
+done:
|
||||
+ IDirect3D8_Release(d3d);
|
||||
+ DestroyWindow(window);
|
||||
+}
|
||||
+
|
||||
/* This tests fog in combination with shaders.
|
||||
* What's tested: linear fog (vertex and table) with pixel shader
|
||||
* linear table fog with non foggy vertex shader
|
||||
@@ -5395,6 +5725,7 @@ START_TEST(visual)
|
||||
offscreen_test();
|
||||
test_blend();
|
||||
test_scalar_instructions();
|
||||
+ fog_negative_z_test();
|
||||
fog_with_shader_test();
|
||||
cnd_test();
|
||||
p8_texture_test();
|
||||
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
|
||||
index fbab386..978e99d 100644
|
||||
--- a/dlls/d3d9/tests/visual.c
|
||||
+++ b/dlls/d3d9/tests/visual.c
|
||||
@@ -1825,6 +1825,404 @@ done:
|
||||
DestroyWindow(window);
|
||||
}
|
||||
|
||||
+/* This test tests fog in combination with negative vertex z coordinates. */
|
||||
+static void fog_negative_z_test(void)
|
||||
+{
|
||||
+ enum
|
||||
+ {
|
||||
+ C_ALPHA_0x00 = 0x00000000,
|
||||
+ C_CLEAR = 0xffff00ff,
|
||||
+ C_FOGGED = 0x0000ff00,
|
||||
+ C_HALF_FOGGED = 0x00808000,
|
||||
+ C_UNFOGGED = 0x00ff0000,
|
||||
+ C_CLAMPED_FOG = 0xdeadbeef /* triggers special codepath when used as middle_color */
|
||||
+ };
|
||||
+
|
||||
+ IDirect3DVertexShader9 *vertex_shader[4] = {NULL, NULL, NULL, NULL};
|
||||
+ IDirect3DPixelShader9 *pixel_shader[3] = {NULL, NULL, NULL};
|
||||
+ IDirect3DVertexDeclaration9 *vertex_declaration = NULL;
|
||||
+ IDirect3DDevice9 *device;
|
||||
+ BOOL has_vs_support, has_ps_support, has_table_fog_support, is_fog_vertex_clamped;
|
||||
+ unsigned int i, ps, y;
|
||||
+ IDirect3D9 *d3d;
|
||||
+ ULONG refcount;
|
||||
+ D3DCAPS9 caps;
|
||||
+ DWORD color, expected_middle_color;
|
||||
+ HWND window;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ /* Basic vertex shader without fog computation ("non foggy") */
|
||||
+ static const DWORD vertex_shader_code1[] =
|
||||
+ {
|
||||
+ 0xfffe0101, /* vs_1_1 */
|
||||
+ 0x00000051, 0xa00f0000, 0x3f000000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 0.5, 0, 0, 0 */
|
||||
+ 0x0000001f, 0x80000000, 0x900f0000, /* dcl_position0 v0 */
|
||||
+ 0x0000001f, 0x8000000a, 0x900f0001, /* dcl_color0 v1 */
|
||||
+ /* output.Pos.z = input.Pos.z * 0.5 + 0.5 */
|
||||
+ 0x00000005, 0x80010000, 0x90aa0000, 0xa0000000, /* mul r0.x, v0.z, c0.x */
|
||||
+ 0x00000002, 0xc0040000, 0x80000000, 0xa0000000, /* add oPos.z, r0.x c0.x */
|
||||
+ /* output.Pos.xyw = input.Pos.xyw */
|
||||
+ 0x00000001, 0xc00b0000, 0x90e40000, /* mov oPos.xyw, v0 */
|
||||
+ /* output.Color = input.Color */
|
||||
+ 0x00000001, 0xd00f0000, 0x90e40001, /* mov oD0, v1 */
|
||||
+ 0x0000ffff, /* END */
|
||||
+ };
|
||||
+
|
||||
+ /* Basic vertex shader with fog computation ("foggy"). Outputs the z coordinate of the vertex
|
||||
+ * as its fog intensity value. */
|
||||
+ static const DWORD vertex_shader_code2[] =
|
||||
+ {
|
||||
+ 0xfffe0101, /* vs_1_1 */
|
||||
+ 0x00000051, 0xa00f0000, 0x3f000000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 0.5, 0, 0, 0 */
|
||||
+ 0x0000001f, 0x80000000, 0x900f0000, /* dcl_position0 v0 */
|
||||
+ 0x0000001f, 0x8000000a, 0x900f0001, /* dcl_color0 v1 */
|
||||
+ /* output.Pos.z = input.Pos.z * 0.5 + 0.5 */
|
||||
+ 0x00000005, 0x80010000, 0x90aa0000, 0xa0000000, /* mul r0.x, v0.z, c0.x */
|
||||
+ 0x00000002, 0xc0040000, 0x80000000, 0xa0000000, /* add oPos.z, r0.x c0.x */
|
||||
+ /* output.Pos.xyw = input.Pos.xyw */
|
||||
+ 0x00000001, 0xc00b0000, 0x90e40000, /* mov oPos.xyw, v0 */
|
||||
+ /* output.Color = input.Color */
|
||||
+ 0x00000001, 0xd00f0000, 0x90e40001, /* mov oD0, v1 */
|
||||
+ /* output.Fog = input.Pos.z */
|
||||
+ 0x00000001, 0xc00f0001, 0x90aa0000, /* mov oFog, v0.z */
|
||||
+ 0x0000ffff, /* END */
|
||||
+ };
|
||||
+
|
||||
+ /* Basic vertex shader with fog computation ("foggy"), vs_2_0 */
|
||||
+ static const DWORD vertex_shader_code3[] =
|
||||
+ {
|
||||
+ 0xfffe0200, /* vs_2_0 */
|
||||
+ 0x05000051, 0xa00f0000, 0x3f000000, 0x00000000, 0x00000000, 0x00000000, /* def c0, 0.5, 0, 0, 0 */
|
||||
+ 0x0200001f, 0x80000000, 0x900f0000, /* dcl_position0 v0 */
|
||||
+ 0x0200001f, 0x8000000a, 0x900f0001, /* dcl_color0 v1 */
|
||||
+ /* output.Pos.z = input.Pos.z * 0.5 + 0.5 */
|
||||
+ 0x03000005, 0x80010000, 0x90aa0000, 0xa0000000, /* mul r0.x, v0.z, c0.x */
|
||||
+ 0x03000002, 0xc0040000, 0x80000000, 0xa0000000, /* add oPos.z, r0.x c0.x */
|
||||
+ /* output.Pos.xyw = input.Pos.xyw */
|
||||
+ 0x02000001, 0xc00b0000, 0x90e40000, /* mov oPos.xyw, v0 */
|
||||
+ /* output.Color = input.Color */
|
||||
+ 0x02000001, 0xd00f0000, 0x90e40001, /* mov oD0, v1 */
|
||||
+ /* output.Fog = input.Pos.z */
|
||||
+ 0x02000001, 0xc00f0001, 0x90aa0000, /* mov oFog, v0.z */
|
||||
+ 0x0000ffff, /* END */
|
||||
+ };
|
||||
+
|
||||
+ /* Basic pixel shader */
|
||||
+ static const DWORD pixel_shader_code[] =
|
||||
+ {
|
||||
+ 0xffff0101, /* ps_1_1 */
|
||||
+ 0x00000001, 0x800f0000, 0x90e40000, /* mov r0, v0 */
|
||||
+ 0x0000ffff
|
||||
+ };
|
||||
+ static const DWORD pixel_shader_code2[] =
|
||||
+ {
|
||||
+ 0xffff0200, /* ps_2_0 */
|
||||
+ 0x0200001f, 0x80000000, 0x900f0000, /* dcl v0 */
|
||||
+ 0x02000001, 0x800f0800, 0x90e40000, /* mov oC0, v0 */
|
||||
+ 0x0000ffff
|
||||
+ };
|
||||
+ static const struct
|
||||
+ {
|
||||
+ struct vec3 position;
|
||||
+ D3DCOLOR diffuse;
|
||||
+ D3DCOLOR specular;
|
||||
+ }
|
||||
+ top_quad[] =
|
||||
+ {
|
||||
+ {{-1.0f, -1.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{-1.0f, 0.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, -1.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 0.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ },
|
||||
+ bottom_quad_1[] =
|
||||
+ {
|
||||
+ {{-1.0f, 0.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{-1.0f, 1.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 0.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 1.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ },
|
||||
+ bottom_quad_2[] =
|
||||
+ {
|
||||
+ {{ 0.0f, 0.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 1.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 0.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 1.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ };
|
||||
+
|
||||
+ static const D3DVERTEXELEMENT9 decl_elements[] =
|
||||
+ {
|
||||
+ {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
|
||||
+ {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, /* diffuse */
|
||||
+ {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, /* specular */
|
||||
+ D3DDECL_END()
|
||||
+ };
|
||||
+ static const struct
|
||||
+ {
|
||||
+ int vshader;
|
||||
+ float fog_start;
|
||||
+ float fog_end;
|
||||
+ D3DFOGMODE vfog;
|
||||
+ D3DFOGMODE tfog;
|
||||
+ DWORD color_left;
|
||||
+ DWORD color_middle_top;
|
||||
+ DWORD color_middle_bottom;
|
||||
+ DWORD color_right;
|
||||
+ }
|
||||
+ test_data[] =
|
||||
+ {
|
||||
+ /* fogstart = 0, fogend = 1:
|
||||
+ * Using z-based fog, the bottom quad should have a gradient UNFOGGED->FOGGED
|
||||
+ * for table fog, and be completely fogged for vertex fog.
|
||||
+ * When the fog coordinate returned by the vertex shader is used instead,
|
||||
+ * the result is a gradient FOGGED->UNFOGGED in the right half of the screen.
|
||||
+ *
|
||||
+ * fogstart = -1, fogend = 0:
|
||||
+ * Both quads are completely fogged, except in the cases where a foggy vertex shader
|
||||
+ * with vertex fog or neither vertex nor table fog are used. Those are independent of
|
||||
+ * fogstart/fogend, the result should therefore equal that of the
|
||||
+ * corresponding (fogstart, fogend) == (0, 1) case.
|
||||
+ *
|
||||
+ * C_CLAMPED_FOG will be replaced by the correct expected value based on
|
||||
+ * the value of D3DPMISCCAPS_FOGVERTEXCLAMPED. If the driver clamps the oFog
|
||||
+ * output of vertex shaders, it should be C_HALF_FOGGED, else C_FOGGED. */
|
||||
+
|
||||
+ /* No vertex shader */
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_UNFOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {0, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ /* Vertex shader without vertex fog computation */
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {1, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ /* Vertex shader vs_1_1 with vertex fog computation */
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ {2, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ {2, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+
|
||||
+ /* Vertex shader vs_2_0 with vertex fog computation */
|
||||
+ {3, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {3, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ {3, 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ {3, 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+
|
||||
+ {3, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {3, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {3, -1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ {3, -1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_CLAMPED_FOG, C_UNFOGGED},
|
||||
+ };
|
||||
+ /* Affine projection matrix for z-near = -1, z-far = 1.
|
||||
+ * Note that for the tests with vertex shaders, this matrix is hard-coded in the shaders. */
|
||||
+ static const D3DMATRIX proj_mat =
|
||||
+ {{{
|
||||
+ 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
+ 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
+ 0.0f, 0.0f, 0.5f, 0.0f,
|
||||
+ 0.0f, 0.0f, 0.5f, 1.0f,
|
||||
+ }}};
|
||||
+
|
||||
+ window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
+ 0, 0, 640, 480, NULL, NULL, NULL, NULL);
|
||||
+ d3d = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
+ ok(!!d3d, "Failed to create a D3D object\n");
|
||||
+ if (!(device = create_device(d3d, window, window, TRUE)))
|
||||
+ {
|
||||
+ skip("Failed to create a D3D device, skipping tests\n");
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
|
||||
+ ok(SUCCEEDED(hr), "Failed to get device caps (%#x)\n", hr);
|
||||
+
|
||||
+ has_table_fog_support = caps.RasterCaps & D3DPRASTERCAPS_FOGTABLE;
|
||||
+ if (!has_table_fog_support)
|
||||
+ skip("No table fog support, skipping some fog tests\n");
|
||||
+
|
||||
+ has_vs_support = caps.VertexShaderVersion >= D3DVS_VERSION(1, 1);
|
||||
+ if (has_vs_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice9_CreateVertexShader(device, vertex_shader_code1, &vertex_shader[1]);
|
||||
+ ok(SUCCEEDED(hr), "CreateVertexShader failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_CreateVertexShader(device, vertex_shader_code2, &vertex_shader[2]);
|
||||
+ ok(SUCCEEDED(hr), "CreateVertexShader failed (%#x)\n", hr);
|
||||
+
|
||||
+ if (caps.VertexShaderVersion >= D3DVS_VERSION(2, 0))
|
||||
+ {
|
||||
+ hr = IDirect3DDevice9_CreateVertexShader(device, vertex_shader_code3, &vertex_shader[3]);
|
||||
+ ok(SUCCEEDED(hr), "CreateVertexShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ skip("No vs_2_0 support, skipping some fog tests\n");
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ skip("No vs_1_1 support, skipping some fog tests\n");
|
||||
+ }
|
||||
+
|
||||
+ has_ps_support = caps.PixelShaderVersion >= D3DPS_VERSION(1, 1);
|
||||
+ if (has_ps_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice9_CreatePixelShader(device, pixel_shader_code, &pixel_shader[1]);
|
||||
+ ok(SUCCEEDED(hr), "CreatePixelShader failed (%#x)\n", hr);
|
||||
+
|
||||
+ if (caps.PixelShaderVersion >= D3DPS_VERSION(2, 0))
|
||||
+ {
|
||||
+ hr = IDirect3DDevice9_CreatePixelShader(device, pixel_shader_code2, &pixel_shader[2]);
|
||||
+ ok(SUCCEEDED(hr), "CreatePixelShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ skip("No ps_2_0 support, skipping some fog tests\n");
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ skip("No ps_1_1 support, skipping some fog tests\n");
|
||||
+ }
|
||||
+
|
||||
+ is_fog_vertex_clamped = caps.PrimitiveMiscCaps & D3DPMISCCAPS_FOGVERTEXCLAMPED;
|
||||
+
|
||||
+ hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements, &vertex_declaration);
|
||||
+ ok(SUCCEEDED(hr), "CreateVertexDeclaration failed (%#x)\n", hr);
|
||||
+
|
||||
+ /* Setup initial states: No depth test, no lighting, fog on, fog color */
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
|
||||
+ ok(SUCCEEDED(hr), "Turning off depth test failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
|
||||
+ ok(SUCCEEDED(hr), "Turning off lighting failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGENABLE, TRUE);
|
||||
+ ok(SUCCEEDED(hr), "Turning on fog calculations failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGCOLOR, C_FOGGED);
|
||||
+ ok(SUCCEEDED(hr), "Setting fog color failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_SetVertexDeclaration(device, vertex_declaration);
|
||||
+ ok(SUCCEEDED(hr), "SetVertexDeclaration failed (%#x)\n", hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice9_SetTransform(device, D3DTS_PROJECTION, &proj_mat);
|
||||
+ ok(SUCCEEDED(hr), "Failed to set projection transform (%#x)\n", hr);
|
||||
+
|
||||
+ for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); i++)
|
||||
+ {
|
||||
+ if (test_data[i].vshader != 0 && !vertex_shader[test_data[i].vshader])
|
||||
+ continue;
|
||||
+ if (test_data[i].tfog != D3DFOG_NONE && !has_table_fog_support)
|
||||
+ continue;
|
||||
+
|
||||
+ if (has_vs_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice9_SetVertexShader(device, vertex_shader[test_data[i].vshader]);
|
||||
+ ok(SUCCEEDED(hr), "SetVertexShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+
|
||||
+ for (ps = 0; ps < sizeof(pixel_shader)/sizeof(pixel_shader[0]); ps++)
|
||||
+ {
|
||||
+ if (ps != 0 && !pixel_shader[ps])
|
||||
+ continue;
|
||||
+
|
||||
+ if (has_ps_support)
|
||||
+ {
|
||||
+ hr = IDirect3DDevice9_SetPixelShader(device, pixel_shader[ps]);
|
||||
+ ok(SUCCEEDED(hr), "SetPixelShader failed (%#x)\n", hr);
|
||||
+ }
|
||||
+
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGVERTEXMODE, test_data[i].vfog);
|
||||
+ ok(SUCCEEDED(hr), "Setting fog vertex mode to %d failed (%#x)\n", test_data[i].vfog, hr);
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGTABLEMODE, test_data[i].tfog);
|
||||
+ ok(SUCCEEDED(hr), "Setting fog table mode to %d failed (%#x)\n", test_data[i].tfog, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGSTART,
|
||||
+ *(DWORD*)(&test_data[i].fog_start));
|
||||
+ ok(SUCCEEDED(hr), "Setting fog start to %.1f failed (%#x)\n", test_data[i].fog_start, hr);
|
||||
+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGEND,
|
||||
+ *(DWORD*)(&test_data[i].fog_end));
|
||||
+ ok(SUCCEEDED(hr), "Setting fog end to %.1f failed (%#x)\n", test_data[i].fog_end, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, C_CLEAR, 1.0f, 0);
|
||||
+ ok(SUCCEEDED(hr), "Clear failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_BeginScene(device);
|
||||
+ ok(SUCCEEDED(hr), "BeginScene failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_DrawPrimitiveUP(
|
||||
+ device, D3DPT_TRIANGLESTRIP, 2, &top_quad[0], sizeof(top_quad[0]));
|
||||
+ ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_DrawPrimitiveUP(
|
||||
+ device, D3DPT_TRIANGLESTRIP, 2, &bottom_quad_1[0], sizeof(bottom_quad_1[0]));
|
||||
+ ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_DrawPrimitiveUP(
|
||||
+ device, D3DPT_TRIANGLESTRIP, 2, &bottom_quad_2[0], sizeof(bottom_quad_2[0]));
|
||||
+ ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%#x)\n", hr);
|
||||
+ hr = IDirect3DDevice9_EndScene(device);
|
||||
+ ok(SUCCEEDED(hr), "EndScene failed (%#x)\n", hr);
|
||||
+
|
||||
+ /* Use 5% tolerance on the colors since there may be a gradient
|
||||
+ * between left and right vertices. */
|
||||
+ for (y = 120; y <= 360; y += 240)
|
||||
+ {
|
||||
+ color = getPixelColor(device, 2, y);
|
||||
+ ok(color_match(color, test_data[i].color_left, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got left color %08x, expected %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, test_data[i].color_left);
|
||||
+ color = getPixelColor(device, 320, y);
|
||||
+ expected_middle_color =
|
||||
+ y == 120 ? test_data[i].color_middle_top : test_data[i].color_middle_bottom;
|
||||
+ if (expected_middle_color == C_CLAMPED_FOG)
|
||||
+ {
|
||||
+ expected_middle_color = is_fog_vertex_clamped ? C_HALF_FOGGED : C_FOGGED;
|
||||
+ }
|
||||
+ ok(color_match(color, expected_middle_color, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got middle color %08x, expected %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, expected_middle_color);
|
||||
+ color = getPixelColor(device, 638, y);
|
||||
+ ok(color_match(color, test_data[i].color_right, 13),
|
||||
+ "fog %.1f-%.1f vs%i ps%i fvm%i ftm%i, y=%i: "
|
||||
+ "got right color %08x, expected %08x+-5%%\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vshader, ps,
|
||||
+ test_data[i].vfog, test_data[i].tfog, y, color, test_data[i].color_right);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
|
||||
+ ok(SUCCEEDED(hr), "Present failed (%#x)\n", hr);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < sizeof(vertex_shader)/sizeof(vertex_shader[0]); i++)
|
||||
+ if (vertex_shader[i])
|
||||
+ IDirect3DVertexShader9_Release(vertex_shader[i]);
|
||||
+ for (i = 0; i < sizeof(pixel_shader)/sizeof(pixel_shader[0]); i++)
|
||||
+ if (pixel_shader[i])
|
||||
+ IDirect3DPixelShader9_Release(pixel_shader[i]);
|
||||
+ IDirect3DVertexDeclaration9_Release(vertex_declaration);
|
||||
+ refcount = IDirect3DDevice9_Release(device);
|
||||
+ ok(!refcount, "Device has %u references left\n", refcount);
|
||||
+done:
|
||||
+ IDirect3D9_Release(d3d);
|
||||
+ DestroyWindow(window);
|
||||
+}
|
||||
+
|
||||
/* This test tests fog in combination with shaders.
|
||||
* What's tested: linear fog (vertex and table) with pixel shader
|
||||
* linear table fog with non foggy vertex shader
|
||||
@@ -17033,6 +17431,7 @@ START_TEST(visual)
|
||||
test_vshader_input();
|
||||
test_vshader_float16();
|
||||
stream_test();
|
||||
+ fog_negative_z_test();
|
||||
fog_with_shader_test();
|
||||
texbem_test();
|
||||
texdepth_test();
|
||||
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
|
||||
index 9263e1e..1d6585c 100644
|
||||
--- a/dlls/ddraw/tests/ddraw7.c
|
||||
+++ b/dlls/ddraw/tests/ddraw7.c
|
||||
@@ -3636,6 +3636,179 @@ static void test_fog_special(void)
|
||||
DestroyWindow(window);
|
||||
}
|
||||
|
||||
+/* This test tests fog in combination with negative vertex z coordinates. */
|
||||
+static void test_fog_negative_z(void)
|
||||
+{
|
||||
+ enum
|
||||
+ {
|
||||
+ C_ALPHA_0x00 = 0x00000000,
|
||||
+ C_CLEAR = 0xffff00ff,
|
||||
+ C_FOGGED = 0x0000ff00,
|
||||
+ C_HALF_FOGGED = 0x00808000,
|
||||
+ C_UNFOGGED = 0x00ff0000
|
||||
+ };
|
||||
+
|
||||
+ D3DCOLOR color, expected_middle_color;
|
||||
+ HRESULT hr;
|
||||
+ ULONG refcount;
|
||||
+ BOOL has_table_fog_support;
|
||||
+ unsigned int i, y;
|
||||
+ HWND window;
|
||||
+ IDirect3DDevice7 *device;
|
||||
+ IDirectDrawSurface7 *rt;
|
||||
+ D3DDEVICEDESC7 caps;
|
||||
+
|
||||
+ static struct
|
||||
+ {
|
||||
+ struct vec3 position;
|
||||
+ D3DCOLOR diffuse;
|
||||
+ D3DCOLOR specular;
|
||||
+ }
|
||||
+ top_quad[] =
|
||||
+ {
|
||||
+ {{-1.0f, 0.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 0.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{-1.0f, -1.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, -1.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ },
|
||||
+ bottom_quad_1[] =
|
||||
+ {
|
||||
+ {{-1.0f, 1.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 1.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{-1.0f, 0.0f, -1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 0.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ },
|
||||
+ bottom_quad_2[] =
|
||||
+ {
|
||||
+ {{ 0.0f, 1.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 1.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 0.0f, 0.0f, 0.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ {{ 1.0f, 0.0f, 1.0f}, C_UNFOGGED, C_ALPHA_0x00},
|
||||
+ };
|
||||
+ static const struct
|
||||
+ {
|
||||
+ float fog_start, fog_end;
|
||||
+ DWORD vertexmode, tablemode;
|
||||
+ D3DCOLOR color_left, color_middle_top, color_middle_bottom, color_right;
|
||||
+ }
|
||||
+ test_data[] =
|
||||
+ {
|
||||
+ { 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ { 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_UNFOGGED, C_HALF_FOGGED, C_HALF_FOGGED, C_FOGGED},
|
||||
+ { 0.0f, 1.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_UNFOGGED, C_FOGGED, C_FOGGED},
|
||||
+ { 0.0f, 1.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+
|
||||
+ {-1.0f, 0.0f, D3DFOG_NONE, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {-1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_LINEAR, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {-1.0f, 0.0f, D3DFOG_LINEAR, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ {-1.0f, 0.0f, D3DFOG_NONE, D3DFOG_NONE, C_FOGGED, C_FOGGED, C_FOGGED, C_FOGGED},
|
||||
+ };
|
||||
+ /* Affine projection matrix for z-near = -1, z-far = 1. */
|
||||
+ static D3DMATRIX proj_mat =
|
||||
+ {
|
||||
+ 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
+ 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
+ 0.0f, 0.0f, 0.5f, 0.0f,
|
||||
+ 0.0f, 0.0f, 0.5f, 1.0f
|
||||
+ };
|
||||
+
|
||||
+ window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
|
||||
+ 0, 0, 640, 480, 0, 0, 0, 0);
|
||||
+
|
||||
+ if (!(device = create_device(window, DDSCL_NORMAL)))
|
||||
+ {
|
||||
+ skip("Failed to create a 3D device, skipping test.\n");
|
||||
+ DestroyWindow(window);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ memset(&caps, 0, sizeof(caps));
|
||||
+ hr = IDirect3DDevice7_GetCaps(device, &caps);
|
||||
+ ok(SUCCEEDED(hr), "IDirect3DDevice7_GetCaps failed, hr %#x.\n", hr);
|
||||
+
|
||||
+ has_table_fog_support = caps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGTABLE;
|
||||
+ if (!has_table_fog_support)
|
||||
+ skip("No table fog support, skipping some fog tests.\n");
|
||||
+
|
||||
+ hr = IDirect3DDevice7_GetRenderTarget(device, &rt);
|
||||
+ ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, TRUE);
|
||||
+ ok(SUCCEEDED(hr), "Failed to enable fog, hr %#x.\n", hr);
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_FOGCOLOR, C_FOGGED);
|
||||
+ ok(SUCCEEDED(hr), "Failed to set fog color, hr %#x.\n", hr);
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
|
||||
+ ok(SUCCEEDED(hr), "Failed to disable lighting, hr %#x.\n", hr);
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
|
||||
+ ok(SUCCEEDED(hr), "Failed to disable depth test, hr %#x.\n", hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &proj_mat);
|
||||
+ ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
|
||||
+
|
||||
+ for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); i++)
|
||||
+ {
|
||||
+ if (test_data[i].tablemode != D3DFOG_NONE && !has_table_fog_support)
|
||||
+ continue;
|
||||
+
|
||||
+ hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, C_CLEAR, 1.0f, 0);
|
||||
+ ok(SUCCEEDED(hr), "Failed to clear render target, i=%d, hr %#x.\n", i, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_FOGVERTEXMODE, test_data[i].vertexmode);
|
||||
+ ok(SUCCEEDED(hr), "Failed to set fog vertex mode, i=%d, hr %#x.\n", i, hr);
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_FOGTABLEMODE, test_data[i].tablemode);
|
||||
+ ok(SUCCEEDED(hr), "Failed to set fog table mode, i=%d, hr %#x.\n", i, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_FOGSTART,
|
||||
+ *(DWORD*)(&test_data[i].fog_start));
|
||||
+ ok(SUCCEEDED(hr), "Failed to set fog start, i=%d, hr %#x.\n", i, hr);
|
||||
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_FOGEND,
|
||||
+ *(DWORD*)(&test_data[i].fog_end));
|
||||
+ ok(SUCCEEDED(hr), "Failed to set fog end, i=%d, hr %#x.\n", i, hr);
|
||||
+
|
||||
+ hr = IDirect3DDevice7_BeginScene(device);
|
||||
+ ok(SUCCEEDED(hr), "Failed to begin scene, i=%d, hr %#x.\n", i, hr);
|
||||
+ hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
|
||||
+ D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR, top_quad, 4, 0);
|
||||
+ ok(SUCCEEDED(hr), "Failed to draw, i=%d, hr %#x.\n", i, hr);
|
||||
+ hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
|
||||
+ D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR, bottom_quad_1, 4, 0);
|
||||
+ ok(SUCCEEDED(hr), "Failed to draw, i=%d, hr %#x.\n", i, hr);
|
||||
+ hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
|
||||
+ D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR, bottom_quad_2, 4, 0);
|
||||
+ ok(SUCCEEDED(hr), "Failed to draw, i=%d, hr %#x.\n", i, hr);
|
||||
+ hr = IDirect3DDevice7_EndScene(device);
|
||||
+ ok(SUCCEEDED(hr), "Failed to end scene, i=%d, hr %#x.\n", i, hr);
|
||||
+
|
||||
+ /* Use 5% tolerance on the colors since there may be a gradient
|
||||
+ * between left and right vertices. */
|
||||
+ for (y = 120; y <= 360; y += 240)
|
||||
+ {
|
||||
+ color = get_surface_color(rt, 2, y);
|
||||
+ ok(compare_color(color, test_data[i].color_left, 13),
|
||||
+ "fog %.1f-%.1f fvm%i ftm%i y=%i: got left color %08x, expected %08x+-5%%.\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vertexmode,
|
||||
+ test_data[i].tablemode, y, color, test_data[i].color_left);
|
||||
+ color = get_surface_color(rt, 320, y);
|
||||
+ expected_middle_color =
|
||||
+ y == 120 ? test_data[i].color_middle_top : test_data[i].color_middle_bottom;
|
||||
+ ok(compare_color(color, expected_middle_color, 13),
|
||||
+ "fog %.1f-%.1f fvm%i ftm%i y=%i: got middle color %08x, expected %08x+-5%%.\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vertexmode,
|
||||
+ test_data[i].tablemode, y, color, expected_middle_color);
|
||||
+ color = get_surface_color(rt, 638, y);
|
||||
+ ok(compare_color(color, test_data[i].color_right, 13),
|
||||
+ "fog %.1f-%.1f fvm%i ftm%i y=%i: got right color %08x, expected %08x+-5%%.\n",
|
||||
+ test_data[i].fog_start, test_data[i].fog_end, test_data[i].vertexmode,
|
||||
+ test_data[i].tablemode, y, color, test_data[i].color_right);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ IDirectDrawSurface7_Release(rt);
|
||||
+ refcount = IDirect3DDevice7_Release(device);
|
||||
+ ok(!refcount, "Device has %u references left.\n", refcount);
|
||||
+ DestroyWindow(window);
|
||||
+}
|
||||
+
|
||||
static void test_lighting_interface_versions(void)
|
||||
{
|
||||
IDirect3DDevice7 *device;
|
||||
@@ -8060,6 +8233,7 @@ START_TEST(ddraw7)
|
||||
test_clear_rect_count();
|
||||
test_coop_level_versions();
|
||||
test_fog_special();
|
||||
+ test_fog_negative_z();
|
||||
test_lighting_interface_versions();
|
||||
test_coop_level_activateapp();
|
||||
test_texturemanage();
|
||||
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
|
||||
index 98239ef..fab7251 100644
|
||||
--- a/dlls/wined3d/glsl_shader.c
|
||||
+++ b/dlls/wined3d/glsl_shader.c
|
||||
@@ -5007,7 +5007,7 @@ static GLhandleARB shader_glsl_generate_ffp_vertex_shader(struct wined3d_shader_
|
||||
/* Need to undo the [0.0 - 1.0] -> [-1.0 - 1.0] transformation from D3D to GL coordinates. */
|
||||
shader_addline(buffer, "gl_FogFragCoord = gl_Position.z * 0.5 + 0.5;\n");
|
||||
else
|
||||
- shader_addline(buffer, "gl_FogFragCoord = ec_pos.z;\n");
|
||||
+ shader_addline(buffer, "gl_FogFragCoord = abs(ec_pos.z);\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
--
|
||||
2.1.3
|
||||
|
@ -1 +0,0 @@
|
||||
Fixes: Take abs() of vertex z coordinate as FFP fog coordinate
|
Loading…
Reference in New Issue
Block a user